Xiaomi mi wifi plug & air purifier

@af950833 Last request for today. :wink: I want to support your Air Purifier Pro properly. You already know the procedere. Could you post the output of:

# I want to know the model name
bin/mirobo --ip 192.168.1.xx --token 3d5fffffffffffffffffffffff37453b info
# First bunch of properties
bin/mirobo --ip 192.168.1.xx --token 3d5fffffffffffffffffffffff37453b get_prop '["power", "aqi", "average_aqi", "humidity", "temp_dec", "mode", "favorite_level", "filter1_life", "f1_hour_used", "use_time", "motor1_speed", "purify_volume", "f1_hour"]'
# Second bunch of properties
bin/mirobo --ip 192.168.1.xx --token 3d5fffffffffffffffffffffff37453b get_prop '["led", "led_b", "bright", "buzzer", "child_lock", "volume" ]'

Thanks! :slight_smile:

(homeassistant) homeassistant@Tommy:/home/pi $ mirobo --ip 192.168.0.15 --token 2a4d39a5721f983fdceae9193fc35596 -d info
INFO:miio.vacuum_cli:Debug mode active
DEBUG:miio.vacuum_cli:Read stored sequence ids: {‘manual_seq’: 0, ‘seq’: 12}
DEBUG:miio.vacuum_cli:Connecting to 192.168.0.15 with token 2a4d39a5721f983fdceae9193fc35596
DEBUG:miio.protocol:Unable to decrypt, returning raw bytes: b’’
DEBUG:miio.device:Got a response: Container:
data = Container:
data = (total 0)
offset2 = 32
offset1 = 32
length = 0
value = (total 0)
header = Container:
data = !1\x00 \x00\x00\x00\x00\x036}B\x00\x0b\xdbO (total 16)
offset2 = 16
offset1 = 0
length = 16
value = Container:
length = 32
unknown = 0
device_id = 03367d42 (total 8)
ts = 1970-01-09 23:50:39
checksum = *M9\xa5r\x1f\x98?\xdc\xea\xe9\x19?\xc3U\x96 (total 16)
DEBUG:miio.device:Discovered b’03367d42’ with ts: 1970-01-09 23:50:39, token: b’2a4d39a5721f983fdceae9193fc35596’
DEBUG:miio.device:192.168.0.15:54321 >>: {‘method’: ‘miIO.info’, ‘params’: [], ‘id’: 13}
DEBUG:miio.device:192.168.0.15:54321 (ts: 1970-01-09 23:50:39, id: 13) << {‘result’: {‘token’: ‘2a4d39a5721f983fdceae9193fc35596’, ‘mac’: ‘28:6C:07:B1:FE:B8’, ‘otu_stat’: [74, 74, 21452, 25, 21384, 404], ‘ot’: ‘otu’, ‘hw_ver’: ‘MW300’, ‘life’: 777039, ‘ap’: {‘ssid’: ‘Tommy’, ‘rssi’: -35, ‘bssid’: ‘AC:9E:17:A1:DF:F8’}, ‘model’: ‘zhimi.airpurifier.v6’, ‘wifi_fw_ver’: ‘SD878x-14.76.36.p84-702.1.0-WM’, ‘netif’: {‘localIp’: ‘192.168.0.15’, ‘mask’: ‘255.255.255.0’, ‘gw’: ‘192.168.0.1’}, ‘mmfree’: 185644, ‘ott_stat’: [0, 0, 0, 0], ‘cfg_time’: 0, ‘fw_ver’: ‘1.2.9_9049’}, ‘id’: 13}
zhimi.airpurifier.v6 v1.2.9_9049 (28:6C:07:B1:FE:B8) @ 192.168.0.15 - token: 2a4d39a5721f983fdceae9193fc35596
DEBUG:miio.vacuum_cli:Full response: {‘ap’: {‘bssid’: ‘AC:9E:17:A1:DF:F8’, ‘rssi’: -35, ‘ssid’: ‘Tommy’},
‘cfg_time’: 0,
‘fw_ver’: ‘1.2.9_9049’,
‘hw_ver’: ‘MW300’,
‘life’: 777039,
‘mac’: ‘28:6C:07:B1:FE:B8’,
‘mmfree’: 185644,
‘model’: ‘zhimi.airpurifier.v6’,
‘netif’: {‘gw’: ‘192.168.0.1’,
‘localIp’: ‘192.168.0.15’,
‘mask’: ‘255.255.255.0’},
‘ot’: ‘otu’,
‘ott_stat’: [0, 0, 0, 0],
‘otu_stat’: [74, 74, 21452, 25, 21384, 404],
‘token’: ‘2a4d39a5721f983fdceae9193fc35596’,
‘wifi_fw_ver’: ‘SD878x-14.76.36.p84-702.1.0-WM’}
DEBUG:miio.vacuum_cli:Writing {‘manual_seq’: 0, ‘seq’: 13} to /tmp/python-mirobo.seq
(homeassistant) homeassistant@Tommy:/home/pi $
(homeassistant) homeassistant@Tommy:/home/pi $ mirobo --ip 192.168.0.15 --token 2a4d39a5721f983fdceae9193fc35596 raw_command get_prop ‘[“power”, “aqi”, “average_aqi”, “humidity”, “temp_dec”, “mode”, “favorite_level”, “filter1_life”, “f1_hour_used”, “use_time”, “motor1_speed”, “purify_volume”, “f1_hour”]’
Sending cmd get_prop with params [‘power’, ‘aqi’, ‘average_aqi’, ‘humidity’, ‘temp_dec’, ‘mode’, ‘favorite_level’, ‘filter1_life’, ‘f1_hour_used’, ‘use_time’, ‘motor1_speed’, ‘purify_volume’, ‘f1_hour’]
[‘off’, 7, 18, 45, 234, ‘auto’, 17, 52, 1664, 2642700, 0, 62180, 3500]
(homeassistant) homeassistant@Tommy:/home/pi $
(homeassistant) homeassistant@Tommy:/home/pi $ mirobo --ip 192.168.0.15 --token 2a4d39a5721f983fdceae9193fc35596 raw_command get_prop ‘[“led”, “led_b”, “bright”, “buzzer”, “child_lock”, “volume” ]’
Sending cmd get_prop with params [‘led’, ‘led_b’, ‘bright’, ‘buzzer’, ‘child_lock’, ‘volume’]
[‘on’, None, 83, None, ‘off’, 50]
(homeassistant) homeassistant@Tommy:/home/pi $

