Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Xiaomi Purifier 4 Compact #1550

Closed
ghost opened this issue Oct 11, 2022 · 11 comments · Fixed by #1581
Closed

Xiaomi Purifier 4 Compact #1550

ghost opened this issue Oct 11, 2022 · 11 comments · Fixed by #1581

Comments

@ghost
Copy link

ghost commented Oct 11, 2022

Device information:

Additional context
'on/off/set_mode/set_led_brightness(reversed)' works with _MAPPING_VA2
'set_fan_level/favorite_level/favorite_rpm' didn't work with any that i tried
'status' doesn't work with any - when sending status command, the device beeps > wifi icon flashes several times > Error: Unable to discover the device 192.168.x.x

also this model has 'PM2.5 IR sensor' not laser like other ones, and does not provide exact pm2.5 value even in the official app


https://home.miot-spec.com/spec?type=urn%3Amiot-spec-v2%3Adevice%3Aair-purifier%3A0000A007%3Azhimi-cpa4%3A1

tested and working:
read pm2 value - get_property_by 3 4
set favorite level - raw_command set_properties '[{"value":1,"siid":9,"piid":11}]'

@ghost ghost added the new device label Oct 11, 2022
@mkohns
Copy link

mkohns commented Nov 3, 2022

Hi! I also have a Purifier 4 Compact.
I got the token via Packet Sender Tool described here.

When trying to use latest master miiocli with

poetry run miiocli -d airpurifier --model zhimi.airp.cpa4 --ip 192.168.178.176 --token mytoken info

I only receive

