dhewg / esphome-miot

ESPHome components for MIoT devices
Other
16 stars 8 forks source link

Mi Air Purifier 3C (zhimi.airp.mb4a) #1

Closed dhewg closed 4 months ago

dhewg commented 5 months ago

Blind attempt to add support for Mi Air Purifier 3C (zhimi.airp.mb4a): zhimi.airp.mb4a.yaml.txt

I can't tell if this works, but please try and report back (with logs if possible): cc @daniel-dona @gfduszynski

gfduszynski commented 5 months ago

I'm planning to give this a shot during the weekend, I need to familiarize myself with the details of the process.

gfduszynski commented 4 months ago

Here are my findings:

Overall very usable, I'm only really missing favorite speed.

dhewg commented 4 months ago

Huh, at first glance display brightness and favorite speed is set up correctly. Can you switch the logger level from DEBUG to VERBOSE and post some logs?

gfduszynski commented 4 months ago

Sure, I need to figure out how to do this trough mqtt. I've reassembled the unit.

gfduszynski commented 4 months ago

Here is a fragment where esp queries stm for various things.

[18:12:40][D][miot:125]: Queuing MCU command 'get_properties 2 1 2 2 2 4 3 4 4 1 4 3 6 1 7 2 8 1 9 1 9 3'
[18:12:40][V][miot:091]: Received MCU message 'get_down'
[18:12:40][V][miot:171]: Sending reply 'down get_properties 2 1 2 2 2 4 3 4 4 1 4 3 6 1 7 2 8 1 9 1 9 3' to MCU
[18:12:40][V][miot:091]: Received MCU message 'result 2 1 0 false 2 2 0 "null" 2 4 0 1 3 4 0 1 4 1 0 100 4 3 0 0 6 1 0 true 7 2 0 3 8 1 0 false 9 1 0 0 9 3 0 1700'
[18:12:40][V][miot.switch:012]: MCU reported switch 2:1 is: OFF
[18:12:40][V][miot.text_sensor:011]: MCU reported text sensor 2:2 is: null
[18:12:40][V][text_sensor:013]: 'Device Fault': Received new state null
[18:12:40][D][text_sensor:064]: 'Device Fault': Sending state 'null'
[18:12:40][V][mqtt:474]: Publish(topic='purifier/sensor/device_fault/state' payload='null' retain=1)
[18:12:40][V][miot.select:011]: MCU reported select 2:4 is: 1
[18:12:40][D][select:015]: 'Mode': Sending state Sleep (index 1)
[18:12:40][V][mqtt:474]: Publish(topic='purifier/select/mode/state' payload='Sleep' retain=1)
[18:12:40][V][miot.sensor:011]: MCU reported sensor 3:4 is: 1.000000
[18:12:40][V][sensor:043]: 'PM2.5 Density': Received new state 1.000000
[18:12:40][D][sensor:094]: 'PM2.5 Density': Sending state 1.00000 µg/m³ with 0 decimals of accuracy
[18:12:40][V][mqtt:474]: Publish(topic='purifier/sensor/pm2_5_density/state' payload='1' retain=1)
[18:12:40][V][miot.sensor:011]: MCU reported sensor 4:1 is: 100.000000
[18:12:40][V][sensor:043]: 'Filter Life Level': Received new state 100.000000
[18:12:40][D][sensor:094]: 'Filter Life Level': Sending state 100.00000 % with 0 decimals of accuracy
[18:12:40][V][mqtt:474]: Publish(topic='purifier/sensor/filter_life_level/state' payload='100' retain=1)
[18:12:40][V][miot.sensor:011]: MCU reported sensor 4:3 is: 0.000000
[18:12:40][V][sensor:043]: 'Filter Used Time': Received new state 0.000000
[18:12:40][D][sensor:094]: 'Filter Used Time': Sending state 0.00000 h with 0 decimals of accuracy
[18:12:40][V][mqtt:474]: Publish(topic='purifier/sensor/filter_used_time/state' payload='0' retain=1)
[18:12:40][V][miot.switch:012]: MCU reported switch 6:1 is: ON
[18:12:40][V][miot.number:011]: MCU reported number 7:2 is: 3.000000
[18:12:40][D][number:012]: 'Display Brightness': Sending state 3.000000
[18:12:40][V][mqtt:474]: Publish(topic='purifier/number/display_brightness/state' payload='3.000000' retain=1)
[18:12:40][V][miot.switch:012]: MCU reported switch 8:1 is: OFF
[18:12:40][V][miot.sensor:011]: MCU reported sensor 9:1 is: 0.000000
[18:12:40][V][sensor:043]: 'Motor Speed': Received new state 0.000000
[18:12:40][D][sensor:094]: 'Motor Speed': Sending state 0.00000 rpm with 0 decimals of accuracy
[18:12:40][V][mqtt:474]: Publish(topic='purifier/sensor/motor_speed/state' payload='0' retain=1)
[18:12:40][V][miot.number:011]: MCU reported number 9:3 is: 1700.000000
[18:12:40][D][number:012]: 'Favorite Speed': Sending state 1700.000000
[18:12:40][V][mqtt:474]: Publish(topic='purifier/number/favorite_speed/state' payload='1700.000000' retain=1)
[18:12:40][V][miot:171]: Sending reply 'ok' to MCU
[18:12:40][V][miot:091]: Received MCU message 'get_down'
[18:12:40][V][miot:171]: Sending reply 'down none' to MCU
[18:12:40][V][miot:091]: Received MCU message 'error "method not found" -5000'
[18:12:40][E][miot:284]: MCU command error -5000: method not found
[18:12:40][V][miot:171]: Sending reply 'ok' to MCU
[18:12:40][W][component:214]: Component miot took a long time for an operation (0.39 s).
[18:12:41][W][component:215]: Components should block for at most 20-30ms.
[18:12:41][V][miot:091]: Received MCU message 'get_down'
[18:12:41][V][miot:171]: Sending reply 'down none' to MCU
[18:12:41][V][miot:091]: Received MCU message 'get_down'
[18:12:41][V][miot:171]: Sending reply 'down none' to MCU
[18:12:41][V][miot:091]: Received MCU message 'mac'
[18:12:41][W][miot:291]: Unknown command 'mac'
[18:12:41][V][miot:171]: Sending reply 'ok' to MCU
[18:12:41][V][miot:091]: Received MCU message 'get_down'
[18:12:41][V][miot:171]: Sending reply 'down none' to MCU
[18:12:41][V][miot:091]: Received MCU message 'get_down'
[18:12:41][V][miot:171]: Sending reply 'down none' to MCU