It is my pleasure to help you :slight_smile:
As I mentioned, there is no “led_b” in the Air purifier(and Buzzer is not in it)

Perfect! I will prepare the next interation.

@af950833 Last wish for this device: Could you check/verify the supported operation modes of the Air Purifier Pro? (Command: set_mode, Possible values: auto, silent, favorite, idle)

Idle isn’t supported and returns an error, right?

@syssi Yes, you are right.

(homeassistant) homeassistant@Tommy:/home/pi $ mirobo --ip 192.168.0.15 --token 2a4d39a5721f983fdceae9193fc35596 raw_command set_mode ‘[“silent”]’
Sending cmd set_mode with params [‘silent’]
[‘ok’]
(homeassistant) homeassistant@Tommy:/home/pi $ mirobo --ip 192.168.0.15 --token 2a4d39a5721f983fdceae9193fc35596 raw_command set_mode ‘[“auto”]’
Sending cmd set_mode with params [‘auto’]
[‘ok’]
(homeassistant) homeassistant@Tommy:/home/pi $ mirobo --ip 192.168.0.15 --token 2a4d39a5721f983fdceae9193fc35596 raw_command set_mode ‘[“idle”]’
Sending cmd set_mode with params [‘idle’]
{‘id’: 6, ‘error’: {‘code’: -5001, ‘message’: ‘invaild_arg’}}
(homeassistant) homeassistant@Tommy:/home/pi $ mirobo --ip 192.168.0.15 --token 2a4d39a5721f983fdceae9193fc35596 raw_command set_mode ‘[“favorite”]’
Sending cmd set_mode with params [‘favorite’]
[‘ok’]

1 Like

@af950833 I prepared the next iteration of the air purifier component: https://github.com/syssi/xiaomi_airpurifier

Please copy the custom component into .homeassistant/custom_components/fan/xiaomi_miio.py

The custom component overrides the official fan.xiaomi_miio component and provides support for the Xiaomi Air Purifier and Xiaomi Air Humidifier:

fan:
  - platform: xiaomi_miio
    name: Xiaomi Air Purifier
    host: 192.168.130.71
    token: b7c4a758c251955d2c24b1d9e41ce47d

  - platform: xiaomi_miio
    name: Xiaomi Air Humidifier
    host: 192.168.130.72
    token: 2b00042f7481c7b056c4b410d28f33cf

I would be happy about a screenshot of both detail views if the component works out of the box. Because you own the Xiaomi Air Purifier Pro there should be some mor attributes available as in my screenshot:

Thanks in advance!

hi syssi,

The HA frontend is just loading and showed nothing.
1

