I have the original ESP32-for-Haier module on my AC, I haven’t yet tried connecting any other “homemade” versions. I can connect a logic analyzer and provide logs if it’ll help in finding out how the original module communicates with the AC.
I don’t know what is “original ESP32-for-Haier module”. I only know the kzw-w001 and kzw-w002
This project is for a homemade replacement of kzw-w001 or 2. I don’t know if it works with others.
Hello everyone, I also own a Tundra Plus unit with the ESP32-for-haier module.
Maybe it is not possible to communicate because the tx and the rx are shifted to 5V?
Unfortunately I don’t have an oscilloscope.
Greetings.
Scroll up, there’s a new module they’re shipping with recent AC models. I have a logic analyzer and I’ll try to see what that new module does.
I haven’t had time to do an analysis with the AC connected, but the ESP32-for-Haier itself provides some valuable info. The TXD0 serves as a debug port at 115200, whereas MCU_TX communicates with the AC at 9600.
Here’s a truncated debug port boot log:
Jun 8 2016 00:22:57
rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:600
load:0x40078000,len:9076
load:0x40080400,len:5168
entry 0x40080648
;+ښj%(536) cpu_start: cpu freq: 80
I (536) cpu_start: Pro cpu up.
I (536) cpu_start: Application information:
I (537) cpu_start: Project name: esp-idf
I (542) cpu_start: App version: 1f794c834
I (547) cpu_start: Compile time: Apr 18 2021 20:49:15
I (553) cpu_start: ELF file SHA256: aaa6972fd7d3769c...
I (559) cpu_start: ESP-IDF: v3.3.5
I (564) cpu_start: Single core mode
I (568) heap_init: Initializing. RAM available for dynamic allocation:
I (575) heap_init: At 3FFAFF10 len 000000F0 (0 KiB): DRAM
I (581) heap_init: At 3FFB6388 len 00001C78 (7 KiB): DRAM
I (587) heap_init: At 3FFB9A20 len 00004108 (16 KiB): DRAM
I (594) heap_init: At 3FFBDB5C len 00000004 (0 KiB): DRAM
I (600) heap_init: At 3FFCCB28 len 000134D8 (77 KiB): DRAM
I (606) heap_init: At 3FFE0440 len 0001FBC0 (126 KiB): D/IRAM
I (612) heap_init: At 40078000 len 00008000 (32 KiB): IRAM
I (618) heap_init: At 4009E118 len 00001EE8 (7 KiB): IRAM
I (624) cpu_start: Pro cpu start user code
j%(643) cpu_start: Starting scheduler on PRO CPU.
app_main --- APPLICATION START ---
RBJwifi driver task: 3ffcfa20, prio:23, stack:3584, core=0
I (679) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
I (679) system_api: Base MAC address is not set, read default base MAC address from BLK0 gf EFUSE
I (689) wifi:wifi firmware version: dc30037
I (689) wifi:config NVS flash: disabled
I (699) wifi:config nano formating: disabled
I (699) wifi:Init data frame dynamic rx buffer num: 32
I (709) wifi:Init management frame dynamic rx buffer num: 32
I (709) wifi:Init management short buffer num: 32
I (719) wifi:Init dynamic tx buffer num: 32
I (719) wifi:Init static rx buffer size: 1600
I (719) wifi:Init static rx buffer num: 2
I (729) wifi:Init dynamic rx buffer num: 32
I (729) wifi_init: rx ba win: 4
I (729) wifi_init: tcpip mbox: 32
I (739) wifi_init: udp mbox: 6
I (739) wifi_init: tcp mbox: 6
I (749) wifi_init: tcp tx win: 5744
I (749) wifi_init: tcp rx win: 5744
I (749) wifi_init: tcp mss: 1436
I (759) wifi_init: WiFi IRAM OP enabled
I (759) wifi_init: WiFi RX IRAM OP enabled
I (769) wifi_init: LWIP IRAM OP enabled
I (779) uart: queue free spaces: 20
I (779) epp_parser_map: epp_parser_state.downloaded = 1
I (779) epp_parser_map: Mapped partition to data memory address 0X3f400000
I (789) epp_parser_map: free heap = 196592
I (789) epp_parser_map: Mapped partition to data memory address 0x3f448000
I (799) epp_parser_map: map partition -> free heap = 196568
1mE (809) uplus_sys_res_area_get_size:
E (809) uplus_sys_res_area_read: offset = 0, len = 256
E (819) uplus_sys_res_area_write: offset = 0, len = 256
I (819) uplus_sys_res_area_write: 0x3ffb4e18 00 00 00 00 73 6f 68 75 00 00 00 00 00 00 00 00 |....sohu........|
I (839) uplus_sys_res_area_write: 0x3ffb4e28 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
I (849) uplus_sys_res_area_write: 0x3ffb4e38 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
I (859) uplus_sys_res_area_write: 0x3ffb4e48 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
I (869) uplus_sys_res_area_write: 0x3ffb4e58 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
I (879) uplus_sys_res_area_write: 0x3ffb4e68 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
I (889) uplus_sys_res_area_write: 0x3ffb4e78 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
I (899) uplus_sys_res_area_write: 0x3ffb4e88 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
I (909) uplus_sys_res_area_write: 0x3ffb4e98 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
I (919) uplus_sys_res_area_write: 0x3ffb4ea8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
I (929) uplus_sys_res_area_write: 0x3ffb4eb8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
I (949) uplus_sys_res_area_write: 0x3ffb4ec8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
I (959) uplus_sys_res_area_write: 0x3ffb4ed8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
I (969) uplus_sys_res_area_write: 0x3ffb4ee8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
I (979) uplus_sys_res_area_write: 0x3ffb4ef8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
I (989) uplus_sys_res_area_write: 0x3ffb4f08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
[347]: uplus_epp_init - start serial connection
uplug_conf_epp_data_get called
[354]: uplug_epp_module_init - called
E (1009) uplus_sys_res_area_write: offset = 16, len = 8
I (1019) uplus_sys_res_area_write: 0x3ffb4e28 00 00 00 00 00 00 00 00 |........|
E (1029) uplus_sys_res_area_write: offset = 0, len = 8
I (1029) uplus_sys_res_area_write: 0x3ffb4e18 02 00 00 00 73 6f 68 75 |....sohu|
[UHomeOS][I][391]: dev_main is 255 dev_minor is 255 dev_dedicated is 0000000000000
]}}͕}ձсcalled
[UHomeOS][LOG][422]: uplugSDK e++ init ok
[422]: uplus_epp_access_register - called
[422]: uplus_epp_access_register - params check pass
[425]: uplug_epp_access_init - called - access method 0
[430]: uplug_epp_access_init - init serial access struct
[435]: uplug_epp_access_init - call init method
+ښj%(1109) CDM_Manager__Initialize: discovery configuration : key = eepromName, value = 00000000
I (1119) CDM_Manager__Initialize: discovery configuration : key = acuVersion, value = 06.26.00
I (1119) CDM_Manager__Initialize: discovery configuration : key = serialNumber, value = 999999992048011665
I (1129) CDM_Manager__Initialize: discovery configuration : key = fwVersion, value = 4.0.0
W (1139) uplus_sys_serial_open: esp_vfs_dev_uart_use_driver
I (1149) CDM_Manager__Initialize: discovery configuration : key = eepromName, value = 00000000
I (1159) CDM_Manager__Initialize: discovery configuration : key = lang, value = it-IT
I (1169) CDM_Manager__Initialize: discovery configuration : key = chipset, value = ESP32D0WDQ5
I (1169) CDM_Manager__Initialize: discovery configuration : key = acuVersion, value = 06.26.00
I (1179) CDM_Manager__Initialize: discovery configuration : key = eppParserSet, value = 1
app_main --- APPLICATION INIT COMPLETED ---
Firmware version : IOTFW_EPP_04_00
----------------------- READ CERTIFICATE DATA
*********************** host-address
a30f6tqw0oh1x0-ats.iot.eu-west-1.amazonaws.com
*********************** host-port
8883
*********************** thing-name
c4-dd-57-45-73-74
*********************** serial-number
999999992048011665
I (1229) LowPower__SleepHandler: Init low power state machine
;[UHomeOS][D][5131]: tx serial e++ data
ff ff 0a 00 00 00 00 00 00 61 00 07 72
[UHomeOS][I][5132]: [UART] tx [cmd 0x61 len = 10, 13] ret 13
[UHomeOS][D][5441]: tx serial e++ data
ff ff 0a 00 00 00 00 00 00 61 00 07 72
[UHomeOS][I][5442]: [UART] tx [cmd 0x61 len = 10, 13] ret 13
[UHomeOS][D][5751]: tx serial e++ data
ff ff 0a 00 00 00 00 00 00 61 00 07 72
[UHomeOS][I][5752]: [UART] tx [cmd 0x61 len = 10, 13] ret 13
;ꫫ=Mum1=um061]: e++ comm time: 930
ꫫ=Mum]um161]: get ver timeout
[UHomeOS][I][6162]: dev_main is 255 dev_minor is 255 dev_dedicated is 0000000000000
_ꫫ=Mum%um191]: e++ state from ver to typeid
_[UHomeOS][D][6271]: tx serial e++ data
ff ff 08 00 00 00 00 00 00 70 78
[UHomeOS][I][6272]: [UART] tx [cmd 0x70 len = 8, 11] ret 11
[UHomeOS][D][6581]: tx serial e++ data
ff ff 08 00 00 00 00 00 00 70 78
[UHomeOS][I][6582]: [UART] tx [cmd 0x70 len = 8, 11] ret 11
[UHomeOS][D][6891]: tx serial e++ data
ff ff 08 00 00 00 00 00 00 70 78
[UHomeOS][I][6892]: [UART] tx [cmd 0x70 len = 8, 11] ret 11
ꫫ=Mum1=um201]: e++ comm time: 930
ꫫ=Mum]um721]: get typeid timeout
[UHomeOS][I][7722]: dev_main is 255 dev_minor is 255 dev_dedicated is 0000000000000
ꫫ=Mum%um751]: e++ state from typeid to status
[UHomeOS][D][7891]: tx serial e++ data
ff ff 0a 00 00 00 00 00 00 01 4d 01 59
[UHomeOS][I][7892]: [UART] tx [cmd 0x01 len = 10, 13] ret 13
[UHomeOS][D][8201]: tx serial e++ data
ff ff 0a 00 00 00 00 00 00 01 4d 01 59
[UHomeOS][I][8202]: [UART] tx [cmd 0x01 len = 10, 13] ret 13
[UHomeOS][D][8512]: tx serial e++ data
ff ff 0a 00 00 00 00 00 00 01 4d 01 59
[UHomeOS][I][8512]: [UART] tx [cmd 0x01 len = 10, 13] ret 13
[UHomeOS][D][8821]: tx serial e++ data
ff ff 0a 00 00 00 00 00 00 01 4d 01 59
[UHomeOS][I][8822]: [UART] tx [cmd 0x01 len = 10, 13] ret 13
?[UHomeOS][D][9131]: tx serial e++ data
ff ff 0a 00 00 00 00 00 00 01 4d 01 59
[UHomeOS][I][9132]: [UART] tx [cmd 0x01 len = 10, 13] ret 13
[UHomeOS][D][9441]: tx serial e++ data
ff ff 0a 00 00 00 00 00 00 01 4d 01 59
[UHomeOS][I][9442]: [UART] tx [cmd 0x01 len = 10, 13] ret 13
[UHomeOS][D][9751]: tx serial e++ data
ff ff 0a 00 00 00 00 00 00 01 4d 01 59
[UHomeOS][I][9752]: [UART] tx [cmd 0x01 len = 10, 13] ret 13
_[UHomeOS][D][10061]: tx serial e++ data
ff ff 0a 00 00 00 00 00 00 01 4d 01 59
[UHomeOS][I][10062]: [UART] tx [cmd 0x01 len = 10, 13] ret 13
;[UHomeOS][D][10371]: tx serial e++ data
ff ff 0a 00 00 00 00 00 00 01 4d 01 59
[UHomeOS][I][10372]: [UART] tx [cmd 0x01 len = 10, 13] ret 13
ꫫ=Mum1=um0681]: e++ comm time: 2790
ꫫ=Mum]um0841]: get status timeout
[UHomeOS][I][10842]: dev_main is 255 dev_minor is 255 dev_dedicated is 0000000000000
[UHomeOS][D][10891]: tx serial e++ data
ff ff 0a 00 00 00 00 00 00 61 00 07 72
[UHomeOS][I][10892]: [UART] tx [cmd 0x61 len = 10, 13] ret 13
uplus_dev_status called 0
ꫫ=Mum]um1201]: serial device closed
Sometime next week I’ll do a dump while connected to the AC. If anyone’s interested in raw dumps (Saleae Logic or Pulseview), just ask.
I may be very wrong here, but doesn’t the usb connect with a simple uart with the aircon? It could work with the midea way
Bad thing is on my parents house the Haier doesn’t have a usb slot, so I’ll have to check the main board for pins to connect
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
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
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.
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
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
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 unavailable
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