Here is where I try to set the fav speed


[18:15:36][V][miot:171]: Sending reply 'down none' to MCU
[18:15:36][D][number:054]: 'Favorite Speed' - Setting number value
[18:15:36][D][number:113]:   New number value: 1000.000000
[18:15:36][V][miot.number:017]: Setting number 9:3 1000.000000
[18:15:36][D][miot:125]: Queuing MCU command 'set_properties 9 3 1000.000000'
[18:15:36][D][number:012]: 'Favorite Speed': Sending state 1000.000000
[18:15:36][V][mqtt:474]: Publish(topic='purifier/number/favorite_speed/state' payload='1000.000000' retain=1)
[18:15:36][W][component:214]: Component api took a long time for an operation (0.06 s).
[18:15:36][W][component:215]: Components should block for at most 20-30ms.
[18:15:36][V][miot:091]: Received MCU message 'get_down'
[18:15:36][V][miot:171]: Sending reply 'down set_properties 9 3 1000.000000' to MCU
[18:15:36][V][miot:091]: Received MCU message 'result 9 3 -4003'
[18:15:36][E][miot:218]: Result error on property 9:3: -4003
[18:15:36][V][miot:171]: Sending reply 'ok' to MCU
[18:15:37][V][miot:091]: Received MCU message 'get_down'
[18:15:37][V][miot:171]: Sending reply 'down none' to MCU
[18:15:37][V][miot:091]: Received MCU message 'get_down'
[18:15:37][V][miot:171]: Sending reply 'down none' to MCU
[18:15:37][V][miot:091]: Received MCU message 'mac'
[18:15:37][W][miot:291]: Unknown command 'mac'
[18:15:37][V][miot:171]: Sending reply 'ok' to MCU
[18:15:37][V][miot:091]: Received MCU message 'get_down'
[18:15:37][V][miot:171]: Sending reply 'down none' to MCU
gfduszynski commented 4 months ago

Interestingly on startup there is [18:21:10][W][miot:183]: Received property value without component: 7 1 true Which does not seem to appear later

gfduszynski commented 4 months ago

Here is one for the brightness:


[18:25:47][D][number:054]: 'Display Brightness' - Setting number value
[18:25:47][D][number:113]:   New number value: 7.000000
[18:25:47][V][miot.number:017]: Setting number 7:2 7.000000
[18:25:47][D][miot:125]: Queuing MCU command 'set_properties 7 2 7.000000'
[18:25:47][D][number:012]: 'Display Brightness': Sending state 7.000000
[18:25:47][V][miot:091]: Received MCU message 'get_down'
[18:25:47][V][miot:171]: Sending reply 'down set_properties 7 2 7.000000' to MCU
[18:25:47][V][miot:091]: Received MCU message 'result 7 2 -4003'
[18:25:47][E][miot:218]: Result error on property 7:2: -4003
[18:25:47][V][miot:171]: Sending reply 'ok' to MCU
[18:25:47][V][miot:091]: Received MCU message 'get_down'
[18:25:47][V][miot:171]: Sending reply 'down none' to MCU
dhewg commented 4 months ago

Device Fault is null as that's the mcu answer, as you can see in the logs. You can try adding

    filters:
      - substitute:
        - "null -> No Faults"

to the text sensor to make it more user/gui friendly. An opened door might just not show up there, e.g. my 4lite has serious stuff like motor fault in there ;)

The brightness/fav speed is weird, the values are sent as e.g. 7.000000, but it's supposed to be just 7. I'll take a look, but my first guess is that's it's how mtqq sends values. Does it work with api:?

gfduszynski commented 4 months ago

I may be mistaken, but I'm testing the commands from HASS, therefore it should be using api, right ? Btw, that mqtt stuff that I said earlier was because of my ignorance, I thought that was the correct way to obtain logs, but figured it out and removed mqtt: from config there after

daniel-dona commented 4 months ago

I didn't have time to test this module, but here is the component I originally adapted. All functionalities are working as expected... just in case It helps debug...

Some of the code is there just because it was used while testing, specially the dirty part around these variables:

int last_41, last_21, last_24, last_34, last_61, last_81, last_72, last_93, last_43, last_91;

https://gist.github.com/daniel-dona/bea0773e3ec4147cd0a58150f055318d

gfduszynski commented 4 months ago

Filter used time went up to 1h. I guess it works then, weird that it reset itself.

daniel-dona commented 4 months ago

Filter used time went up to 1h. I guess it works then, weird that it reset itself.

One of the MIOT defined actions is filter reset, check this: imagen

https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:air-purifier:0000A007:zhimi-mb4:2

gfduszynski commented 4 months ago

Yes, but I did not trigger this action on purpose (as far as I am aware).

dhewg commented 4 months ago

I checked my device, and indeed it also get values like 7.000000. But compared to the 3C it accepts that value. I guess the fw on the 3C refuses the precision, and I pushed a possible fix to the number branch here. Please test that by replacing @main with @number at the top of the yaml file, does it work then?

dhewg commented 4 months ago

Yes, but I did not trigger this action on purpose (as far as I am aware).

That's unexpected. The filter life was kept as I replaced the vendor fw with esphome, I only tested a reset afterwards, which worked too.

daniel-dona commented 4 months ago

Yes, but I did not trigger this action on purpose (as far as I am aware).

The other way to reset it was something like pressing the buttons for some time, maybe that was the case (?)

Mine only reset by calling the action manually, I'm not sure...

gfduszynski commented 4 months ago

Well, because I've screwed up I had to ask my friend to solder in a new ESP32 (which I've programed beforehand) there is a good chance that this has something to do with this depending on where this info is stored.

In any case @number works like a charm (both fan speed and backlight)

[20:31:18][D][number:054]: 'Favorite Speed' - Setting number value
[20:31:18][D][number:113]:   New number value: 1000.000000
[20:31:18][V][miot.number:017]: Setting number 9:3 1000.000000
[20:31:18][D][miot:125]: Queuing MCU command 'set_properties 9 3 1000'
[20:31:18][D][number:012]: 'Favorite Speed': Sending state 1000.000000
[20:31:18][V][miot:091]: Received MCU message 'get_down'
[20:31:18][V][miot:171]: Sending reply 'down set_properties 9 3 1000' to MCU
[20:31:18][V][miot:091]: Received MCU message 'result 9 3 0'
[20:31:18][V][miot:171]: Sending reply 'ok' to MCU
[20:31:18][V][miot:091]: Received MCU message 'properties_changed 9 3 1000 2 4 2'
[20:31:18][V][miot.number:011]: MCU reported number 9:3 is: 1000.000000
[20:31:18][D][number:012]: 'Favorite Speed': Sending state 1000.000000
[20:31:18][V][miot.select:011]: MCU reported select 2:4 is: 2
[20:31:18][D][select:015]: 'Mode': Sending state Favorite (index 2)
dhewg commented 4 months ago