pi@Tommy:~ $ cat /home/homeassistant/.homeassistant/home-assistant.log
2018-02-22 17:36:33 WARNING (Recorder) [homeassistant.components.recorder] Ended unfinished session (id=76 from 2018-02-22 08:29:04.944067)
2018-02-22 17:36:40 WARNING (Thread-14) [homeassistant.components.emulated_hue] When targeting Google Home, listening port has to be port 80
2018-02-22 17:36:57 WARNING (MainThread) [homeassistant.components.sensor] Setup of platform yr is taking over 10 seconds.
2018-02-22 17:36:57 ERROR (Thread-14) [miio.device] Got error when receiving: timed out
2018-02-22 17:36:57 WARNING (Thread-14) [miio.device] Retrying with incremented id, retries left: 3
2018-02-22 17:36:59 ERROR (Thread-21) [miio.device] Got error when receiving: timed out
2018-02-22 17:36:59 WARNING (Thread-21) [miio.device] Retrying with incremented id, retries left: 3
2018-02-22 17:37:06 ERROR (MainThread) [homeassistant.core] Timer got out of sync. Resetting
2018-02-22 17:37:11 ERROR (MainThread) [homeassistant.core] Timer got out of sync. Resetting
2018-02-22 17:37:30 ERROR (MainThread) [aiohttp.server] Error handling request
Traceback (most recent call last):
File “/srv/homeassistant/lib/python3.5/site-packages/homeassistant/remote.py”, line 126, in default
return json.JSONEncoder.default(self, o)
File “/usr/lib/python3.5/json/encoder.py”, line 179, in default
raise TypeError(repr(o) + " is not JSON serializable")
TypeError: <FilterType.Regular: ‘regular’> is not JSON serializable

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File “/srv/homeassistant/lib/python3.5/site-packages/homeassistant/remote.py”, line 132, in default
for child_obj in o]
TypeError: ‘FilterType’ object is not iterable

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File “/srv/homeassistant/lib/python3.5/site-packages/aiohttp/web_protocol.py”, line 416, in start
resp = yield from self._request_handler(request)
File “/srv/homeassistant/lib/python3.5/site-packages/aiohttp/web.py”, line 325, in _handle
resp = yield from handler(request)
File “/srv/homeassistant/lib/python3.5/site-packages/aiohttp/web_middlewares.py”, line 93, in impl
return (yield from handler(request))
File “/srv/homeassistant/lib/python3.5/site-packages/homeassistant/components/http/ban.py”, line 58, in ban_middleware
return (yield from handler(request))
File “/srv/homeassistant/lib/python3.5/site-packages/homeassistant/components/http/auth.py”, line 49, in auth_middleware
return (yield from handler(request))
File “/srv/homeassistant/lib/python3.5/site-packages/homeassistant/components/http/static.py”, line 70, in staticresource_middleware
return (yield from handler(request))
File “/srv/homeassistant/lib/python3.5/site-packages/homeassistant/components/http/init.py”, line 430, in handle
result = yield from result
File “/usr/lib/python3.5/asyncio/coroutines.py”, line 213, in coro
res = yield from res
File “/srv/homeassistant/lib/python3.5/site-packages/homeassistant/components/websocket_api.py”, line 397, in handle
yield from self._writer_task
File “/usr/lib/python3.5/asyncio/futures.py”, line 382, in iter
return self.result() # May raise too.
File “/usr/lib/python3.5/asyncio/futures.py”, line 293, in result
raise self._exception
File “/usr/lib/python3.5/asyncio/tasks.py”, line 239, in _step
result = coro.send(None)
File “/srv/homeassistant/lib/python3.5/site-packages/homeassistant/components/websocket_api.py”, line 246, in _writer
yield from self.wsock.send_json(message, dumps=JSON_DUMP)
File “/srv/homeassistant/lib/python3.5/site-packages/aiohttp/web_ws.py”, line 197, in send_json
return self.send_str(dumps(data))
File “/usr/lib/python3.5/json/init.py”, line 237, in dumps
**kw).encode(obj)
File “/usr/lib/python3.5/json/encoder.py”, line 198, in encode
chunks = self.iterencode(o, _one_shot=True)
File “/usr/lib/python3.5/json/encoder.py”, line 256, in iterencode
return _iterencode(o, 0)
File “/srv/homeassistant/lib/python3.5/site-packages/homeassistant/remote.py”, line 135, in default
return json.JSONEncoder.default(self, o)
File “/usr/lib/python3.5/json/encoder.py”, line 179, in default
raise TypeError(repr(o) + " is not JSON serializable")
TypeError: <FilterType.Regular: ‘regular’> is not JSON serializable
2018-02-22 17:37:44 ERROR (Recorder) [homeassistant.components.recorder.util] Error executing query: <FilterType.Regular: ‘regular’> is not JSON serializable

