diff --git a/esphome/components/daikin/climate.py b/esphome/components/daikin/climate.py index f1d5c7ed4a..ff3f506fb2 100644 --- a/esphome/components/daikin/climate.py +++ b/esphome/components/daikin/climate.py @@ -8,7 +8,7 @@ AUTO_LOAD = ['climate_ir'] daikin_ns = cg.esphome_ns.namespace('daikin') DaikinClimate = daikin_ns.class_('DaikinClimate', climate_ir.ClimateIR) -CONFIG_SCHEMA = climate_ir.CLIMATE_IR_SCHEMA.extend({ +CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend({ cv.GenerateID(): cv.declare_id(DaikinClimate), }) diff --git a/esphome/components/daikin/daikin.cpp b/esphome/components/daikin/daikin.cpp index eabbb96014..b6e80d62a7 100644 --- a/esphome/components/daikin/daikin.cpp +++ b/esphome/components/daikin/daikin.cpp @@ -115,7 +115,8 @@ uint8_t DaikinClimate::temperature_() { // Force special temperatures depending on the mode switch (this->mode) { case climate::CLIMATE_MODE_FAN_ONLY: - return 25; + return 0x32; + case climate::CLIMATE_MODE_AUTO: case climate::CLIMATE_MODE_DRY: return 0xc0; default: @@ -124,5 +125,103 @@ uint8_t DaikinClimate::temperature_() { } } +bool DaikinClimate::parse_state_frame_(const uint8_t frame[]) { + uint8_t checksum = 0; + for (int i = 0; i < (DAIKIN_STATE_FRAME_SIZE - 1); i++) { + checksum += frame[i]; + } + if (frame[DAIKIN_STATE_FRAME_SIZE - 1] != checksum) + return false; + uint8_t mode = frame[5]; + if (mode & DAIKIN_MODE_ON) { + switch (mode & 0xF0) { + case DAIKIN_MODE_COOL: + this->mode = climate::CLIMATE_MODE_COOL; + break; + case DAIKIN_MODE_DRY: + this->mode = climate::CLIMATE_MODE_DRY; + break; + case DAIKIN_MODE_HEAT: + this->mode = climate::CLIMATE_MODE_HEAT; + break; + case DAIKIN_MODE_AUTO: + this->mode = climate::CLIMATE_MODE_AUTO; + break; + case DAIKIN_MODE_FAN: + this->mode = climate::CLIMATE_MODE_FAN_ONLY; + break; + } + } else { + this->mode = climate::CLIMATE_MODE_OFF; + } + uint8_t temperature = frame[6]; + if (!(temperature & 0xC0)) { + this->target_temperature = temperature >> 1; + } + uint8_t fan_mode = frame[8]; + if (fan_mode & 0xF) + this->swing_mode = climate::CLIMATE_SWING_VERTICAL; + else + this->swing_mode = climate::CLIMATE_SWING_OFF; + switch (fan_mode & 0xF0) { + case DAIKIN_FAN_1: + case DAIKIN_FAN_2: + this->fan_mode = climate::CLIMATE_FAN_LOW; + break; + case DAIKIN_FAN_3: + this->fan_mode = climate::CLIMATE_FAN_MEDIUM; + break; + case DAIKIN_FAN_4: + case DAIKIN_FAN_5: + this->fan_mode = climate::CLIMATE_FAN_HIGH; + break; + case DAIKIN_FAN_AUTO: + this->fan_mode = climate::CLIMATE_FAN_AUTO; + break; + } + this->publish_state(); + return true; +} + +bool DaikinClimate::on_receive(remote_base::RemoteReceiveData data) { + uint8_t state_frame[DAIKIN_STATE_FRAME_SIZE] = {}; + if (!data.expect_item(DAIKIN_HEADER_MARK, DAIKIN_HEADER_SPACE)) { + return false; + } + for (uint8_t pos = 0; pos < DAIKIN_STATE_FRAME_SIZE; pos++) { + uint8_t byte = 0; + for (int8_t bit = 0; bit < 8; bit++) { + if (data.expect_item(DAIKIN_BIT_MARK, DAIKIN_ONE_SPACE)) + byte |= 1 << bit; + else if (!data.expect_item(DAIKIN_BIT_MARK, DAIKIN_ZERO_SPACE)) { + return false; + } + } + state_frame[pos] = byte; + if (pos == 0) { + // frame header + if (byte != 0x11) + return false; + } else if (pos == 1) { + // frame header + if (byte != 0xDA) + return false; + } else if (pos == 2) { + // frame header + if (byte != 0x27) + return false; + } else if (pos == 3) { + // frame header + if (byte != 0x00) + return false; + } else if (pos == 4) { + // frame type + if (byte != 0x00) + return false; + } + } + return this->parse_state_frame_(state_frame); +} + } // namespace daikin } // namespace esphome diff --git a/esphome/components/daikin/daikin.h b/esphome/components/daikin/daikin.h index ea69256701..4671d57570 100644 --- a/esphome/components/daikin/daikin.h +++ b/esphome/components/daikin/daikin.h @@ -31,11 +31,14 @@ const uint8_t DAIKIN_FAN_5 = 0x70; const uint32_t DAIKIN_IR_FREQUENCY = 38000; const uint32_t DAIKIN_HEADER_MARK = 3360; const uint32_t DAIKIN_HEADER_SPACE = 1760; -const uint32_t DAIKIN_BIT_MARK = 360; +const uint32_t DAIKIN_BIT_MARK = 520; const uint32_t DAIKIN_ONE_SPACE = 1370; -const uint32_t DAIKIN_ZERO_SPACE = 520; +const uint32_t DAIKIN_ZERO_SPACE = 360; const uint32_t DAIKIN_MESSAGE_SPACE = 32300; +// State Frame size +const uint8_t DAIKIN_STATE_FRAME_SIZE = 19; + class DaikinClimate : public climate_ir::ClimateIR { public: DaikinClimate() @@ -51,6 +54,9 @@ class DaikinClimate : public climate_ir::ClimateIR { uint8_t operation_mode_(); uint8_t fan_speed_(); uint8_t temperature_(); + // Handle received IR Buffer + bool on_receive(remote_base::RemoteReceiveData data) override; + bool parse_state_frame_(const uint8_t frame[]); }; } // namespace daikin