ESP Haier: Haier Air Conditioner + ESP Home + Wemos D1 mini

It does, this has been established, what I’m trying to find out is how this new module polls information from the AC and what it receives back. The bits are clearly very similar to the previous models

New ESP32 modules works with albetaCOM v2 version: GitHub - albetaCOM/esp-haier: ESP8266 code to connect to Haier Air Conditioner ((firmware version R_1.

But when using this version there is a problem with the purify option which turns on every time after changing the settings using the diy module. Maybe somoeone can help to identify problem in code of that fork. Purify problem with some details is also reported in github isuues. I can help with debugging, but my programming skills are not good enough to solve this issue

1 Like

I’ve completed a full dump of a few configuration command sent via the hON app and the ESP32 module. I made a list of all the commands I sent, but my logic analyzer got disconnected a few times so it’s not complete.
The good thing is that the debug port logs absolutely everything, the JSON it receives from the IoT site, the decoded commands, as well as all the bytes sent and received via MCU_TX (tx_serial e+++ data) and RX (rx_serial e++ data). Hopefuly someone will be able to debug it, I don’t have the time to do it in the next couple of weeks, I can maybe do more of these data dumps if needed.
This is just a snippet, full dump is here: ESP32-for-Haier debug dump - Pastebin.com

 I (514689) uplus_epp_usr_monitor: e_EPP_Protocol_Connection_State = 10, status = 5, free heap = 74048
 I (514739) cdm_rx_task: s sFunc errors errors 00
 I (515289) cdm_rx_task: s sFunc errors errors 00
 I (515739) uplus_epp_usr_monitor: e_EPP_Protocol_Connection_State = 10, status = 5, free heap = 71932
 I (515839) cdm_rx_task: s sFunc errors errors 00
 I (515879) cdm_command_task: parameters, size = 39
 I (515899) cdm_command_task: 1 e operationName = grSetDAC
 I (515909) cdm_command_task: 1 w onOffStatus = 1, onOffStatus = true, cTab 0 0, cFunc 1 ft01 1
 I (515939) cdm_command_task: 1 w screenDisplayStatus = 1, screenDisplayStatus = true, cTab 0 0, cFunc 1 ft01 1
 I (515949) cdm_command_task: 1 w echoStatus = 0, echoStatus = false, cTab 0 0, cFunc 1 ft01 1
 I (515989) cdm_command_task: 1 w tempSel = 22.00, targetTemperature = 22.00, cTab 0 0, cFunc 0  0
 I (515999) cdm_command_task: 1 w machMode = 4, operationMode = 4, cTab 0 0, cFunc 0  0
 I (516009) cdm_command_task: 1 w 10degreeHeatingStatus = 0, 10degreeHeatingStatus = false, cTab 0 0, cFunc 1 ft01 1
 I (516049) cdm_command_task: 1 w muteStatus = 0, muteStatus = false, cTab 0 0, cFunc 1 ft01 1
 I (516069) cdm_command_task: 1 w rapidMode = 0, rapidMode = false, cTab 0 0, cFunc 1 ft01 1
 I (516089) cdm_command_task: 1 w healthMode = 0, healthMode = false, cTab 0 0, cFunc 1 ft01 1
 I (516109) cdm_command_task: 1 w humanSensingStatus = 0, humanSensingStatus = 0, cTab 0 0, cFunc 0  0
 I (516139) cdm_command_task: 1 w selfCleaning56Status = 0, selfCleaning56Status = false, cTab 0 0, cFunc 1 ft01 1
 I (516159) cdm_command_task: 1 w selfCleaningStatus = 0, selfCleaningStatus = false, cTab 0 0, cFunc 1 ft01 1
 I (516169) cdm_command_task: 1 w cleaningTimeStatus = 0, cleaningTimeStatus = false, cTab 0 0, cFunc 1 ft01 1
 I (516199) cdm_command_task: 1 w filterChangeStatusCloud = 0, cloudFilterChangeFlag = false, cTab 0 0, cFunc 1 ft01 1
 I (516229) cdm_command_task: 1 w specialMode = 0, specialMode = 0, cTab 0 0, cFunc 0  0
 I (516239) cdm_command_task: 1 w energySavePeriod = 15, energySavePeriod = 15, cTab 0 0, cFunc 0  0
 I (516269) cdm_command_task: 1 w heatAccumulationStatus = 0, heatAccumulationStatus = false, cTab 0 0, cFunc 1 ft01 1
 I (516299) cdm_command_task: 1 w tempUnit = 0, tempUnit = 1, cTab 1 1, cFunc 0  0
 I (516319) cdm_command_task: 1 w pmvStatus = 0, pmvStatus = false, cTab 0 0, cFunc 1 ft01 1
 I (516339) cdm_command_task: 1 w intelligenceStatus = 0, intelligenceStatus = false, cTab 0 0, cFunc 1 ft01 1
 I (516389) cdm_rx_task: s sFunc errors errors 00
 I (516399) cdm_rx_task: + operationName =  -> grSetDAC, isSuperTriggerStatusChange 1
 I (516399) cdm_rx_task: isSuperTriggerStatusChange = 1, isStatusChange = 1, isTransmissionRateElapsed = 0, currentTimestamp = 1628677169, transmissionTimestamp = 1628677148, elapsed = 21, transMode = 0, transmissionRate = 3600
 I (516409) cdm_command_task: 1 w halfDegreeSettingStatus = 0, halfDegreeSettingStatus = false, cTab 0 0, cFunc 1 ft01 1
 I (516449) cdm_command_task: 1 w lockStatus = 0, lockStatus = false, cTab 0 0, cFunc 1 ft01 1
 I (516469) cdm_command_task: 1 w electricHeatingStatus = 0, electricHeatingStatus = false, cTab 0 0, cFunc 1 ft01 1
 I (516499) cdm_command_task: 1 w humiditySel = 30, targetHumidity = 30, cTab 0 0, cFunc 0  0
 I (516529) cdm_command_task: 1 w windSensingStatus = 0, windSensingStatus = false, cTab 0 0, cFunc 1 ft01 1
 I (516549) cdm_command_task: 1 w voiceSignStatus = 0, voiceSignStatus = false, cTab 0 0, cFunc 1 ft01 1
 I (516569) cdm_command_task: 1 w voiceStatus = 0, voiceStatus = false, cTab 0 0, cFunc 1 ft01 1
 I (516579) cdm_command_task: 1 w energySavingStatus = 0, energySavingStatus = false, cTab 0 0, cFunc 1 ft01 1
 I (516609) cdm_command_task: 1 w lightStatus = 0, lightStatus = false, cTab 0 0, cFunc 1 ft01 1
 I (516629) cdm_command_task: 1 w ch2oCleaningStatus = 0, ch2oCleaningStatus = false, cTab 0 0, cFunc 1 ft01 1
 I (516659) cdm_command_task: 1 w pm2p5CleaningStatus = 0, pm2p5CleaningStatus = false, cTab 0 0, cFunc 1 ft01 1
 I (516679) cdm_command_task: 1 w humidificationStatus = 0, humidificationStatus = false, cTab 0 0, cFunc 1 ft01 1
 I (516699) cdm_command_task: 1 w freshAirStatus = 0, freshAirStatus = false, cTab 0 0, cFunc 1 ft01 1
 I (516739) cdm_command_task: 1 w windSpeed = 5, windSpeed = 5, cTab 0 0, cFunc 0  0
 I (516759) cdm_command_task: 1 w windDirectionVertical = 5, windDirectionVertical = 5, cTab 0 0, cFunc 0  0
 I (516779) cdm_command_task: 1 w windDirectionHorizontal = 0, windDirectionHorizontal = 0, cTab 0 0, cFunc 0  0
 I (516799) cdm_command_task: 1 w silentSleepStatus = 1, silentSleepStatus = true, cTab 0 0, cFunc 1 ft01 1
 I (516829) cdm_command_task: 0 ? prStr = Heat
 I (516829) cdm_command_task: edgeCommand = operationName=grSetDAC
 I (516829) cdm_command_task: applianceCommand = onOffStatus=true&screenDisplayStatus=true&echoStatus=false&targetTemperature=22.00&operationMode=4&10degreeHeatingStatus=false&muteStatus=false&rapidMode=false&healthMode=false&humanSensingStatus=0&selfCleaning56Status=false&selfCleaningStatus=false&cleaningTimeStatus=false&cloudFilterChangeFlag=false&specialMode=0&energySavePeriod=15&heatAccumulationStatus=false&tempUnit=1&pmvStatus=false&intelligenceStatus=false&halfDegreeSettingStatus=false&lockStatus=false&electricHeatingStatus=false&targetHumidity=30&windSensingStatus=false&voiceSignStatus=false&voiceStatus=false&energySavingStatus=false&lightStatus=false&ch2oCleaningStatus=false&pm2p5CleaningStatus=false&humidificationStatus=false&freshAirStatus=false&windSpeed=5&windDirectionVertical=5&windDirectionHorizontal=0&silentSleepStatus=true
 I (516909) uplus_epp_usr_monitor: e_EPP_Protocol_Connection_State = 10, status = 5, free heap = 70780
 I (516909) cdm_trigger_epp_request: operationName = grSetDAC
 W (516919) uplus_epp_plugin_op: sn = 18, name = grSetDAC
 I (516959) cdm_rx_task: s sFunc errors errors 00
 I (516959) cdm_rx_task: + operationName = grSetDAC -> , isSuperTriggerStatusChange 1
 I (516969) cdm_rx_task: isSuperTriggerStatusChange = 1, isStatusChange = 1, isTransmissionRateElapsed = 0, currentTimestamp = 1628677170, transmissionTimestamp = 1628677169, elapsed = 1, transMode = 0, transmissionRate = 3600
 [UHomeOS][I][516371]: w json data : [{"name":"onOffStatus","value":"true"},{"name":"screenDisplayStatus","value":"true"},{"name":"echoStatus","value":"false"},{"name":"targetTemperature","value":"22.00"},{"name":"operationMode","value":"4"},{"name":"10degreeHeatingStatus","value":"false"},{"name":"muteStatus","value":"false"},{"name":"rapidMode","value":"false"},{"name":"healthMode","value":"false"},{"name":"humanSensingStatus","value":"0"},{"name":"selfCleaning56Status","value":"false"},{"name":"selfCleaningStatus","value":"false"},{"name":"cleaningTimeStatus","value":"false"},{"name":"cloudFilterChangeFlag","value":"false"},{"name":"specialMode","value":"0"},{"name":"energySavePeriod","value":"15"},{"name":"heatAccumulationStatus","value":"false"},{"name":"tempUnit","value":"1"},{"name":"pmvStatus","value":"false"},{"name":"intelligenceStatus","value":"false"},{"name":"halfDegreeSettingStatus","value":"false"},{"name":"lockStatus","value":"false"},{"name":"electricHeatingStatus","value":"false"},{"name":"targetHumidity","value":"30"},{"name":"windSensingStatus","value":"false"},{"name":"voiceSignStatus","value":"false"},{"name":"voiceStatus","value":"false"},{"name":"energySavingStatus","value":"false"},{"name":"lightStatus","value":"false"},{"name":"ch2oCleaningStatus","value":"false"},{"name":"pm2p5CleaningStatus","value":"false"},{"name":"humidificationStatus","value":"false"},{"name":"freshAirStatus","value":"false"},{"name":"windSpeed","value":"5"},{"name":"windDirectionVertical","value":"5"},{"name":"windDirectionHorizontal","value":"0"},{"name":"silentSleepStatus","value":"true"}]
 I (517149) uplug_info_get_cb: info_type = 1, status = 5
 op_name::grSetDAC
 attr_set:[{"name":"onOffStatus","value":"true"},{"name":"screenDisplayStatus","value":"true"},{"name":"echoStatus","value":"false"},{"name":"targetTemperature","value":"22.00"},{"name":"operationMode","value":"4"},{"name":"10degreeHeatingStatus","value":"false"},{"name":"muteStatus","value":"false"},{"name":"rapidMode","value":"false"},{"name":"healthMode","value":"false"},{"name":"humanSensingStatus","value":"0"},{"name":"selfCleaning56Status","value":"false"},{"name":"selfCleaningStatus","value":"false"},{"name":"cleaningTimeStatus","value":"false"},{"name":"cloudFilterChangeFlag","value":"false"},{"name":"specialMode","value":"0"},{"name":"energySavePeriod","value":"15"},{"name":"heatAccumulationStatus","value":"false"},{"name":"tempUnit","value":"1"},{"name":"pmvStatus","value":"false"},{"name":"intelligenceStatus","value":"false"},{"name":"halfDegreeSettingStatus","value":"false"},{"name":"lockStatus","value":"false"},{"name":"electricHeatingStatus","value":"false"},{"name":"targetHumidity","value":"30"},{"name":"windSensingStatus","value":"false"},{"name":"voiceSignStatus","value":"false"},{"name":"voiceStatus","value":"false"},{"name":"energySavingStatus","value":"false"},{"name":"lightStatus","value":"false"},{"name":"ch2oCleaningStatus","value":"false"},{"name":"pm2p5CleaningStatus","value":"false"},{"name":"humidificationStatus","value":"false"},{"name":"freshAirStatus","value":"false"},{"name":"windSpeed","value":"5"},{"name":"windDirectionVertical","value":"5"},{"name":"windDirectionHorizontal","value":"0"},{"name":"silentSleepStatus","value":"true"}]
 dev_set:{"subdeviceList":[]}
 INFO:exec info is 'onOffStatus true'
 INFO:exec info is 'screenDisplayStatus true'
 INFO:exec info is 'echoStatus false'
 INFO:exec info is 'targetTemperature 22.00'
 INFO:exec info is 'operationMode 4'
 INFO:exec info is '10degreeHeatingStatus false'
 INFO:exec info is 'muteStatus false'
 INFO:exec info is 'rapidMode false'
 INFO:exec info is 'healthMode false'
 INFO:exec info is 'humanSensingStatus 0'
 WRN:not found sub json in configfile:[selfCleaning56Status]
 INFO:exec info is 'selfCleaningStatus false'
 INFO:exec info is 'cleaningTimeStatus false'
 INFO:exec info is 'cloudFilterChangeFlag false'
 INFO:exec info is 'specialMode 0'
 INFO:exec info is 'energySavePeriod 15'
 WRN:not found sub json in configfile:[heatAccumulationStatus]
 INFO:exec info is 'tempUnit 1'
 INFO:exec info is 'pmvStatus false'
 INFO:exec info is 'intelligenceStatus false'
 INFO:exec info is 'halfDegreeSettingStatus false'
 INFO:exec info is 'lockStatus false'
 INFO:exec info is 'electricHeatingStatus false'
 INFO:exec info is 'targetHumidity 30'
 WRN:not found sub json in configfile:[windSensingStatus]
 WRN:not found sub json in configfile:[voiceSignStatus]
 WRN:not found sub json in configfile:[voiceStatus]
 INFO:exec info is 'energySavingStatus false'
 INFO:exec info is 'lightStatus false'
 INFO:exec info is 'ch2oCleaningStatus false'
 INFO:exec info is 'pm2p5CleaningStatus false'
 INFO:exec info is 'humidificationStatus false'
 INFO:exec info is 'freshAirStatus false'
 INFO:exec info is 'windSpeed 5'
 INFO:exec info is 'windDirectionVertical 5'
 INFO:exec info is 'windDirectionHorizontal 0'
 INFO:exec info is 'silentSleepStatus true'
 epp data: FF FF 14 00 00 00 00 00 00 01 60 01 06 06 85 00 02 21 00 00 00 00 2A
 I (517449) uplug_info_get_cb: wifi_ap_record.rssi = -49, wifi_info->rssi = 61
 I (517529) cdm_rx_task: s sFunc errors errors 00
 [UHomeOS][D][516882]: tx serial e++ data
 ff ff 0c 40 00 00 00 00 00 f7 00 00 00 3d 80 d5
 71
 [UHomeOS][I][516884]: [UART] tx [cmd 0xF7 len = 12, 17] ret 17
 I (517569) cdm_trigger_epp_request: pairs_count = 37, ret = 0
 [UHomeOS][D][516971]: rx serial e++ data
 ff ff 08 00 00 00 00 00 00 05 4d
 [UHomeOS][I][516972]: [UART] rx [cmd 0x05 len = 8]
 [UHomeOS][LOG][516972]: e++ comm time: 90
 [UHomeOS][D][517041]: tx serial e++ data
 ff ff 14 40 00 00 00 00 00 01 60 01 06 06 85 00
 02 21 00 00 00 00 6a 20 1e
 [UHomeOS][I][517043]: [UART] tx [cmd 0x01 len = 20, 25] ret 25
 [UHomeOS][D][517171]: rx serial e++ data
 ff ff 2a 00 00 00 00 00 00 02 6d 01 06 06 85 00
 02 21 00 00 00 00 34 00 5f 00 00 03 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 24
 [UHomeOS][I][517176]: [UART] rx [cmd 0x02 len = 42]
 [UHomeOS][LOG][517181]: e++ comm time: 140
 I (518089) cdm_rx_task: s sFunc errors errors 00
 [UHomeOS][I][517551]: status changed
 uplus_get_pkt_buf_list called
 [UHomeOS][D][517571]: rsp
 ff ff 2a 00 00 00 00 00 00 02 6d 01 06 06 85 00
 02 21 00 00 00 00 34 00 5f 00 00 03 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 e4
 ERR:e++ data[0][type:2]doesn't match with attr[errCode]'s value list in configfile
 [UHomeOS][W][517618]: rx op rsp, sn 18, result 0
 op response, sn 18, result 0, pairs 49
 I (518269) cdm_command_task: cdm_command_executed_queue_element = SUCCESS
 uplus_get_pkt_buf_list called
 [UHomeOS][D][517675]: rpt
 ff ff 2a 00 00 00 00 00 00 06 6d 01 06 06 85 00
 02 21 00 00 00 00 34 00 5f 00 00 03 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 e8
 ERR:e++ data[0][type:2]doesn't match with attr[errCode]'s value list in configfile
 status report pairs 49
 I (518369) cdm_enqueue_rx: free heap 59948
 I (518379) cdm_enqueue_rx: free heap 57068
 I (518569) uplus_epp_usr_monitor: e_EPP_Protocol_Connection_State = 10, status = 5, free heap = 70568
 I (518599) cdm_rx_task: 1 r targetTemperature = 22.00, tempSel = 22.00, cTab 0 0, cFunc 0  0
 I (518609) cdm_rx_task: 1 r windDirectionVertical = 5, windDirectionVertical = 5, cTab 0 0, cFunc 0  0
 I (518619) cdm_rx_task: 1 r operationMode = 4, machMode = 4, cTab 0 0, cFunc 0  0
 I (518629) cdm_rx_task: 1 r specialMode = 0, specialMode = 0, cTab 0 0, cFunc 0  0
 I (518649) cdm_rx_task: 1 r windSpeed = 5, windSpeed = 5, cTab 0 0, cFunc 0  0
 I (518649) cdm_rx_task: 1 r energySavePeriod = 15, energySavePeriod = 15, cTab 0 0, cFunc 0  0
 I (518669) cdm_rx_task: 1 r tempUnit = 1, tempUnit = 0, cTab 1 1, cFunc 0  0
 I (518679) cdm_rx_task: 1 r pmvStatus = false, pmvStatus = 0, cTab 0 0, cFunc 1 ft01 1
 I (518689) cdm_rx_task: 1 r intelligenceStatus = false, intelligenceStatus = 0, cTab 0 0, cFunc 1 ft01 1
 I (518699) cdm_rx_task: 1 r halfDegreeSettingStatus = false, halfDegreeSettingStatus = 0, cTab 0 0, cFunc 1 ft01 1
 I (518719) cdm_rx_task: 1 r screenDisplayStatus = true, screenDisplayStatus = 1, cTab 0 0, cFunc 1 ft01 1
 I (518719) cdm_rx_task: 1 r 10degreeHeatingStatus = false, 10degreeHeatingStatus = 0, cTab 0 0, cFunc 1 ft01 1
 I (518739) cdm_rx_task: 1 r echoStatus = false, echoStatus = 0, cTab 0 0, cFunc 1 ft01 1
 I (518759) cdm_rx_task: 1 r lockStatus = false, lockStatus = 0, cTab 0 0, cFunc 1 ft01 1
 I (518769) cdm_rx_task: 1 r silentSleepStatus = true, silentSleepStatus = 1, cTab 0 0, cFunc 1 ft01 1
 I (518779) cdm_rx_task: 1 r muteStatus = false, muteStatus = 0, cTab 0 0, cFunc 1 ft01 1
 I (518799) cdm_rx_task: 1 r rapidMode = false, rapidMode = 0, cTab 0 0, cFunc 1 ft01 1
 I (518799) cdm_rx_task: 1 r electricHeatingStatus = false, electricHeatingStatus = 0, cTab 0 0, cFunc 1 ft01 1
 I (518819) cdm_rx_task: 1 r healthMode = false, healthMode = 0, cTab 0 0, cFunc 1 ft01 1
 I (518829) cdm_rx_task: 1 r onOffStatus = true, onOffStatus = 1, cTab 0 0, cFunc 1 ft01 1
 I (518849) cdm_rx_task: 1 r targetHumidity = 30, humiditySel = 30, cTab 0 0, cFunc 0  0
 I (518859) cdm_rx_task: 1 r humanSensingStatus = 0, humanSensingStatus = 0, cTab 0 0, cFunc 0  0
 I (518869) cdm_rx_task: 1 r windDirectionHorizontal = 0, windDirectionHorizontal = 0, cTab 0 0, cFunc 0  0
 I (518879) cdm_rx_task: 1 r localFilterChangeFlag = false, filterChangeStatusLocal = 0, cTab 0 0, cFunc 1 ft01 1
 I (518889) cdm_rx_task: 1 r energySavingStatus = false, energySavingStatus = 0, cTab 0 0, cFunc 1 ft01 1
 I (518909) cdm_rx_task: 1 r lightStatus = false, lightStatus = 0, cTab 0 0, cFunc 1 ft01 1
 I (518919) cdm_rx_task: 1 r selfCleaningStatus = false, selfCleaningStatus = 0, cTab 0 0, cFunc 1 ft01 1
 I (518929) cdm_rx_task: 1 r ch2oCleaningStatus = false, ch2oCleaningStatus = 0, cTab 0 0, cFunc 1 ft01 1
 I (518949) cdm_rx_task: 1 r pm2p5CleaningStatus = false, pm2p5CleaningStatus = 0, cTab 0 0, cFunc 1 ft01 1
 I (518959) cdm_rx_task: 1 r humidificationStatus = false, humidificationStatus = 0, cTab 0 0, cFunc 1 ft01 1
 I (518969) cdm_rx_task: 1 r freshAirStatus = false, freshAirStatus = 0, cTab 0 0, cFunc 1 ft01 1
 I (518989) cdm_rx_task: 1 r indoorTemperature = 26.00, tempIndoor = 26.00, cTab 0 0, cFunc 0  0
 I (518999) cdm_rx_task: 1 r indoorHumidity = 0, humidityIndoor = 0, cTab 0 0, cFunc 0  0
 I (519009) cdm_rx_task: 1 r outdoorTemperature = 31.00, tempOutdoor = 31.00, cTab 0 0, cFunc 0  0
 I (519019) cdm_rx_task: 1 r acType = 0, acType = 0, cTab 0 0, cFunc 0  0
 I (519039) cdm_rx_task: 1 r sensingResult = 0, sensingResult = 0, cTab 0 0, cFunc 0  0
 I (519039) cdm_rx_task: 1 r airQuality = 0, airQuality = 0, cTab 0 0, cFunc 0  0
 I (519059) cdm_rx_task: 1 r pm2p5Level = 0, pm2p5LevelIndoor = 0, cTab 0 0, cFunc 0  0
 I (519069) cdm_rx_task: 1 r errCode = , errCode = , cTab 0 0, cFunc 0  0
 I (519079) cdm_rx_task: 1 r ErrAckFlag = false, errAckFlag = 0, cTab 0 0, cFunc 1 ft01 1
 I (519099) cdm_rx_task: 1 r operationModeHK = 0, machineModeHK = 0, cTab 0 0, cFunc 0  0
 I (519109) cdm_rx_task: 1 r opSrc = 3, operationSource = 3, cTab 0 0, cFunc 0  0
 I (519129) cdm_rx_task: 1 r totalCleaningTime = 0, totalWorkTime = 0, cTab 0 0, cFunc 0  0
 I (519129) cdm_rx_task: 1 r indoorPM2p5Value = 0, pm2p5ValueIndoor = 0, cTab 0 0, cFunc 0  0
 I (519149) cdm_rx_task: 1 r outdoorPM2p5Value = 0, pm2p5ValueOutdoor = 0, cTab 0 0, cFunc 0  0
 I (519149) cdm_rx_task: 1 r ch2oValue = 0, ch2oValueIndoor = 0, cTab 0 0, cFunc 0  0
 I (519179) cdm_rx_task: 1 r vocValue = 0, vocValueIndoor = 0, cTab 0 0, cFunc 0  0
 I (519179) cdm_rx_task: 1 r co2Value = 0, co2ValueIndoor = 0, cTab 0 0, cFunc 0  0
 I (519199) cdm_rx_task: 1 r totalElectricityUsed = 0, totalElectricityUsed = 0, cTab 0 0, cFunc 0  0
 I (519239) cdm_rx_task: s sFunc errors errors 00
 I (519249) cdm_rx_task: + silentSleepStatus = 0 -> 1, isSuperTriggerStatusChange 1
 I (519249) cdm_rx_task: isSuperTriggerStatusChange = 1, isStatusChange = 1, isTransmissionRateElapsed = 0, currentTimestamp = 1628677172, transmissionTimestamp = 1628677170, elapsed = 2, transMode = 0, transmissionRate = 3600
 [UHomeOS][D][518672]: tx serial e++ data
 ff ff 08 40 00 00 00 00 00 73 bb 87 01
 [UHomeOS][I][518674]: [UART] tx [cmd 0x73 len = 8, 13] ret 13
 [UHomeOS][D][518761]: rx serial e++ data
 ff ff 12 00 00 00 00 00 00 74 0f 5a 00 00 00 00
 00 00 00 00 2f
 [UHomeOS][I][518762]: [UART] rx [cmd 0x74 len = 18]
 [UHomeOS][LOG][518765]: e++ comm time: 94
 [UHomeOS][D][518851]: tx serial e++ data
 ff ff 0a 40 00 00 00 00 00 01 4d 01 99 b3 b4
 [UHomeOS][I][518852]: [UART] tx [cmd 0x01 len = 10, 15] ret 15
 I (519579) uplus_epp_usr_monitor: e_EPP_Protocol_Connection_State = 10, status = 5, free heap = 71392
 [UHomeOS][D][518971]: rx serial e++ data
 ff ff 2a 00 00 00 00 00 00 02 6d 01 06 06 85 00
 02 21 00 00 00 00 34 00 5f 00 00 03 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 24
 [UHomeOS][I][518977]: [UART] rx [cmd 0x02 len = 42]
 [UHomeOS][LOG][518981]: e++ comm time: 130
 [UHomeOS][D][519062]: tx serial e++ data
 ff ff 08 40 00 00 00 00 00 fc 44 23 40
 [UHomeOS][I][519062]: [UART] tx [cmd 0xFC len = 8, 13] ret 13
 I (519819) cdm_rx_task: s sFunc errors errors 00
 [UHomeOS][D][519163]: rx serial e++ data
 ff ff 0e 00 00 00 00 00 00 fd 00 00 00 00 00 00
 4b
 [UHomeOS][I][519165]: [UART] rx [cmd 0xFD len = 14]
 [UHomeOS][LOG][519169]: e++ comm time: 108

2 Likes

Mabe is a Mexican division of Haier, and from pictures I saw of the “Mabe” wifi card, I realized they were both using the same KZW-W001. I just used your code and was able to add my Mabe branded mini split to Home Assistant with little issue. The only thing is when I select Cool in the Home Assistant app, the mini split display shows a green snowflake/green star of some sort, and not the blue snowflake for cooling mode. Everything else works perfect.

Maybe enable “eco mode”?

If you set the cool mode from device remote, with show Home Assistant?

I ordered JST XH connectors but the won’t fit.
They are way to big!

So I went through and reflashed the Wemos and saw all the Deprecated comments on the swing and modes, so I went through the forks of your code.

I found someone, Okison, that had revised your code to incorporate swing and the new Home Assistant code.

Revised Haier.h code incorporating Swing by Okison

The previous issue with the green snowflake disappeared with flashing Okison’s version, but now, the Home Assistant climate page for the mini split shows “Off” regardless of mode. Everything works, but the persistent “Off” is confusing.

1 Like

Because I still doesn’t have the right connector i put the Wemos D1 at the ESP32.
With the Haierv2.h file from albetaCOM GitHub - albetaCOM/esp-haier: ESP8266 code to connect to Haier Air Conditioner ((firmware version I can communicate with the unit.

It can turn it on and off. When I set temperature it goes to “Health” mode (the same as fresh or purified?). When I set another mode it also goes to health mode.
It turns on when I select a mode like “cool or heat” but it goes on “Health”

I don’t have the knowhow from here. But changing the ESP32 for a ESP8266 gives opportunities.

A little late to the party, but did you check, if your unit is a Midea one? There would be a solution ready to use. It looks a lot like the Midea PCBs…

Check here: Midea branded AC’s with ESPhome (no cloud)

Try to delete or comment row 123:

traits.set_supports_action(true);

I’m using the Haierv2.h file from albetaCOM GitHub - albetaCOM/esp-haier:

I’ve modified Haierv2.h in order to eliminate deprecated warnings and I had your same problem.
For me solution has been to delete

traits.set_supports_action(true);

I’ve a workaround for the “Health” problem.
Below is a new version of Haierv2.h file.
Now is Haierv3.h
The Health problem seems to be related to the Purify flag.

If PurifyControl is set to false (row 471 of Haierv3.h ) the Purify status is toggle at every command
(don’t ask why)
So the solution is to send the message two times with an interval of 1 sec.
Look at row 759

  • Result is that the Purify status after the second message is maintained (if was ON remain ON, if was off remain OFF)

  • You can change the Purify using the remote.

  • Not a perfect solution, just a workaround :slight_smile:

I’ve also removed all the ‘deprecated’ messages.

Here is the modified file

/**
* Create by Miguel Ángel López on 20/07/19
* Modified by Alba Prades on 21/07/20
* Modified by Alba Prades on 13/08/20 
* Modified by Alba Prades on 25/08/20: Added fan, dry and swing features
*      Added modes
* Modified by Carlo Pinasco on 25/08/21: Workaround to fix Purify problem and fix deprecated warning messages.
*   
*   If PurifyControl is set to false (row 471) the Purify status is toggle at every command
*   (don't ask why)
*   So the solution is to send the message two times with an interval of 1 sec.
*   Look at row 759
*   Result is that the Purify status after the second message is maintened (if was ON remain ON, if was off remain OFF)
*   You can change the Purify using the remote.
*   Not a perfect solution, just a workaround :-)
*
*
**/

#ifndef HAIER_ESP_HAIER_H
#define HAIER_ESP_HAIER_H

#include "esphome.h"
#include <string>

using namespace esphome;
using namespace esphome::climate;

// Updated read offset

#define MODE_OFFSET 			14
#define MODE_MSK				0xF0
	#define MODE_AUTO       	0x00
	#define MODE_DRY			0x40
	#define MODE_COOL			0x20
	#define MODE_HEAT			0x80
	#define MODE_FAN			0xC0
#define FAN_MSK					0x0F
	#define FAN_LOW	    		0x03
	#define FAN_MID		  		0x02
	#define FAN_HIGH	     	0x01
	#define FAN_AUTO	   		0x05
	
#define HORIZONTAL_SWING_OFFSET		19
	#define HORIZONTAL_SWING_CENTER 		0x00
	#define HORIZONTAL_SWING_MAX_LEFT 		0x03
	#define HORIZONTAL_SWING_LEFT 			0x04
	#define HORIZONTAL_SWING_MAX_RIGHT 		0x06
	#define HORIZONTAL_SWING_RIGHT 			0x05
	#define HORIZONTAL_SWING_AUTO 			0x07
	
#define VERTICAL_SWING_OFFSET			13
	#define VERTICAL_SWING_MAX_UP			0x02
	#define VERTICAL_SWING_UP				0x04
	#define VERTICAL_SWING_CENTER				0x06
	#define VERTICAL_SWING_DOWN				0x08
	#define VERTICAL_SWING_HEALTH_UP			0x01
	#define VERTICAL_SWING_HEALTH_DOWN		0x03
	#define VERTICAL_SWING_AUTO 				0x0C

#define TEMPERATURE_OFFSET   	22

#define STATUS_DATA_OFFSET			17 // Purify/Quiet mode/OnOff/...
	#define POWER_BIT				(0)	
	#define PURIFY_BIT				(1)	
	#define QUIET_BIT				(3)	
	#define AUTO_FAN_MAX_BIT		(4)
	
#define SET_POINT_OFFSET 		12	

// Another byte
	#define SWING        		27
	#define SWING_OFF          	0
	#define SWING_VERTICAL     	1
	#define SWING_HORIZONTAL   	2
	#define SWING_BOTH

	#define LOCK        		28
	#define LOCK_ON     		80
	#define LOCK_OFF    		00

// Updated read offset



#define FRESH       			31
	#define FRESH_ON    		1
	#define FRESH_OFF   		0

// Updated read offset


#define COMMAND_OFFSET			9
	#define RESPONSE_POLL		2

#define CRC_OFFSET(message)		(2 + message[2])

// Control commands
#define CTR_POWER_OFFSET		13
	#define CTR_POWER_ON		0x01
	#define CTR_POWER_OFF		0x00
	
#define POLY 0xa001


// temperatures supported by AC system
#define MIN_SET_TEMPERATURE 16
#define MAX_SET_TEMPERATURE 30

//if internal temperature is outside of those boundaries, message will be discarded
#define MIN_VALID_INTERNAL_TEMP 10
#define MAX_VALID_INTERNAL_TEMP 50

class Haier : public Climate, public PollingComponent {

private:

    byte lastCRC;
    byte status[47];
	
	byte initialization_1[13] = {0xFF,0xFF,0x0A,0x0,0x0,0x0,0x0,0x0,0x00,0x61,0x00,0x07,0x72};
	byte initialization_2[13] = {0xFF,0xFF,0x08,0x40,0x0,0x0,0x0,0x0,0x0,0x70,0xB8,0x86,0x41};
 	byte poll[15] = {0xFF,0xFF,0x0A,0x40,0x00,0x00,0x00,0x00,0x00,0x01,0x4D,0x01,0x99,0xB3,0xB4};
    byte power_command[17]     = {0xFF,0xFF,0x0C,0x40,0x00,0x00,0x00,0x00,0x00,0x01,0x5D,0x01,0x00,0x01,0xAC,0xBD,0xFB};
	byte control_command[25] = {0xFF,0xFF,0x14,0x40,0x00,0x00,0x00,0x00,0x00,0x01,0x60,0x01,0x09,0x08,0x25,0x00,0x02,0x03,0x00,0x06,0x00,0x0C,0x03,0x0B,0x70};

	byte climate_mode_fan_speed = FAN_AUTO;
	byte climate_mode_setpoint = 0x0A;
	
	byte fan_mode_fan_speed = FAN_HIGH;
	byte fan_mode_setpoint = 0x08;
	
	bool first_status_received = false;
	
	// Some vars for debuging purposes	
	byte previous_status[47];
	bool previous_status_init = false;
	
	
	// Functions

	void SetHvacModeControl(byte mode)
	{
		control_command[MODE_OFFSET] &= ~MODE_MSK;
		control_command[MODE_OFFSET] |= mode;
	}	
	
	byte GetHvacModeStatus()
	{
		return status[MODE_OFFSET] & MODE_MSK;
	}	
	
	void SetTemperatureSetpointControl(byte temp)
	{ 
		control_command[SET_POINT_OFFSET] = temp;
	}	
	
	byte GetTemperatureSetpointStatus()
	{
		return status[SET_POINT_OFFSET];
	}	
	
	void SetFanSpeedControl(byte fan_mode)
	{
		control_command[MODE_OFFSET] &= ~FAN_MSK;
		control_command[MODE_OFFSET] |= fan_mode;
	}
	
	byte GetFanSpeedStatus()
	{
		return status[MODE_OFFSET] & FAN_MSK;
	}		
	
	void SetHorizontalSwingControl(byte swing_mode)
	{
		control_command[HORIZONTAL_SWING_OFFSET] = swing_mode;
	}
	
	byte GetHorizontalSwingStatus()
	{
		return status[HORIZONTAL_SWING_OFFSET];
	}	
	
	void SetVerticalSwingControl(byte swing_mode)
	{
		control_command[VERTICAL_SWING_OFFSET] = swing_mode;
	}
	
	byte GetVerticalSwingStatus()
	{
		return status[VERTICAL_SWING_OFFSET];
	}	
	
	void SetQuietModeControl(bool quiet_mode)
	{
		byte tmp;
		byte msk;
		
		msk = (0x01 << QUIET_BIT);		
		
		if(quiet_mode == true){
			control_command[STATUS_DATA_OFFSET] |= msk;
		}
		else{
			msk = ~msk;
			control_command[STATUS_DATA_OFFSET] &= msk;
		}
	}
	
	bool GetQuietModeStatus( void )
	{
		bool ret = false;		
		byte tmp;
		byte msk;
		
		msk = (0x01 << QUIET_BIT);
		tmp = status[STATUS_DATA_OFFSET] & msk;
		
		if(tmp != 0) ret = true;
		
		return ret;
	}
	
	
	void SetPurifyControl(bool purify_mode)
	{
		byte tmp;
		byte msk;
		
		msk = (0x01 << PURIFY_BIT);		
		
		if(purify_mode == true){
			control_command[STATUS_DATA_OFFSET] |= msk;
		}
		else{
			msk = ~msk;
			control_command[STATUS_DATA_OFFSET] &= msk;
		}
	}
	
	bool GetPurifyStatus( void )
	{
		bool ret = false;		
		byte tmp;
		byte msk;
		
		msk = (0x01 << PURIFY_BIT);
		tmp = status[STATUS_DATA_OFFSET] & msk;
		
		if(tmp != 0) ret = true;
		
		return ret;
	}
	
	void SetPowerControl(bool power_mode)
	{
		byte tmp;
		byte msk;
		
		msk = (0x01 << POWER_BIT);		
		
		if(power_mode == true){
			control_command[STATUS_DATA_OFFSET] |= msk;
		}
		else{
			msk = ~msk;
			control_command[STATUS_DATA_OFFSET] &= msk;
		}
	}
	
	bool GetPowerStatus( void )
	{
		bool ret = false;		
		byte tmp;
		byte msk;
		
		msk = (0x01 << POWER_BIT);
		tmp = status[STATUS_DATA_OFFSET] & msk;
		
		if(tmp != 0) ret = true;
		
		return ret;
	}
	
	
	bool GetFastModeStatus( void )
	{
		bool ret = false;		
		byte tmp;
		byte msk;
		
		msk = (0x01 << AUTO_FAN_MAX_BIT);
		tmp = status[STATUS_DATA_OFFSET] & msk;
		
		if(tmp != 0) ret = true;
		
		return ret;
	}
	
	void SetFastModeControl(bool fast_mode)
	{
		byte tmp;
		byte msk;
		
		msk = (0x01 << AUTO_FAN_MAX_BIT);		
		
		if(fast_mode == true){
			control_command[STATUS_DATA_OFFSET] |= msk;
		}
		else{
			msk = ~msk;
			control_command[STATUS_DATA_OFFSET] &= msk;
		}
	}
	
	
	void CompareStatusByte()
	{
		int i;
		
		if(previous_status_init == false){
			for (i=0;i<sizeof(status);i++){
				previous_status[i] = status[i];
			}
			previous_status_init = true;
		}
		
		for (i=0;i<sizeof(status);i++)
		{
			if(status[i] != previous_status[i]){
				ESP_LOGD("Debug", "Status byte %d: 0x%X --> 0x%X ", i, previous_status[i],status[i]);
			}
			previous_status[i] = status[i];
		}
	}


public:

    Haier() : PollingComponent(5 * 1000) {
        lastCRC = 0;
    }


    
    void setup() override {
        
        Serial.begin(9600);
		delay(1000);
		Serial.write(initialization_1, sizeof(initialization_1));
        auto raw = getHex(initialization_1, sizeof(initialization_1));
        ESP_LOGD("Haier", "initialization_1: %s ", raw.c_str());
		delay(1000);
		Serial.write(initialization_2, sizeof(initialization_2));
        raw = getHex(initialization_2, sizeof(initialization_2));
        ESP_LOGD("Haier", "initialization_2: %s ", raw.c_str());
    }

    void loop() override  {
		byte data[47];
        if (Serial.available() > 0) {
			if (Serial.read() != 255) return;
			if (Serial.read() != 255) return;
			
			data[0] = 255;
			data[1] = 255;

            Serial.readBytes(data+2, sizeof(data)-2);
			
			// If is a status response
			if (data[COMMAND_OFFSET] == RESPONSE_POLL) {
				// Update the status frame
				memcpy(status, data, sizeof(status));
				parseStatus();
			}
		}
    }

    void update() override {
        
        Serial.write(poll, sizeof(poll));
        auto raw = getHex(poll, sizeof(poll));
        ESP_LOGD("Haier", "POLL: %s ", raw.c_str());
    }

protected:
    ClimateTraits traits() override {
        auto traits = climate::ClimateTraits();
        //traits.set_supports_away(false);
        //traits.set_supports_auto_mode(true);
        //traits.set_supports_heat_mode(true);
        //traits.set_supports_cool_mode(true);
        //traits.set_supports_dry_mode(true);
        //traits.set_supports_fan_only_mode(true);
        //traits.set_supports_fan_mode_on(false);
        //traits.set_supports_fan_mode_off(false);
        //traits.set_supports_fan_mode_auto(true);
        //traits.set_supports_fan_mode_low(true);
        //traits.set_supports_fan_mode_medium(true);
        //traits.set_supports_fan_mode_middle(true);
        //traits.set_supports_fan_mode_high(true);
       // traits.set_supports_fan_mode_focus(false);
        //traits.set_supports_fan_mode_diffuse(false);		
        
        //traits.set_supports_action(true);

        traits.set_supported_modes(
        {
            climate::CLIMATE_MODE_OFF,
            climate::CLIMATE_MODE_COOL,
            climate::CLIMATE_MODE_HEAT,
            climate::CLIMATE_MODE_FAN_ONLY,
            climate::CLIMATE_MODE_DRY,
            climate::CLIMATE_MODE_AUTO
        });

        traits.set_supported_fan_modes(
        {
            climate::CLIMATE_FAN_AUTO,
            climate::CLIMATE_FAN_LOW,
            climate::CLIMATE_FAN_MEDIUM,
            climate::CLIMATE_FAN_HIGH,
            climate::CLIMATE_FAN_MIDDLE
            
        });

        traits.set_supported_swing_modes(
        {
            climate::CLIMATE_SWING_OFF,
            climate::CLIMATE_SWING_BOTH,
            climate::CLIMATE_SWING_VERTICAL,
            climate::CLIMATE_SWING_HORIZONTAL
        });

        traits.set_visual_min_temperature(MIN_SET_TEMPERATURE);
        traits.set_visual_max_temperature(MAX_SET_TEMPERATURE);
        traits.set_visual_temperature_step(1.0f);
        traits.set_supports_current_temperature(true);
        //traits.set_supports_swing_mode_off(true);
        //traits.set_supports_swing_mode_both(true);
        //traits.set_supports_swing_mode_vertical(true);
        //traits.set_supports_swing_mode_horizontal(true);		
        //traits.set_supports_action(true);// Cal identificar el byte
        return traits;
    }

public:

    void parseStatus() {


        auto raw = getHex(status, sizeof(status));
        ESP_LOGD("Haier", "Readed message ALBA: %s ", raw.c_str());

        byte check = getChecksum(status, sizeof(status));

        if (check != status[CRC_OFFSET(status)]) {
            ESP_LOGW("Haier", "Invalid checksum (%d vs %d)", check, status[CRC_OFFSET(status)]);
            return;
        }

        lastCRC = check;

        current_temperature = status[TEMPERATURE_OFFSET]/2;
        target_temperature = status[SET_POINT_OFFSET] + 16;

        if(current_temperature < MIN_VALID_INTERNAL_TEMP || current_temperature > MAX_VALID_INTERNAL_TEMP 
            || target_temperature < MIN_SET_TEMPERATURE || target_temperature > MAX_SET_TEMPERATURE){
            ESP_LOGW("Haier", "Invalid temperatures");
            return;
        }
		
		// Read all the info from the status message and update values in control message
		// so the next message is updated
		// This is usefull if there are manual changes with the remote control
		SetPowerControl(GetPowerStatus());
		SetHvacModeControl(GetHvacModeStatus());
		// workaround for Purify problem
        SetPurifyControl(false);
		SetQuietModeControl(GetQuietModeStatus());
		SetFastModeControl(GetFastModeStatus());
		SetFanSpeedControl(GetFanSpeedStatus());
		SetHorizontalSwingControl(GetHorizontalSwingStatus());
		SetVerticalSwingControl(GetVerticalSwingStatus());
		SetTemperatureSetpointControl(GetTemperatureSetpointStatus());
		
		if(GetHvacModeStatus() == MODE_FAN){
			fan_mode_fan_speed = GetFanSpeedStatus();
			fan_mode_setpoint = GetTemperatureSetpointStatus();
		}
		else{
			climate_mode_fan_speed = GetFanSpeedStatus();
			climate_mode_setpoint = GetTemperatureSetpointStatus();
		}
		
		// Flag to enable modifications from UI as we now know the status of the A/C
		first_status_received = true;

		
		// DEBUG DATA, uncomment what's needed
		//ESP_LOGW("Debug", "Power Status = 0x%X", GetPowerStatus());
		//ESP_LOGW("Debug", "HVAC Mode = 0x%X", GetHvacModeStatus());
		//ESP_LOGW("Debug", "Purify status = 0x%X", GetPurifyStatus());
		//ESP_LOGW("Debug", "Quiet mode Status = 0x%X", GetQuietModeStatus());
		//ESP_LOGW("Debug", "Fast mode Status = 0x%X", GetFastModeStatus());
		//ESP_LOGW("Debug", "Fan speed Status = 0x%X", GetFanSpeedStatus());
		//ESP_LOGW("Debug", "Horizontal Swing Status = 0x%X", GetHorizontalSwingStatus());
		//ESP_LOGW("Debug", "Vertical Swing Status = 0x%X", GetVerticalSwingStatus());
		//ESP_LOGW("Debug", "Set Point Status = 0x%X", GetTemperatureSetpointStatus());
		CompareStatusByte();
		
		
		// Update home assistant component
		
        if (GetPowerStatus() == false) {
            mode = CLIMATE_MODE_OFF;
		} else {
			// Check current hvac mode
            switch (GetHvacModeStatus()) {
                case MODE_COOL:
                    mode = CLIMATE_MODE_COOL;
                    break;
                case MODE_HEAT:
                    mode = CLIMATE_MODE_HEAT;
                    break;
                case MODE_DRY:
				    mode = CLIMATE_MODE_DRY;
					break;
				case MODE_FAN:
                    mode = CLIMATE_MODE_FAN_ONLY;
                    break;
                case MODE_AUTO:
                default:
                    mode = CLIMATE_MODE_AUTO;
            }
					
			// Get fan speed
			// If "quiet mode" is set we will read it as "fan low"
			if ( GetQuietModeStatus() == true) {
                fan_mode = CLIMATE_FAN_LOW;
            }
			// If we detect that fast mode is on the we read it as "fan high"
			else if( GetFastModeStatus() == true) {
				fan_mode = CLIMATE_FAN_HIGH;
			}			
			else {				
				// No quiet or fast so we read the actual fan speed.
                switch (GetFanSpeedStatus()) {
                    case FAN_AUTO:
                        fan_mode = CLIMATE_FAN_AUTO;
                        break;
                    case FAN_MID:
                        fan_mode = CLIMATE_FAN_MEDIUM;
                        break;
                    //case FAN_MIDDLE:
                    //    fan_mode = CLIMATE_FAN_MIDDLE;
                    //    break;
					case FAN_LOW:
						fan_mode = CLIMATE_FAN_LOW;
                        break;
                    case FAN_HIGH:
                        fan_mode = CLIMATE_FAN_HIGH;
                        break;
                    default:
                        fan_mode = CLIMATE_FAN_AUTO;
						
                }
            }				


			// Check the status of the swings (vertical and horizontal and translate according component configuration
			if( (GetHorizontalSwingStatus() == HORIZONTAL_SWING_AUTO) && (GetVerticalSwingStatus() == VERTICAL_SWING_AUTO) ){
				swing_mode = CLIMATE_SWING_BOTH;				
			}
			else if(GetHorizontalSwingStatus() == HORIZONTAL_SWING_AUTO){
				swing_mode = CLIMATE_SWING_HORIZONTAL;
			}
			else if(GetVerticalSwingStatus() == VERTICAL_SWING_AUTO){
				swing_mode = CLIMATE_SWING_VERTICAL;
			}
			else{
				swing_mode = CLIMATE_SWING_OFF;
			}
		}

        this->publish_state();

    }


    void control(const ClimateCall &call) override {
		
        ClimateMode new_mode;
		bool new_control_cmd = false;
		
		
		ESP_LOGD("Control", "Control call");
		
		if(first_status_received == false){
			ESP_LOGD("Control", "No action, first poll answer not received");
			return;
		}

        if (call.get_mode().has_value()) {
            // User requested mode change
            new_mode = *call.get_mode();
        
			ESP_LOGD("Control", "*call.get_mode() = %d", new_mode);
			
			// It seems that this message is no needed, we keep it here commented
						
			if((new_mode != CLIMATE_MODE_OFF) && (GetPowerStatus() == false)){
			//	 if the current mode is off -> we need to power on
				sendData(power_command, sizeof(power_command));  
				delay(1000);	
			}
			else 
			{
			
            switch (new_mode) {
                case CLIMATE_MODE_OFF:
					SetPowerControl(false);
					sendData(control_command, sizeof(control_command)); 
                    break;
					
                case CLIMATE_MODE_AUTO:
					SetPowerControl(true);
					SetHvacModeControl(MODE_AUTO);
					
					// Recover fan_speed and setpoint (when switching to fan_only they are "lost")
					SetFanSpeedControl(climate_mode_fan_speed);
					SetTemperatureSetpointControl(climate_mode_setpoint);	
						
					sendData(control_command, sizeof(control_command));
                    break;
					
                case CLIMATE_MODE_HEAT:	
					SetPowerControl(true);
					SetHvacModeControl(MODE_HEAT);
					
					// Recover fan_speed and setpoint (when switching to fan_only they are "lost")
					SetFanSpeedControl(climate_mode_fan_speed);
					SetTemperatureSetpointControl(climate_mode_setpoint);	
					
					sendData(control_command, sizeof(control_command));
                    break;
					
                case CLIMATE_MODE_DRY:		
					SetPowerControl(true);
					SetHvacModeControl(MODE_DRY);
					
					// Recover fan_speed and setpoint (when switching to fan_only they are "lost")
					SetFanSpeedControl(climate_mode_fan_speed);
					SetTemperatureSetpointControl(climate_mode_setpoint);	
										
					sendData(control_command, sizeof(control_command));					
                    break;
					
                case CLIMATE_MODE_FAN_ONLY:				
					SetPowerControl(true);
					SetHvacModeControl(MODE_FAN);				
					
					// Recover fan_speed and setpoint (fan_only values are "special")
					SetFanSpeedControl(fan_mode_fan_speed);
					SetTemperatureSetpointControl(fan_mode_setpoint);	
					
					sendData(control_command, sizeof(control_command));
                    break;

                case CLIMATE_MODE_COOL:
					SetPowerControl(true);
					SetHvacModeControl(MODE_COOL);
					
					// Recover fan_speed and setpoint (when switching to fan_only they are "lost")
					SetFanSpeedControl(climate_mode_fan_speed);
					SetTemperatureSetpointControl(climate_mode_setpoint);
					
					sendData(control_command, sizeof(control_command));
                    break;
            }
			}
            // Publish updated state
            mode = new_mode;
            this->publish_state();
		}
		
		        //Set fan speed
        if (call.get_fan_mode().has_value()) {
            switch(call.get_fan_mode().value()) {
                case CLIMATE_FAN_LOW:
					SetFanSpeedControl(FAN_LOW);
                    break;
                case CLIMATE_FAN_MIDDLE:
					SetFanSpeedControl(FAN_MID);
                    break;
                case CLIMATE_FAN_MEDIUM:
					SetFanSpeedControl(FAN_MID);
                    break;
                case CLIMATE_FAN_HIGH:
					SetFanSpeedControl(FAN_HIGH);
                    break;
                case CLIMATE_FAN_AUTO:
                    SetFanSpeedControl(FAN_AUTO);
                    break;
			}
			sendData(control_command, sizeof(control_command)); 
		}

        //Set swing mode
        if (call.get_swing_mode().has_value()){
            switch(call.get_swing_mode().value()) {
                case CLIMATE_SWING_OFF:
					// When not auto we decide to set it to the center
					SetHorizontalSwingControl(HORIZONTAL_SWING_CENTER);
					// When not auto we decide to set it to the center
					SetVerticalSwingControl(VERTICAL_SWING_CENTER);
                    break;
                case CLIMATE_SWING_VERTICAL:
					// When not auto we decide to set it to the center
                    SetHorizontalSwingControl(HORIZONTAL_SWING_CENTER);
					SetVerticalSwingControl(VERTICAL_SWING_AUTO);
                    break;
                case CLIMATE_SWING_HORIZONTAL:
                    SetHorizontalSwingControl(HORIZONTAL_SWING_AUTO);
					// When not auto we decide to set it to the center
					SetVerticalSwingControl(VERTICAL_SWING_CENTER);
                    break;
                case CLIMATE_SWING_BOTH:
                    SetHorizontalSwingControl(HORIZONTAL_SWING_AUTO);
					SetVerticalSwingControl(VERTICAL_SWING_AUTO);
                    break;
			}
			sendData(control_command, sizeof(control_command)); 
        }
		
		
		if (call.get_target_temperature().has_value()) {
		    float temp = *call.get_target_temperature();
			ESP_LOGD("Control", "*call.get_target_temperature() = %f", temp);
			control_command[SET_POINT_OFFSET] = (unsigned int) temp - 16;
			sendData(control_command, sizeof(control_command));			
			target_temperature = temp;
            this->publish_state();
		}
		
		
   }


    void sendData(byte * message, byte size) {
        byte crc_offset = CRC_OFFSET(message);
        byte crc = getChecksum(message, size);
        word crc_16 = crc16(0, &(message[2]), crc_offset-2);
        
        // Updates the crc
        message[crc_offset] = crc;
        message[crc_offset+1] = (crc_16>>8)&0xFF;
        message[crc_offset+2] = crc_16&0xFF;

        Serial.write(message, size); delay(1000);Serial.write(message, size);
        auto raw = getHex(message, size);
        ESP_LOGD("Haier", "Message sent: %s  - CRC: %X - CRC16: %X", raw.c_str(), crc, crc_16);

    }

    String getHex(byte * message, byte size) {


        String raw;

        for (int i=0; i < size; i++){
			raw += " " + String(message[i]);

        }
        raw.toUpperCase();

        return raw;


    }

    byte getChecksum(const byte * message, size_t size) {
		byte position = CRC_OFFSET(message);
        byte crc = 0;
        
        if (size < ( position)) {
        	ESP_LOGE("Control", "frame format error (size = %d vs length = %d)", size, message[2]);
        	return 0;
        }

        for (int i = 2; i < position; i++)
            crc += message[i];

        return crc;
    }


    unsigned crc16(unsigned crc, unsigned char *buf, size_t len)
    { 
        while (len--) {
            crc ^= *buf++;
            crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
            crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
            crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
            crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
            crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
            crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
            crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
            crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1;
        }
        return crc;
    }


};


#endif //HAIER_ESP_HAIER_H
1 Like

So this one should work for me too?

I can skip this below?

I’ve modified Haierv2.h in order to eliminate deprecated warnings and I had your same problem.
For me solution has been to delete

traits.set_supports_action(true);

Never mind it’s working thanks.

I have connected Wemos using you code. I can set modes, temperature etc, but hassio always shows climate entity as unavailableBez tytułu

I have tried to upgrade esphome on hassio, now i cant add wemos as climate device:

Traceback (most recent call last):
File “/usr/src/homeassistant/homeassistant/components/esphome/init.py”, line 214, in on_login
entity_infos, services = await cli.list_entities_services()
File “/usr/local/lib/python3.8/site-packages/aioesphomeapi/client.py”, line 137, in list_entities_services
entities.append(cls(**kwargs))
File “”, line 9, in init
self.supported_modes = __attr_converter_supported_modes(supported_modes)
File “/usr/local/lib/python3.8/site-packages/aioesphomeapi/model.py”, line 245, in _convert_climate_modes
return [ClimateMode(val) for val in value]
File “/usr/local/lib/python3.8/site-packages/aioesphomeapi/model.py”, line 245, in
return [ClimateMode(val) for val in value]
File “/usr/local/lib/python3.8/enum.py”, line 339, in call
return cls.new(cls, value)
File “/usr/local/lib/python3.8/enum.py”, line 662, in new
raise ve_exc
ValueError: 6 is not a valid ClimateMode

My device is model AS25S2SF2FA year 2021.
My yaml code is:

esphome:
  name: clima-studio
  platform: ESP8266
  board:   board: d1_mini
  includes:
    - Haierv3.h #my code
    
# Enable logging
logger:
  level: DEBUG
  baud_rate: 0 #Important. You can't use serial port
# Enable Home Assistant API
api:

ota:
  password: "8b77208d0177e64ea90bd3a1ae555326"

wifi:
  networks:  !include wifi_network.yaml  

    
  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Clima-Studio Fallback Hotspot"
    password: "IUMKWgrC3oid"

captive_portal:

climate:
  - platform: custom
    lambda: |-
      auto haier = new Haier();
      App.register_component(haier);
      return {haier};
    climates:
      - name: "Clima Studio"

The difference from the original version (MiguelAngelLV) and my version (derived by the albetaCOM v2 version: [GitHub - albetaCOM/esp-haier: ESP8266 code to connect to Haier Air Conditioner ((firmware version R_1
is the firmware of the Haier Conditioner.

What is your version of esphome?

Copyright © 2019-2021 ESPHome | Made with Materialize

v2021.8.0

Hi, Does anyone is using Alexa or Google assistant to control the ESP Haier? My problem is that when I turn on with “Alexa turn on ac” or “OK google, turn on ac” Its always turning on in heat at 25°c no matter how was turned off before. Is there a way to change this defaul behavior to for example Heat/Cool 23°c?

Assuming you are using Haierv2.h file…

I had the same behavior with Alexa. Solution is available in my Haierv3.h file (look here: ESP Haier: Haier Air Conditioner + ESP Home + Wemos D1 mini - #133 by CarloPinasco)

At row 612 you can see what I’ve changed from the Haierv2.h file.