Ups! This is my fault. Fixed! Please update the custom component.

You have to correct the line# 510 :slight_smile:
3

After that, I got the below result.(make the picture to enlarge)

2

For reference, at the HA starting, there are some time out errors but everything is OK.
2018-02-22 18:54:41 WARNING (Thread-17) [homeassistant.components.emulated_hue] When targeting Google Home, listening port has to be port 80
2018-02-22 18:54:50 ERROR (Thread-9) [miio.device] Got error when receiving: timed out
2018-02-22 18:54:50 WARNING (Thread-9) [miio.device] Retrying with incremented id, retries left: 3
2018-02-22 18:54:50 ERROR (Thread-19) [miio.device] Got error when receiving: timed out
2018-02-22 18:54:50 WARNING (Thread-19) [miio.device] Retrying with incremented id, retries left: 3
2018-02-22 18:55:17 ERROR (MainThread) [homeassistant.core] Timer got out of sync. Resetting
2018-02-22 19:01:38 ERROR (Thread-4) [miio.device] Got error when receiving: timed out
2018-02-22 19:01:38 WARNING (Thread-4) [miio.device] Retrying with incremented id, retries left: 3
2018-02-22 19:02:37 ERROR (MainThread) [homeassistant.core] Timer got out of sync. Resetting

Hi,

first of all, thanks for the great work with this module!

Now, onto my problem, I cannot figure out how to set the mode on my purifier v2…
I can change the mode from the Home Assistant UI, but whenever I try sending the command manually I get an error message.

Here’s my setup:

Versions
python-miio==0.3.6
Home Assistant 0.63.3
Custom Component from https://github.com/home-assistant/home-assistant/blob/master/homeassistant/components/fan/xiaomi_miio.py

Config

  • platform: xiaomi_miio
    name: Air Purifier
    host: 192.168.1.61
    token: d4c02da2dexxxx158xxxx9a4413316df

The fan is visible as:
fan.air_purifier on speed: Silent
speed_list: Auto,Silent,Favorite,Idle
sleep_time: 75486
child_lock: false
buzzer: false
filter_life_remaining: 74
temperature: 22.3
favorite_level: 16
mode: silent
turbo_mode_supported: true
sleep_mode: silent
motor_speed: 348
sleep_mode_learn_count: 30
extra_features: 1
led_brightness: 1
filter_hours_used: 909
learn_mode: true
friendly_name: Air Purifier
humidity: 56
average_aqi: 8
aqi: 10
model: zhimi.airpurifier.m1
led: true
supported_features: 6905
purify_volume: 241409

The problem:
Calling service: fan.turn_on
with JSON:
{
“entity_id”: “fan.air_purifier”,
“speed”:“auto”
}

I get the error:
2018-02-22 21:10:29 ERROR (MainThread) [homeassistant.core] Error executing service <ServiceCall fan.turn_on: entity_id=[‘fan.air_purifier’], speed=auto>
Traceback (most recent call last):
File “/usr/local/lib/python3.5/dist-packages/homeassistant/core.py”, line 1010, in _event_to_service_call
yield from service_handler.func(service_call)
File “/usr/local/lib/python3.5/dist-packages/homeassistant/components/fan/init.py”, line 218, in async_handle_fan_service
yield from getattr(fan, method[‘method’])(**params)
File “/home/pi/.homeassistant/custom_components/fan/xiaomi_miio.py”, line 327, in async_turn_on
result = yield from self.async_set_speed(speed)
File “/home/pi/.homeassistant/custom_components/fan/xiaomi_miio.py”, line 552, in async_set_speed
self._device.set_mode, OperationMode[speed])
File “/usr/lib/python3.5/enum.py”, line 277, in getitem
return cls.member_map[name]
KeyError: ‘auto’

It doesn’t matter what I try, auto, high,low, a number, always the same error.

Any tips?

thanks again!

There is no service to change the mode in the current air purifier component.
You can do it with a shell command like the below.
With them, you can make a automation what you want.

shell_command:
mi_air_mode_auto: /srv/homeassistant/bin/mirobo --ip 192.168.0.15 --token 2a4d39a5721f983fdceae9193fc35555 raw_command set_mode ‘[“auto”]’
mi_air_mode_silent: /srv/homeassistant/bin/mirobo --ip 192.168.0.15 --token 2a4d39a5721f983fdceae9193fc35555 raw_command set_mode ‘[“silent”]’
mi_air_mode_favorite: /srv/homeassistant/bin/mirobo --ip 192.168.0.15 --token 2a4d39a5721f983fdceae9193fc35555 raw_command set_mode ‘[“favorite”]’