DEBUG:miio.miioprotocol:Got a response: Container:
data = Container:
data = b'' (total 0)
value = b'' (total 0)
offset1 = 32
offset2 = 32
length = 0
header = Container:
data = b'!1\x00 \x00\x00\x00\x00\x1f\xcc|\xb3\x00\x00\n\xc6' (total 16)
value = Container:
length = 32
unknown = 0
device_id = unhexlify('1fcc7cb3')
ts = 1970-01-01 00:45:58
offset1 = 0
offset2 = 16
length = 16
checksum = b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' (total 16)
DEBUG:miio.miioprotocol:Discovered 1fcc7cb3 with ts: 1970-01-01 00:45:58, token: b'ffffffffffffffffffffffffffffffff'
DEBUG:miio.miioprotocol:192.168.178.176:54321 >>: {'id': 1, 'method': 'miIO.info', 'params': []}
DEBUG:miio.miioprotocol:Retrying with incremented id, retries left: 3
DEBUG:miio.miioprotocol:Got a response: Container:
data = Container:
data = b'' (total 0)
value = b'' (total 0)
offset1 = 32
offset2 = 32
length = 0
header = Container:
data = b'!1\x00 \x00\x00\x00\x00\x1f\xcc|\xb3\x00\x00\n\xcb' (total 16)
value = Container:
length = 32
unknown = 0
device_id = unhexlify('1fcc7cb3')
ts = 1970-01-01 00:46:03
offset1 = 0
offset2 = 16
length = 16
checksum = b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' (total 16)
DEBUG:miio.miioprotocol:Discovered 1fcc7cb3 with ts: 1970-01-01 00:46:03, token: b'ffffffffffffffffffffffffffffffff'
DEBUG:miio.miioprotocol:192.168.178.176:54321 >>: {'id': 102, 'method': 'miIO.info', 'params': []}
DEBUG:miio.miioprotocol:Retrying with incremented id, retries left: 2
DEBUG:miio.miioprotocol:Got a response: Container:
data = Container:
data = b'' (total 0)
value = b'' (total 0)
offset1 = 32
offset2 = 32
length = 0
header = Container:
data = b'!1\x00 \x00\x00\x00\x00\x1f\xcc|\xb3\x00\x00\n\xd0' (total 16)
value = Container:
length = 32
unknown = 0
device_id = unhexlify('1fcc7cb3')
ts = 1970-01-01 00:46:08
offset1 = 0
offset2 = 16
length = 16
checksum = b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' (total 16)
DEBUG:miio.miioprotocol:Discovered 1fcc7cb3 with ts: 1970-01-01 00:46:08, token: b'ffffffffffffffffffffffffffffffff'
DEBUG:miio.miioprotocol:192.168.178.176:54321 >>: {'id': 203, 'method': 'miIO.info', 'params': []}
DEBUG:miio.miioprotocol:Retrying with incremented id, retries left: 1
DEBUG:miio.miioprotocol:Got a response: Container:
data = Container:
data = b'' (total 0)
value = b'' (total 0)
offset1 = 32
offset2 = 32
length = 0
header = Container:
data = b'!1\x00 \x00\x00\x00\x00\x1f\xcc|\xb3\x00\x00\n\xd5' (total 16)
value = Container:
length = 32
unknown = 0
device_id = unhexlify('1fcc7cb3')
ts = 1970-01-01 00:46:13
offset1 = 0
offset2 = 16
length = 16
checksum = b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' (total 16)
DEBUG:miio.miioprotocol:Discovered 1fcc7cb3 with ts: 1970-01-01 00:46:13, token: b'ffffffffffffffffffffffffffffffff'
DEBUG:miio.miioprotocol:192.168.178.176:54321 >>: {'id': 304, 'method': 'miIO.info', 'params': []}
ERROR:miio.miioprotocol:Got error when receiving: timed out
ERROR:miio.click_common:Exception: No response from the device
Traceback (most recent call last):
File "/Users/MYUSER/miio/python-miio/miio/miioprotocol.py", line 194, in send
data, addr = s.recvfrom(4096)
TimeoutError: timed out

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/Users/MYUSER/miio/python-miio/miio/miioprotocol.py", line 194, in send
data, addr = s.recvfrom(4096)
TimeoutError: timed out

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/Users/MYUSER/miio/python-miio/miio/miioprotocol.py", line 194, in send
data, addr = s.recvfrom(4096)
TimeoutError: timed out

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/Users/MYUSER/miio/python-miio/miio/miioprotocol.py", line 194, in send
data, addr = s.recvfrom(4096)
TimeoutError: timed out

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "/Users/MYUSER/miio/python-miio/miio/click_common.py", line 54, in call
return self.main(*args, **kwargs)
File "/Users/MYUSER/Library/Caches/pypoetry/virtualenvs/python-miio-k1hBW-Bf-py3.10/lib/python3.10/site-packages/click/core.py", line 1055, in main
rv = self.invoke(ctx)
File "/Users/MYUSER/Library/Caches/pypoetry/virtualenvs/python-miio-k1hBW-Bf-py3.10/lib/python3.10/site-packages/click/core.py", line 1657, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/Users/MYUSER/Library/Caches/pypoetry/virtualenvs/python-miio-k1hBW-Bf-py3.10/lib/python3.10/site-packages/click/core.py", line 1657, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/Users/MYUSER/Library/Caches/pypoetry/virtualenvs/python-miio-k1hBW-Bf-py3.10/lib/python3.10/site-packages/click/core.py", line 1404, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/Users/MYUSER/Library/Caches/pypoetry/virtualenvs/python-miio-k1hBW-Bf-py3.10/lib/python3.10/site-packages/click/core.py", line 760, in invoke
return __callback(*args, **kwargs)
File "/Users/MYUSER/miio/python-miio/miio/click_common.py", line 307, in wrap
kwargs["result"] = func(*args, **kwargs)
File "/Users/MYUSER/Library/Caches/pypoetry/virtualenvs/python-miio-k1hBW-Bf-py3.10/lib/python3.10/site-packages/click/decorators.py", line 84, in new_func
return ctx.invoke(f, obj, *args, **kwargs)
File "/Users/MYUSER/Library/Caches/pypoetry/virtualenvs/python-miio-k1hBW-Bf-py3.10/lib/python3.10/site-packages/click/core.py", line 760, in invoke
return __callback(*args, **kwargs)
File "/Users/MYUSER/miio/python-miio/miio/click_common.py", line 272, in command_callback
return miio_command.call(miio_device, *args, **kwargs)
File "/Users/MYUSER/miio/python-miio/miio/click_common.py", line 219, in call
return method(*args, **kwargs)
File "/Users/MYUSER/miio/python-miio/miio/click_common.py", line 186, in _wrap
return func(self, *args, **kwargs)
File "/Users/MYUSER/miio/python-miio/miio/device.py", line 130, in info
return self._fetch_info()
File "/Users/MYUSER/miio/python-miio/miio/device.py", line 135, in _fetch_info
devinfo = DeviceInfo(self.send("miIO.info"))
File "/Users/MYUSER/miio/python-miio/miio/device.py", line 89, in send
return self._protocol.send(
File "/Users/MYUSER/miio/python-miio/miio/miioprotocol.py", line 234, in send
return self.send(
File "/Users/MYUSER/miio/python-miio/miio/miioprotocol.py", line 234, in send
return self.send(
File "/Users/MYUSER/miio/python-miio/miio/miioprotocol.py", line 234, in send
return self.send(
File "/Users/MYUSER/miio/python-miio/miio/miioprotocol.py", line 242, in send
raise DeviceException("No response from the device") from ex
miio.exceptions.DeviceException: No response from the device

I understand that this is a new device to miiocli.
But the upper post states that at least something is working.
What might be wrong on my side?
Firmware Version is also: 2.2.1

@ghost
Copy link
Author

ghost commented Nov 3, 2022

@mkohns this is the base command i am using "miiocli -o json airpurifiermiot --model zhimi.airp.mb5 --ip --token". Note the device type is "airpurifiermiot" not "airpurifier"

Pretty much everything is working if you use properties from https://home.miot-spec.com/spec?type=urn%3Amiot-spec-v2%3Adevice%3Aair-purifier%3A0000A007%3Azhimi-cpa4%3A1

To get device status do something like - base_command_from_above raw_command get_properties '[{"siid":2,"piid":1}, {"siid":3,"piid":4}, {"siid":9,"piid":11}, {"siid":2,"piid":4}]' /power, pm2, fav_level, mode/

@mkohns
Copy link

mkohns commented Nov 3, 2022

@messyjoes1 Thanks a lot for the help an insights! This is working now for me.
For others reading this: I actually had 2 issues

  1. my token was wrong. I got the token with Packet Sender Tool in reset/unset/no wifi connect mode. The token extraction seemed to worked fine. It turned out - that the token changes - when you start using the app. Not very nice. For token extraction I used this tool:

bash <(curl -L https://github.com/PiotrMachowski/Xiaomi-cloud-tokens-extractor/raw/master/run.sh)

This was quite impressing.

  1. as stated in above post: use "airpurifiermiot" not "airpurifier"

This is my output now

poetry run miiocli -o json -d airpurifiermiot --ip 192.168.178.176 --token mytoken --model zhimi.airp.mb5 raw_command get_properties '[{"siid":2,"piid":1}, {"siid":3,"piid":4}, {"siid":9,"piid":11}, {"siid":2,"piid":4}]'

DEBUG:miio.miioprotocol:Got a response: Container:
data = Container:
data = b'' (total 0)
value = b'' (total 0)
offset1 = 32
offset2 = 32
length = 0
header = Container:
data = b'!1\x00 \x00\x00\x00\x00\x1f\xcc|\xb3\x00\x00\x19\xa9' (total 16)
value = Container:
length = 32
unknown = 0
device_id = unhexlify('1fcc7cb3')
ts = 1970-01-01 01:49:29
offset1 = 0
offset2 = 16
length = 16
checksum = b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' (total 16)
DEBUG:miio.miioprotocol:Discovered 1fcc7cb3 with ts: 1970-01-01 01:49:29, token: b'ffffffffffffffffffffffffffffffff'
DEBUG:miio.miioprotocol:192.168.178.176:54321 >>: {'id': 1,
'method': 'get_properties',
'params': [{'piid': 1, 'siid': 2},
{'piid': 4, 'siid': 3},
{'piid': 11, 'siid': 9},
{'piid': 4, 'siid': 2}]}
DEBUG:miio.miioprotocol:192.168.178.176:54321 (ts: 1970-01-01 01:49:30, id: 1) << {'exe_time': 240,
'id': 1,
'result': [{'code': 0,
'did': '533494963',
'piid': 1,
'siid': 2,
'value': True},
{'code': 0, 'did': '533494963', 'piid': 4, 'siid': 3, 'value': 9},
{'code': 0, 'did': '533494963', 'piid': 11, 'siid': 9, 'value': 8},
{'code': 0, 'did': '533494963', 'piid': 4, 'siid': 2, 'value': 0}]}
[{"did": "533494963", "siid": 2, "piid": 1, "code": 0, "value": true}, {"did": "533494963", "siid": 3, "piid": 4, "code": 0, "value": 9}, {"did": "533494963", "siid": 9, "piid": 11, "code": 0, "value": 8}, {"did": "533494963", "siid": 2, "piid": 4, "code": 0, "value": 0}]

@mkohns
Copy link

mkohns commented Nov 3, 2022

@messyjoes1: one more question.

Would it be the right approach to edit file miio/integrations/airpurifier/zhimi/airpurifier_miot.py

  1. add new mapping, say _MAPPING_CPA4 with spec https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:air-purifier:0000A007:zhimi-cpa4:1

  2. add this line to _MAPPINGS

"zhimi.airp.cpa4": _MAPPING_CPA4, # airpurifier 4 compact

  1. add zhimi.airp.cpa4 to REVERSED_LED_BRIGHTNESS

What do you think? Do I miss something?

@mkohns
Copy link

mkohns commented Nov 3, 2022

Okay, I tested what I described above.
This is working fine.
I can now access the air purifier 4 compact completely :)
Getting and setting properties works nice.

You can find the small changes in fork: https://github.com/mkohns/python-miio

The reason why command "status" made the device crash (and beep) was in max_properties setting.
The cpa4 only supports to retrieve one property at the same time.
If you request more (default is 15), he does not like it.

I have never implemented anything in python. I am a golang developer.
Perhaps someone can give feedback if this is ready for pull request?

@rytilahti
Copy link
Owner

Could you try the request with fewer, but more than 1, properties to see if that works? If yes, the limitation comes from the UDP datagram size and not from the device.

Btw, you can also obtain the tokens in git master version using miiocli cloud command as described here: https://python-miio.readthedocs.io/en/latest/discovery.html#obtaining-tokens

@mkohns
Copy link

mkohns commented Nov 4, 2022

Hi @rytilahti! Nice to meet you.
I have increased the max props and tested it.
The highest value I found was 3. With 4 the device crashes again.
I adjusted this in the code.

@rytilahti
Copy link
Owner

Hi @mkohns, thanks for testing! It's good to know about that limitation so I can make it somehow configurable in the future. I'm currently working on a generic implementation for all miot devices to avoid the need to manually create implementations for specific devices.

@hmmbob
Copy link

hmmbob commented Nov 18, 2023

Am I right that this fix has not been released as part of the package yet?

I'm thinking that this might be related to the issue I just created at Home Assistant (home-assistant/core#104169), as they are using the latest available package

@cjitariu
Copy link

Hello. I have the same problem was it solved?

@ilMartiniano
Copy link

+1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants