Natywne komponenty gree/coolix nie dzialaly - zla suma kontrolna. Protokol zreverse-engineerowany z 22 ramek IR nagranych z pilota: - bajt0 = tryb+power: cool 0x19, heat 0x4C, fan 0x1B, off 0x44 - bajt1 = temperatura jako (temp-16) - checksum = (lo(b0..b3)+hi(b4..b6)+0x0A)&0xF w gornym nibblu b7 - timingi: hdr 9030/-4460, mark 677, space0 553, space1 1630, gap 19960 Termostat Off/Cool/Heat/Fan, zakres 16-30C, HW: Wemos D1 Mini + Grove IR.
86 lines
3 KiB
C++
86 lines
3 KiB
C++
#pragma once
|
|
#include "esphome/core/component.h"
|
|
#include "esphome/components/climate/climate.h"
|
|
#include "esphome/components/remote_transmitter/remote_transmitter.h"
|
|
|
|
namespace esphome {
|
|
namespace gree_ir {
|
|
|
|
class GreeIR : public climate::Climate, public Component {
|
|
public:
|
|
void set_transmitter(remote_transmitter::RemoteTransmitterComponent *tx) {
|
|
this->transmitter_ = tx;
|
|
}
|
|
|
|
void setup() override {
|
|
this->mode = climate::CLIMATE_MODE_OFF;
|
|
this->target_temperature = 24;
|
|
this->publish_state();
|
|
}
|
|
|
|
climate::ClimateTraits traits() override {
|
|
auto traits = climate::ClimateTraits();
|
|
traits.set_supported_modes({
|
|
climate::CLIMATE_MODE_OFF,
|
|
climate::CLIMATE_MODE_COOL,
|
|
climate::CLIMATE_MODE_HEAT,
|
|
climate::CLIMATE_MODE_FAN_ONLY,
|
|
});
|
|
traits.set_visual_min_temperature(16);
|
|
traits.set_visual_max_temperature(30);
|
|
traits.set_visual_temperature_step(1);
|
|
return traits;
|
|
}
|
|
|
|
void control(const climate::ClimateCall &call) override {
|
|
if (call.get_mode().has_value())
|
|
this->mode = *call.get_mode();
|
|
if (call.get_target_temperature().has_value())
|
|
this->target_temperature = *call.get_target_temperature();
|
|
this->transmit_state_();
|
|
this->publish_state();
|
|
}
|
|
|
|
protected:
|
|
remote_transmitter::RemoteTransmitterComponent *transmitter_{nullptr};
|
|
|
|
void transmit_state_() {
|
|
uint8_t b[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
|
uint8_t mode_byte, b2, b1_0;
|
|
switch (this->mode) {
|
|
case climate::CLIMATE_MODE_COOL: mode_byte = 0x19; b2 = 0x60; b1_0 = 0x06; break;
|
|
case climate::CLIMATE_MODE_HEAT: mode_byte = 0x4C; b2 = 0x40; b1_0 = 0x01; break;
|
|
case climate::CLIMATE_MODE_FAN_ONLY: mode_byte = 0x1B; b2 = 0x60; b1_0 = 0x02; break;
|
|
default: mode_byte = 0x44; b2 = 0x00; b1_0 = 0x01; break;
|
|
}
|
|
int temp = (int) this->target_temperature;
|
|
if (temp < 16) temp = 16;
|
|
if (temp > 30) temp = 30;
|
|
uint8_t t = (this->mode == climate::CLIMATE_MODE_OFF) ? 0x0A : (uint8_t)(temp - 16);
|
|
|
|
b[0] = mode_byte; b[1] = t; b[2] = b2; b[3] = 0x50;
|
|
b[4] = b1_0; b[5] = 0x00; b[6] = 0x00;
|
|
uint8_t cs = ((b[0] & 0xF) + (b[1] & 0xF) + (b[2] & 0xF) + (b[3] & 0xF) +
|
|
((b[4] >> 4) & 0xF) + ((b[5] >> 4) & 0xF) + ((b[6] >> 4) & 0xF) + 0x0A) & 0xF;
|
|
b[7] = (cs << 4) & 0xF0;
|
|
|
|
auto transmit = this->transmitter_->transmit();
|
|
auto *data = transmit.get_data();
|
|
data->set_carrier_frequency(38000);
|
|
const int MK = 677, S0 = 553, S1 = 1630, GAP = 19960;
|
|
data->mark(9030); data->space(4460);
|
|
for (int by = 0; by < 4; by++)
|
|
for (int bit = 0; bit < 8; bit++) { data->mark(MK); data->space(((b[by] >> bit) & 1) ? S1 : S0); }
|
|
const int foot[3] = {0, 1, 0};
|
|
for (int i = 0; i < 3; i++) { data->mark(MK); data->space(foot[i] ? S1 : S0); }
|
|
data->mark(MK); data->space(GAP);
|
|
for (int by = 4; by < 8; by++)
|
|
for (int bit = 0; bit < 8; bit++) { data->mark(MK); data->space(((b[by] >> bit) & 1) ? S1 : S0); }
|
|
data->mark(MK);
|
|
transmit.perform();
|
|
}
|
|
};
|
|
|
|
} // namespace gree_ir
|
|
} // namespace
|