@hkrob You found a bug! I just fixed the set_speed service. This is the code change:

https://github.com/syssi/xiaomi_airpurifier/commit/8bc091f03cfaaea6ffff2b823bb52b6103f6508b

You could use the custom component in the meantime. I will provide an official fix for home assistant soon!

@syssi you’re awesome, working fine now!

@af950833 thanks for the work-around, but you might want to correct your statement “There is no service to change the mode in the current air purifier component”

cheers guys

As I mentioned, there is no service to change a mode in current air purifier.
The fan.turn_on (you tried) is not a service of air purifier.
Syssi is making a new code and he will add it but not available now.

I rethink my fix. This wasn’t a bug. The change broke the dropdown of the UI. Please revert the fix. The payload of the service was wrong. This will work:

{“entity_id”: “fan.air_purifier”, “speed”:“Auto”}
{“entity_id”: “fan.air_purifier”, “speed”:“Favorite”}

etc.

Could someone of the powerstrip owners (@hangy?) provide the output of following commands:

mirobo raw_command get_prop "['power', 'temperature', 'current', 'mode', 'power_consume_rate', 'wifi_led', 'power_price']"
mirobo raw_command set_power_price "[1.55]"
mirobo raw_command get_prop "['power', 'temperature', 'current', 'mode', 'power_consume_rate', 'wifi_led', 'power_price']"
mirobo raw_command set_power_price "[2]"
mirobo raw_command get_prop "['power', 'temperature', 'current', 'mode', 'power_consume_rate', 'wifi_led', 'power_price']"

mirobo raw_command set_wifi_led "['off']"
mirobo raw_command get_prop "['power', 'temperature', 'current', 'mode', 'power_consume_rate', 'wifi_led', 'power_price']"
mirobo raw_command set_wifi_led "['on']"
mirobo raw_command get_prop "['power', 'temperature', 'current', 'mode', 'power_consume_rate', 'wifi_led', 'power_price']"

Thanks in advance!

here it is @syssi :slight_smile:

mirobo raw_command get_prop "['power', 'temperature', 'current', 'mode', 'power_consume_rate', 'wifi_led', 'power_price']" ->
['on', 44.07, 0.22, None, 26.29, 'on', 8]

raw_command set_power_price "[1.55]" ->
Sending cmd set_power_price with params [1.55]
['ok']

raw_command get_prop "['power', 'temperature', 'current', 'mode', 'power_consume_rate', 'wifi_led', 'power_price']" ->
['on', 44.0, 0.22, None, 26.29, 'on', 1]

raw_command set_power_price "[2]" ->
Sending cmd set_power_price with params [2]
['ok']

raw_command get_prop "['power', 'temperature', 'current', 'mode', 'power_consume_rate', 'wifi_led', 'power_price']" ->
['on', 43.93, 0.22, None, 26.39, 'on', 2]

raw_command set_wifi_led "['off']" ->
Sending cmd set_wifi_led with params ['off']
['ok']

raw_command get_prop "['power', 'temperature', 'current', 'mode', 'power_consume_rate', 'wifi_led', 'power_price']" ->
['on', 43.86, 0.22, None, 26.6, 'off', 2]

raw_command set_wifi_led "['on']" ->
Sending cmd set_wifi_led with params ['on']
['ok']

raw_command get_prop "['power', 'temperature', 'current', 'mode', 'power_consume_rate', 'wifi_led', 'power_price']" ->
['on', 43.72, 0.22, None, 25.89, 'on', 2]

i’ve understand that the electricity power can not be set with decimal value… i think because in china is not needed :wink:

Thanks for your support! I will introduce the additional properties into the official component soon.

2 Likes

Sorry for dumb question, can someone help me with setting the speed/mode for the air purifier.

- alias: 'xiaomi fan test silent'        
  trigger:
  action:
    - service: persistent_notification.create
      data:
        message: "I just turned the fan onto silent mode"
        title: "Fan Notification"
    - service: FAN.XIAOMI_MIIO_SET_OPERATION_MODE
      data:
        mode: 'silent'
        
- alias: 'xiaomi fan test favorite'        
  trigger:
  action:
    - service: persistent_notification.create
      data:
        message: "I just turned the fan onto favorite mode"
        title: "Fan Notification"
    - service: FAN.XIAOMI_MIIO_SET_OPERATION_MODE
      data:
        mode: 'favorite'