Daikin climate receiver support (#1001)

* climate.daikin: implement remote receive

* climate.daikin: fix temperature value in special modes

* climate.daikin: tweak timing to fit better to ir-remote signal
This commit is contained in:
puuu 2020-04-17 06:57:58 +09:00 committed by GitHub
parent c1dfed5c08
commit 65f4d30fd0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 109 additions and 4 deletions

View file

@ -8,7 +8,7 @@ AUTO_LOAD = ['climate_ir']
daikin_ns = cg.esphome_ns.namespace('daikin') daikin_ns = cg.esphome_ns.namespace('daikin')
DaikinClimate = daikin_ns.class_('DaikinClimate', climate_ir.ClimateIR) 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), cv.GenerateID(): cv.declare_id(DaikinClimate),
}) })

View file

@ -115,7 +115,8 @@ uint8_t DaikinClimate::temperature_() {
// Force special temperatures depending on the mode // Force special temperatures depending on the mode
switch (this->mode) { switch (this->mode) {
case climate::CLIMATE_MODE_FAN_ONLY: case climate::CLIMATE_MODE_FAN_ONLY:
return 25; return 0x32;
case climate::CLIMATE_MODE_AUTO:
case climate::CLIMATE_MODE_DRY: case climate::CLIMATE_MODE_DRY:
return 0xc0; return 0xc0;
default: 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 daikin
} // namespace esphome } // namespace esphome

View file

@ -31,11 +31,14 @@ const uint8_t DAIKIN_FAN_5 = 0x70;
const uint32_t DAIKIN_IR_FREQUENCY = 38000; const uint32_t DAIKIN_IR_FREQUENCY = 38000;
const uint32_t DAIKIN_HEADER_MARK = 3360; const uint32_t DAIKIN_HEADER_MARK = 3360;
const uint32_t DAIKIN_HEADER_SPACE = 1760; 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_ONE_SPACE = 1370;
const uint32_t DAIKIN_ZERO_SPACE = 520; const uint32_t DAIKIN_ZERO_SPACE = 360;
const uint32_t DAIKIN_MESSAGE_SPACE = 32300; const uint32_t DAIKIN_MESSAGE_SPACE = 32300;
// State Frame size
const uint8_t DAIKIN_STATE_FRAME_SIZE = 19;
class DaikinClimate : public climate_ir::ClimateIR { class DaikinClimate : public climate_ir::ClimateIR {
public: public:
DaikinClimate() DaikinClimate()
@ -51,6 +54,9 @@ class DaikinClimate : public climate_ir::ClimateIR {
uint8_t operation_mode_(); uint8_t operation_mode_();
uint8_t fan_speed_(); uint8_t fan_speed_();
uint8_t temperature_(); 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 } // namespace daikin