Nice, thanks for the confirmation! Fix pushed to @main, so please switch back to that branch as I deleted @number now :)

gfduszynski commented 4 months ago

In the mean time I've tested the "Reset filter" action:

[20:41:20][D][button:010]: 'Reset Filter Life' Pressed.
[20:41:20][D][miot:125]: Queuing MCU command 'action 4 1 3'
[20:41:20][V][miot:091]: Received MCU message 'get_down'
[20:41:20][V][miot:171]: Sending reply 'down action 4 1 3' to MCU
[20:41:20][V][miot:091]: Received MCU message 'result -4006'
[20:41:20][V][miot:171]: Sending reply 'ok' to MCU

HASS keeps showing "2h" and when the periodic check occurs this is the fragment for the filter life:

[20:42:29][V][miot.sensor:011]: MCU reported sensor 4:3 is: 2.000000
[20:42:29][V][sensor:043]: 'Filter Used Time': Received new state 2.000000
[20:42:29][D][sensor:094]: 'Filter Used Time': Sending state 2.00000 h with 0 decimals of accuracy

Btw. Thank you guys for your work, you are amazing :beers:

daniel-dona commented 4 months ago

In the mean time I've tested the "Reset filter" action:

[20:41:20][D][button:010]: 'Reset Filter Life' Pressed.
[20:41:20][D][miot:125]: Queuing MCU command 'action 4 1 3'
[20:41:20][V][miot:091]: Received MCU message 'get_down'
[20:41:20][V][miot:171]: Sending reply 'down action 4 1 3' to MCU
[20:41:20][V][miot:091]: Received MCU message 'result -4006'
[20:41:20][V][miot:171]: Sending reply 'ok' to MCU

HASS keeps showing "2h" and when the periodic check occurs this is the fragment for the filter life:

[20:42:29][V][miot.sensor:011]: MCU reported sensor 4:3 is: 2.000000
[20:42:29][V][sensor:043]: 'Filter Used Time': Received new state 2.000000
[20:42:29][D][sensor:094]: 'Filter Used Time': Sending state 2.00000 h with 0 decimals of accuracy

Btw. Thank you guys for your work, you are amazing 🍻

Try using a different value in the action, 100 or something like that worked for me...

action 4 1 100

Not even sure what the last parameter means, is not clearly documented in the spec

gfduszynski commented 4 months ago

Unfortunately it did not work

[20:51:49][D][button:010]: 'Reset Filter Life' Pressed.
[20:51:49][D][miot:125]: Queuing MCU command 'action 4 1 100'
[20:51:49][V][miot:091]: Received MCU message 'get_down'
[20:51:49][V][miot:171]: Sending reply 'down action 4 1 100' to MCU
[20:51:49][V][miot:091]: Received MCU message 'result -4006'
[20:51:49][V][miot:171]: Sending reply 'ok' to MCU
[20:51:49][V][miot:091]: Received MCU message 'net'
[20:51:49][V][miot:171]: Sending reply 'cloud' to MCU
dhewg commented 4 months ago

The 3 is supposed to be the PIID, see https://github.com/blakadder/miot?tab=readme-ov-file#action And PIID 3 here is filter-used-time, so to me the yaml looks in sync with the specs.

But maybe the specs are wrong. Maybe an additional value is missing, what to set the used time to. Wild guess, but does maybe miot_action_args: "3 0" work?

gfduszynski commented 4 months ago

Bingo


[20:59:23][D][button:010]: 'Reset Filter Life' Pressed.
[20:59:23][D][miot:125]: Queuing MCU command 'action 4 1 3 0'
[20:59:23][V][miot:091]: Received MCU message 'get_down'
[20:59:23][V][miot:171]: Sending reply 'down action 4 1 3 0' to MCU
[20:59:23][V][miot:091]: Received MCU message 'result 4 1 0'
[20:59:23][V][miot:171]: Sending reply 'ok' to MCU
[20:59:23][V][miot:091]: Received MCU message 'properties_changed 4 1 100 4 3 0'
[20:59:23][V][miot.sensor:011]: MCU reported sensor 4:1 is: 100.000000
[20:59:23][V][sensor:043]: 'Filter Life Level': Received new state 100.000000
[20:59:23][D][sensor:094]: 'Filter Life Level': Sending state 100.00000 % with 0 decimals of accuracy
[20:59:23][V][miot.sensor:011]: MCU reported sensor 4:3 is: 0.000000
[20:59:23][V][sensor:043]: 'Filter Used Time': Received new state 0.000000
[20:59:23][D][sensor:094]: 'Filter Used Time': Sending state 0.00000 h with 0 decimals of accuracy
dhewg commented 4 months ago

Woot, nice! Once you have a nice and complete yaml, please open a PR to add it. Or, alternatively, attach it here and I'll add it

gfduszynski commented 4 months ago

After switching back to main issue with number precision is back. I have run esphome clean ....yaml just to make sure.

[21:11:47][D][number:054]: 'Display Brightness' - Setting number value
[21:11:47][D][number:113]:   New number value: 3.000000
[21:11:47][V][miot.number:017]: Setting number 7:2 3.000000
[21:11:47][D][miot:125]: Queuing MCU command 'set_properties 7 2 3.000000'
[21:11:47][D][number:012]: 'Display Brightness': Sending state 3.000000
[21:11:47][V][miot:091]: Received MCU message 'get_down'
[21:11:47][V][miot:171]: Sending reply 'down set_properties 7 2 3.000000' to MCU
[21:11:47][V][miot:091]: Received MCU message 'result 7 2 -4003'
[21:11:47][E][miot:218]: Result error on property 7:2: -4003

It's most likely the latest because this was couple of lines before:


[21:11:46][V][miot.select:011]: MCU reported select 2:4 is: 2
[21:11:46][D][select:015]: 'Mode': Sending state Favorite (index 2)
[21:11:46][V][miot.number:011]: MCU reported number 9:3 is: 1000.000000
[21:11:46][D][number:012]: 'Favorite Speed': Sending state 1000.000000
[21:11:46][V][miot.sensor:011]: MCU reported sensor 3:4 is: 1.000000
[21:11:46][V][sensor:043]: 'PM2.5 Density': Received new state 1.000000
[21:11:46][D][sensor:094]: 'PM2.5 Density': Sending state 1.00000 µg/m³ with 0 decimals of accuracy
[21:11:46][V][miot.sensor:011]: MCU reported sensor 4:1 is: 100.000000
[21:11:46][V][sensor:043]: 'Filter Life Level': Received new state 100.000000
[21:11:46][D][sensor:094]: 'Filter Life Level': Sending state 100.00000 % with 0 decimals of accuracy
[21:11:46][V][miot.sensor:011]: MCU reported sensor 4:3 is: 0.000000
[21:11:46][V][sensor:043]: 'Filter Used Time': Received new state 0.000000
[21:11:46][D][sensor:094]: 'Filter Used Time': Sending state 0.00000 h with 0 decimals of accuracy
[21:11:46][V][miot.switch:012]: MCU reported switch 8:1 is: OFF
[21:11:46][V][miot.switch:012]: MCU reported switch 6:1 is: OFF
[21:11:46][W][miot:183]: Received property value without component: 7 1 true
[21:11:46][V][miot.number:011]: MCU reported number 7:2 is: 7.000000
[21:11:46][D][number:012]: 'Display Brightness': Sending state 7.000000
[21:11:46][V][miot:171]: Sending reply 'ok' to MCU
[21:11:46][W][component:214]: Component miot took a long time for an operation (0.13 s).
[21:11:46][W][component:215]: Components should block for at most 20-30ms.
dhewg commented 4 months ago

I guess that's due to esphome's caching. Try setting refresh: https://esphome.io/components/external_components.html#external-components-refresh

gfduszynski commented 4 months ago

https://github.com/dhewg/esphome-miot/pull/7

cristianchelu commented 4 months ago

Sorry for barging in on this issue, but I need to say a massive THANK YOU for this insight:

But maybe the specs are wrong. Maybe an additional value is missing, what to set the used time to. Wild guess, but does maybe miot_action_args: "3 0" work?

The specs aren't clear, but the action arguments have to be named (well... numbered) and you can send the arguments in whicever order.

For a more illustrative example, here I have an action for a Pet Feeder, which takes a bunch of parameters:

SIID 5 feedplanserve
Action 7 feedlistadd
    10 - feedplan-id
    6 - feedplan-hour
    7 - feedplan-min
    8 - feedplan-unit

Only calling the action in this format works:

down action 5 7 10 [id_value] 6 [hour_value] 7 [minute_value] 8 [servings_value]
down action 5 7 8 [servings_value] 10 [id_value] 7 [minute_value] 6 [hour_value] 
down action 5 7 [ other permutations of the above ]

Directly calling the action with just the argument values results either in an error or gibberish data, depending on the firmware validation, even if we keep the order from the spec;

down action 5 7 [id_value] [hour_value] [minute_value] [servings_value]
# Fails or results in gibberish data
[12:21:48][V][miot:171]: Sending reply 'down action 5 7 10 0 6 11 7 5 8 1' to MCU
[12:21:48][V][miot:091]: Received MCU message 'result 5 7 0'
[12:21:54][V][miot:171]: Sending reply 'down action 5 6' to MCU
[12:21:54][V][miot:091]: Received MCU message 'result 5 6 0 12 "0,11,5,1,255,1,255,255,255,255,2,255,255,255,255,3,255,255,255,255,4,255,255,255,255"'
# ID 0, Hour 11, Minute 05, Servings 1
# Swapped arg 6 [hour] and 7 [minute] order
[12:22:12][V][miot:171]: Sending reply 'down action 5 7 10 1 7 05 6 12 8 1' to MCU
[12:22:12][V][miot:091]: Received MCU message 'result 5 7 0'
[12:22:14][V][miot:171]: Sending reply 'down action 5 6' to MCU
[12:22:14][V][miot:091]: Received MCU message 'result 5 6 0 12 "0,11,5,1,255,1,12,5,1,255,2,255,255,255,255,3,255,255,255,255,4,255,255,255,255"'
# ID 0, Hour 11, Minute 05, Servings 1
# ID 1, Hour 12, Minute 05, Servings 1 -- still correct

Some actions work without args on some devices. For example, down action 4 1 on my zhimi.airp.mb5 still resets the time same as down action 4 1 3 0, but I guess it's better to always be explicit in argument passing.

So yeah... thanks!

dhewg commented 4 months ago

@gfduszynski I commited some changes to unify all 3 devices, let me know if I messed up ;)

gfduszynski commented 4 months ago

@dhewg Looks good to me :) There is still a mystery with [20:23:21][W][miot:183]: Received property value without component: 7 1 true I don't know if this is useful or not.

dhewg commented 4 months ago

SIID 7 is Screen, and it's a bool. Turn display on/off maybe? Try this: Go to HA's Developer tools, then Services, select <your device name>_mcu_command, at command enter set_properties 7 1 false and then watch the device while hitting Call service

gfduszynski commented 4 months ago

False turns off the screen, while True does not appear to do anything.

[20:54:57][D][miot:125]: Queuing MCU command 'set_properties 7 1 true'
[20:54:57][W][miot:183]: Received property value without component: 7 1 true
[20:55:00][D][miot:125]: Queuing MCU command 'set_properties 7 1 false'
[20:55:00][W][miot:183]: Received property value without component: 7 1 true
dhewg commented 4 months ago

Weird, '1' maybe? Or it's just to turn it off and the other brightness is able to light it up again? But that'll be weird too...

Maybe it's just some left over debug thing, it's not part of the spec anyway...

gfduszynski commented 4 months ago

Tried 1, but to no avail. After turning it off adjusting brightness restores the screen. I think you are right and It's not worth the effort.

dhewg commented 4 months ago

I've enabled the wiki here, have you taken some pics to put some basic instructions there?

gfduszynski commented 4 months ago

Unfortunately no, however what I can say is I did it probably in the worst possible way as evident by the need to replace the ESP32 :smiling_face_with_tear:

I tried to do everything in place as one of the screws for PCB is covered by a piece of plastic. Once I was sure I killed the esp (because I was lazy and didn't want disassemble the whole thing) I chosen violence and bent the whole case to gain access to the second screw. Actually worked and I didn't destroy it.

Pins are in different order than on other air purifiers tx/rx are in the middle surrounded by gnd and vcc. I'm not giving exact order because I don't want to mislead anybody. They have nice labels on the underside luckily.

Good tip in case your uart adapter cannot handle the required current is to use built in power from the device. There is a ribbon cable providing 24V to the board.

Be very careful with the PCB whenever doing anything as solder mask appears to be very fragile.

dhewg commented 4 months ago

Wow, okay, but nice that you were able to get it working again!