Closed Alangasar closed 3 years ago
Has anyone tested the commands on this robot?
I tested the commands and found some working.
get_properties:
piid: 2 siid: 1 - device status piid: 2 siid: 2 - I don't know
piid: 3 siid: 1 - battery in% piid: 3 siid: 2 - battery status
piid: 4 siid: 1 - voice status piid: 4 siid: 2 - voice volume in%
piid: 9 siid: 1 - last vacuum cleaning area in m2 piid: 9 siid: 2 - duration of the last vacuuming in min piid: 9 siid: 3 - total cleaning area in m2 piid: 9 siid: 4 - total duration of cleaning in min piid: 9 siid: 5 - total number of vacuums
piid: 11 siid: 1 - filter consumption in% piid: 11 siid: 2 - remaining time to replace the filter in min
piid: 12 siid: 1 - I don't know piid: 12 siid: 2 - DND mode state
piid: 14 siid: 1 - main brush consumption in% piid: 14 siid: 2 - remaining time to replace the main brush in min
piid: 15 siid: 1 - angle brush wear in% piid: 15 siid: 2 - remaining time to replace angular brushes in min
piid: 16 siid: 1 - value 0, I don't know
set_properties:
siid: 4 piid: 1 value: 0/1 enable disable voice siid: 4 piid: 2 value: volume value 0-100 siid: 8 piid: 1 value: 2 - a step forward; 0 - left; 1 - right; -- > Captured packet from Mi Home by wireshark, UDP protocol. I couldn't find the command to start - stop the robot and setting the vacuuming power. I've been capturing packets and the Mi Home app doesn't send packets directly to the robot. It only sends data to the server via the TLS protocol.
This is an example of sending a request and response: Request: { "method": "get_properties", "params": [ { "did": "123456789", "siid": 2, "piid": 1 } ] } Response: { "id": 367107977, "result": [ { "did": "123456789", "siid": 2, "piid": 1, "code": 0, "value": 5 } ], "exe_time": 70 }
There is someone who can help me??? The most important thing for me is turning the robot on and off.
Start cleanup "method":"action","params":{"did":"X","siid":2,"aiid":1} Pause cleanup "method":"action","params":{"did":"X","siid":2,"aiid":2} Charge "method":"action","params":{"did":"X","siid":13,"aiid":1}
Start cleanup "method":"action","params":{"did":"X","siid":2,"aiid":1} Pause cleanup "method":"action","params":{"did":"X","siid":2,"aiid":2} Charge "method":"action","params":{"did":"X","siid":13,"aiid":1}
It works, thanks.
I tested the commands and found some working.
get_properties:
piid: 2 siid: 1 - device status piid: 2 siid: 2 - I don't know
piid: 3 siid: 1 - battery in% piid: 3 siid: 2 - battery status
piid: 4 siid: 1 - voice status piid: 4 siid: 2 - voice volume in%
piid: 9 siid: 1 - last vacuum cleaning area in m2 piid: 9 siid: 2 - duration of the last vacuuming in min piid: 9 siid: 3 - total cleaning area in m2 piid: 9 siid: 4 - total duration of cleaning in min piid: 9 siid: 5 - total number of vacuums
piid: 11 siid: 1 - filter consumption in% piid: 11 siid: 2 - remaining time to replace the filter in min
piid: 12 siid: 1 - I don't know piid: 12 siid: 2 - DND mode state
piid: 14 siid: 1 - main brush consumption in% piid: 14 siid: 2 - remaining time to replace the main brush in min
piid: 15 siid: 1 - angle brush wear in% piid: 15 siid: 2 - remaining time to replace angular brushes in min
piid: 16 siid: 1 - value 0, I don't know
set_properties:
siid: 4 piid: 1 value: 0/1 enable disable voice siid: 4 piid: 2 value: volume value 0-100 siid: 8 piid: 1 value: 2 - a step forward; 0 - left; 1 - right; -- > Captured packet from Mi Home by wireshark, UDP protocol. I couldn't find the command to start - stop the robot and setting the vacuuming power. I've been capturing packets and the Mi Home app doesn't send packets directly to the robot. It only sends data to the server via the TLS protocol.
This is an example of sending a request and response: Request: { "method": "get_properties", "params": [ { "did": "123456789", "siid": 2, "piid": 1 } ] } Response: { "id": 367107977, "result": [ { "did": "123456789", "siid": 2, "piid": 1, "code": 0, "value": 5 } ], "exe_time": 70 }
There is someone who can help me??? The most important thing for me is turning the robot on and off.
get_commands = { 1:'{"method":"get_properties","params":[{"siid":2,"piid":1}]}', #command_get_status 2:'{"method":"get_properties","params":[{"siid":2,"piid":2}]}', #command_get_error 3:'{"method":"get_properties","params":[{"siid":2,"piid":4}]}', #command_get_mode 4:'{"method":"get_properties","params":[{"siid":2,"piid":5}]}', #command_get_water_mode 5:'{"method":"get_properties","params":[{"siid":2,"piid":6}]}', #command_get_fan_mode 6:'{"method":"get_properties","params":[{"siid":3,"piid":2}]}', #command_get_charge_state 7:'{"method":"get_properties","params":[{"siid":16,"piid":1}]}', #command_get_mop_status 8:'{"method":"get_properties","params":[{"siid":3,"piid":1}]}', #command_get_battery_level 9:'{"method":"get_properties","params":[{"siid":14,"piid":1}]}', #command_get_main_brush_life_level_percent 10:'{"method":"get_properties","params":[{"siid":14,"piid":2}]}', #command_get_main_brush_life_level_minutes 11:'{"method":"get_properties","params":[{"siid":15,"piid":1}]}', #command_get_side_brush_life_level_percent 12:'{"method":"get_properties","params":[{"siid":15,"piid":2}]}', #command_get_side_brush_life_level_minutes 13:'{"method":"get_properties","params":[{"siid":11,"piid":1}]}', #command_get_filter_life_level_percent 14:'{"method":"get_properties","params":[{"siid":11,"piid":2}]}', #command_get_filter_brush_life_level_minutes 15:'{"method":"get_properties","params":[{"siid":9,"piid":1}]}', #command_get_clean-area # responce value always 0 16:'{"method":"get_properties","params":[{"siid":9,"piid":2}]}', #command_get_clean-time # responce value always 0 17:'{"method":"get_properties","params":[{"siid":9,"piid":3}]}', #command_get_total_clean-area # responce value always 0 18:'{"method":"get_properties","params":[{"siid":9,"piid":4}]}', #command_get_total_clean-time # responce value always 0 19:'{"method":"get_properties","params":[{"siid":9,"piid":5}]}', #command_get_total_clean-count # responce value always 0 20:'{"method":"get_properties","params":[{"siid":12,"piid":1}]}', #command_get_speech_language 21:'{"method":"get_properties","params":[{"siid":12,"piid":1}]}'} #command_get_DND_status
action_commands = { 1:'{"method":"action","params":{"siid":2,"aiid":1}}', #command_start_sweep 2:'{"method":"action","params":{"siid":2,"aiid":2}}', #command_stop_sweep 3:'{"method":"action","params":{"siid":2,"aiid":3}}', #command_go_charge 4:'{"method":"action","params":{"siid":6,"aiid":1}}', #command_find_vacuum 5:'{"method":"action","params":{"siid":13,"aiid":1}}', #command_start_charge 6:'{"method":"action","params":{"siid":13,"aiid":2}}'} #command_stop_charge
set_commands = { 1:'{"method":"set_properties","params":[{"siid":2,"piid":4,"value":', #command_set_work_mode 2:'{"method":"set_properties","params":[{"siid":2,"piid":5,"value":', #command_set_water_mode 3:'{"method":"set_properties","params":[{"siid":2,"piid":6,"value":', #command_set_fan_mode 4:'{"method":"set_properties","params":[{"siid":12,"piid":1,"value":', #command_set_speech_language 5:'{"method":"set_properties","params":[{"siid":12,"piid":2,"value":'} #command_set_DND_status
Thanks. I've already tested all these commands from this link: https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:vacuum:0000A006:mijia-v1:1
Thanks. I've already tested all these commands from this link: https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:vacuum:0000A006:mijia-v1:1
19:_'{"method":"getproperties","params":[{"siid":9,"piid":5}]}', #command_get_total_clean-count # responce value always 0
What kind of response you have received this request?
Thanks. I've already tested all these commands from this link: https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:vacuum:0000A006:mijia-v1:1
19:_'{"method":"getproperties","params":[{"siid":9,"piid":5}]}', #command_get_total_clean-count # responce value always 0
What kind of response you have received this request?
When I was using the vacuum cleaner by MiHome I had values there. Now, when I started the vacuum cleaner by commands, I also always have 0. Try to run the vacuum cleaner through MiHome several times and check if the values are there.
Now, when I started the vacuum cleaner by commands, I also always have 0
Can you write how to run commands? I only want to run/stop cleaner from command line. Thanks
Now, when I started the vacuum cleaner by commands, I also always have 0
Can you write how to run commands? I only want to run/stop cleaner from command line. Thanks
Where do you want to run these commands?
Where do you want to run these commands?
From command line. I want make script for Home Assistant.
From command line. I want make script for Home Assistant.
I use the plugin for domoticz from here: https://github.com/mrin/domoticz-mirobot-plugin
I see that this topic is quite Inactive nowadays but I am wondering whether the Xiaomi Robot Vacuum-Mop Essential is (fully) supported or not. This because I om thinking about buying one as my first vacuum robot and I want to use it in combination with Domoticz using this library.
Hey Rick, I have spend 2 days trying to get it to work with hass but the essential mob is not yet fully supported. Compared this with a roborock of a friend of mine and that integrations works like a charm. I recommend you look for a different mob if you want full support.
Hello, is there any news about support for this device?
Hello, is there any news about support for this device?
I am using a custom component for home assistant based on python-miio.
Class for sending commands.
from .miot_device import MiotDevice
class MyVacuum(MiDevice):
@command()
def status(self) -> Status:
status = Status()
response = self.send('get_properties', [{"siid": 2, "piid": 1}, {"siid": 2, "piid": 2}, {"siid": 2, "piid": 6}, {"siid": 3, "piid": 1}, {"siid": 9, "piid": 2}, {"siid": 9, "piid": 1}, {"siid": 14, "piid": 1}, {"siid": 15, "piid": 1}, {"siid": 11, "piid": 1}])
status.error = response[1]["value"]
status.status = response[0]["value"]
status.battery = response[3]["value"]
status.fan_speed = response[2]["value"]
status.clean_time = response[4]["value"]
status.clean_area = response[5]["value"]
status.brush_life_level = response[6]["value"]
status.side_brush_life_level = response[7]["value"]
status.filter_life_level = response[8]["value"]
return status
def call_action(self, siid, aiid, params=None):
if params is None:
params = []
payload = {
"did": f"call-{siid}-{aiid}",
"siid": siid,
"aiid": aiid,
}
return self.send("action", payload)
@command(click.argument("speed", type=int))
def set_fan_speed(self, speed):
"""Set fan speed"""
return self.send('set_properties', [{"siid": 2, "piid": 6, "value": speed}])
@command()
def return_home(self) -> None:
"""aiid 1 Start Charge: in: [] -> out: []"""
return self.call_action(2, 3)
@command()
def start(self) -> None:
"""Start cleaning."""
return self.call_action(2, 1)
@command()
def stop(self) -> None:
"""Stop cleaning."""
return self.call_action(2, 2)
@command()
def find(self) -> None:
"""Find the robot."""
return self.call_action(6, 1)
Below modified vacuum class in ...config\custom_components\xiaomi_vacuum.
"""Xiaomi Vacuum"""
from functools import partial
import logging
import voluptuous as vol
from .miio import MyVacuum, DeviceException
from homeassistant.components.vacuum import (
PLATFORM_SCHEMA,
SUPPORT_STATE,
SUPPORT_BATTERY,
SUPPORT_LOCATE,
SUPPORT_PAUSE,
SUPPORT_RETURN_HOME,
SUPPORT_START,
SUPPORT_STOP,
SUPPORT_FAN_SPEED,
STATE_CLEANING,
STATE_IDLE,
STATE_PAUSED,
STATE_RETURNING,
STATE_DOCKED,
STATE_ERROR,
StateVacuumEntity,
)
from homeassistant.const import CONF_HOST, CONF_NAME, CONF_TOKEN
from homeassistant.helpers import config_validation as cv, entity_platform
_LOGGER = logging.getLogger(__name__)
DEFAULT_NAME = "Xiaomi Vacuum cleaner"
DATA_KEY = "vacuum.xiaomi_vacuum"
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
vol.Required(CONF_HOST): cv.string,
vol.Required(CONF_TOKEN): vol.All(str, vol.Length(min=32, max=32)),
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
},
extra=vol.ALLOW_EXTRA,
)
ATTR_STATUS = "status"
ATTR_ERROR = "error"
ATTR_FAN_SPEED = "fan_speed"
ATTR_CLEANING_TIME = "cleaning_time"
ATTR_CLEANING_AREA = "cleaning_area"
ATTR_MAIN_BRUSH_LIFE_LEVEL = "main_brush_life_level"
ATTR_SIDE_BRUSH_LIFE_LEVEL = "side_brush_life_level"
ATTR_FILTER_LIFE_LEVEL = "filter_life_level"
SUPPORT_XIAOMI = (
SUPPORT_STATE
| SUPPORT_BATTERY
| SUPPORT_LOCATE
| SUPPORT_RETURN_HOME
| SUPPORT_START
| SUPPORT_STOP
| SUPPORT_PAUSE
| SUPPORT_FAN_SPEED
)
STATE_CODE_TO_STATE = {
1: STATE_IDLE,
2: STATE_CLEANING,
3: STATE_PAUSED,
4: STATE_ERROR,
5: STATE_DOCKED,
6: STATE_RETURNING,
}
SPEED_CODE_TO_NAME = {
0: "Silent",
1: "Standard",
2: "Strong",
3: "Turbo",
}
ERROR_CODE_TO_ERROR = {
0: "NoError",
1: "Left_wheel_motor",
2: "Right_wheel_motor",
3: "Cliff",
4: "Battery_low",
5: "Bumper",
6: "Brush",
7: "Side_brush",
8: "Fan",
9: "Dustbin",
10: "Charging",
11: "No_wate",
12: "Pick_up",
}
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""Set up the Xiaomi vacuum cleaner robot platform."""
if DATA_KEY not in hass.data:
hass.data[DATA_KEY] = {}
host = config.get(CONF_HOST)
token = config.get(CONF_TOKEN)
name = config.get(CONF_NAME)
# Create handler
_LOGGER.info("Initializing with host %s (token %s...)", host, token)
vacuum = MyVacuum(host, token)
mirobo = MiroboVacuum(name, vacuum)
hass.data[DATA_KEY][host] = mirobo
async_add_entities([mirobo], update_before_add=True)
class MiroboVacuum(StateVacuumEntity):
"""Representation of a Xiaomi Vacuum cleaner robot."""
def __init__(self, name, vacuum):
"""Initialize the Xiaomi vacuum cleaner robot handler."""
self._name = name
self._vacuum = vacuum
self._fan_speeds = None
self._fan_speeds_reverse = None
self.vacuum_state = None
self.vacuum_error = None
self.battery_percentage = None
self._current_fan_speed = None
self._main_brush_life_level = None
self._side_brush_life_level = None
self._filter_life_level = None
self._cleaning_area = None
self._cleaning_time = None
@property
def name(self):
"""Return the name of the device."""
return self._name
@property
def state(self):
"""Return the status of the vacuum cleaner."""
if self.vacuum_state is not None:
try:
return STATE_CODE_TO_STATE[int(self.vacuum_state)]
except KeyError:
_LOGGER.error(
"STATE_CODE not supported: %s",
self.vacuum_state,
)
return None
@property
def error(self):
"""Return the error of the vacuum cleaner."""
if self.vacuum_error is not None:
try:
return ERROR_CODE_TO_ERROR.get(self.vacuum_error, "Unknown")
except KeyError:
_LOGGER.error(
"ERROR_CODE not supported: %s",
self.vacuum_error,
)
return None
@property
def battery_level(self):
"""Return the battery level of the vacuum cleaner."""
if self.vacuum_state is not None:
return self.battery_percentage
@property
def fan_speed(self):
"""Return the fan speed of the vacuum cleaner."""
if self.vacuum_state is not None:
speed = self._current_fan_speed
if speed in self._fan_speeds_reverse:
return SPEED_CODE_TO_NAME.get(self._current_fan_speed, "Unknown")
_LOGGER.debug("Unable to find reverse for %s", speed)
return speed
@property
def fan_speed_list(self):
"""Get the list of available fan speed steps of the vacuum cleaner."""
return list(self._fan_speeds_reverse)
@property
def device_state_attributes(self):
"""Return the specific state attributes of this vacuum cleaner."""
if self.vacuum_state is not None:
return {
ATTR_STATUS: STATE_CODE_TO_STATE[int(self.vacuum_state)],
ATTR_ERROR: ERROR_CODE_TO_ERROR.get(self.vacuum_error, "Unknown"),
ATTR_FAN_SPEED: SPEED_CODE_TO_NAME.get(self._current_fan_speed, "Unknown"),
ATTR_MAIN_BRUSH_LIFE_LEVEL: self._main_brush_life_level,
ATTR_SIDE_BRUSH_LIFE_LEVEL: self._side_brush_life_level,
ATTR_FILTER_LIFE_LEVEL: self._filter_life_level,
ATTR_CLEANING_AREA: self._cleaning_area,
ATTR_CLEANING_TIME: self._cleaning_time,
}
@property
def supported_features(self):
"""Flag vacuum cleaner robot features that are supported."""
return SUPPORT_XIAOMI
async def _try_command(self, mask_error, func, *args, **kwargs):
"""Call a vacuum command handling error messages."""
try:
await self.hass.async_add_executor_job(partial(func, *args, **kwargs))
return True
except DeviceException as exc:
_LOGGER.error(mask_error, exc)
return False
async def async_locate(self, **kwargs):
"""Locate the vacuum cleaner."""
await self._try_command("Unable to locate the botvac: %s", self._vacuum.find)
async def async_start(self):
"""Start or resume the cleaning task."""
await self._try_command(
"Unable to start the vacuum: %s", self._vacuum.start)
async def async_stop(self, **kwargs):
"""Stop the vacuum cleaner."""
await self._try_command("Unable to stop: %s", self._vacuum.stop)
async def async_pause(self):
"""Pause the cleaning task."""
await self._try_command("Unable to set start/pause: %s", self._vacuum.stop)
async def async_return_to_base(self, **kwargs):
"""Set the vacuum cleaner to return to the dock."""
await self._try_command("Unable to return home: %s", self._vacuum.return_home)
async def async_set_fan_speed(self, fan_speed, **kwargs):
"""Set fan speed."""
if fan_speed in self._fan_speeds_reverse:
fan_speed = self._fan_speeds_reverse[fan_speed]
else:
try:
fan_speed = int(fan_speed)
except ValueError as exc:
_LOGGER.error(
"Fan speed step not recognized (%s). Valid speeds are: %s",
exc,
self.fan_speed_list,
)
return
await self._try_command(
"Unable to set fan speed: %s", self._vacuum.set_fan_speed, fan_speed)
def update(self):
"""Fetch state from the device."""
try:
state = self._vacuum.status()
self.vacuum_state = state.status
self.vacuum_error = state.error
self._fan_speeds = SPEED_CODE_TO_NAME
self._fan_speeds_reverse = {v: k for k, v in self._fan_speeds.items()}
self.battery_percentage = state.battery
self._current_fan_speed = state.fan_speed
self._main_brush_life_level = state.brush_life_level
self._side_brush_life_level = state.side_brush_life_level
self._filter_life_level = state.filter_life_level
self._cleaning_area = state.clean_area
self._cleaning_time = state.clean_time
except OSError as exc:
_LOGGER.error("Got OSError while fetching the state: %s", exc)
In Home Assistant you can integrate cleaner with custom MioT Auto integration (available in HACS)
In Home Assistant you can integrate cleaner with custom MioT Auto integration (available in HACS)
Perfect thank you!
Hello, is there any news about support for this device?
I am using a custom component for home assistant based on python-miio.
Class for sending commands.
from .miot_device import MiotDevice class MyVacuum(MiDevice): @command() def status(self) -> Status: status = Status() response = self.send('get_properties', [{"siid": 2, "piid": 1}, {"siid": 2, "piid": 2}, {"siid": 2, "piid": 6}, {"siid": 3, "piid": 1}, {"siid": 9, "piid": 2}, {"siid": 9, "piid": 1}, {"siid": 14, "piid": 1}, {"siid": 15, "piid": 1}, {"siid": 11, "piid": 1}]) status.error = response[1]["value"] status.status = response[0]["value"] status.battery = response[3]["value"] status.fan_speed = response[2]["value"] status.clean_time = response[4]["value"] status.clean_area = response[5]["value"] status.brush_life_level = response[6]["value"] status.side_brush_life_level = response[7]["value"] status.filter_life_level = response[8]["value"] return status def call_action(self, siid, aiid, params=None): if params is None: params = [] payload = { "did": f"call-{siid}-{aiid}", "siid": siid, "aiid": aiid, } return self.send("action", payload) @command(click.argument("speed", type=int)) def set_fan_speed(self, speed): """Set fan speed""" return self.send('set_properties', [{"siid": 2, "piid": 6, "value": speed}]) @command() def return_home(self) -> None: """aiid 1 Start Charge: in: [] -> out: []""" return self.call_action(2, 3) @command() def start(self) -> None: """Start cleaning.""" return self.call_action(2, 1) @command() def stop(self) -> None: """Stop cleaning.""" return self.call_action(2, 2) @command() def find(self) -> None: """Find the robot.""" return self.call_action(6, 1)
Below modified vacuum class in ...config\custom_components\xiaomi_vacuum.
"""Xiaomi Vacuum""" from functools import partial import logging import voluptuous as vol from .miio import MyVacuum, DeviceException from homeassistant.components.vacuum import ( PLATFORM_SCHEMA, SUPPORT_STATE, SUPPORT_BATTERY, SUPPORT_LOCATE, SUPPORT_PAUSE, SUPPORT_RETURN_HOME, SUPPORT_START, SUPPORT_STOP, SUPPORT_FAN_SPEED, STATE_CLEANING, STATE_IDLE, STATE_PAUSED, STATE_RETURNING, STATE_DOCKED, STATE_ERROR, StateVacuumEntity, ) from homeassistant.const import CONF_HOST, CONF_NAME, CONF_TOKEN from homeassistant.helpers import config_validation as cv, entity_platform _LOGGER = logging.getLogger(__name__) DEFAULT_NAME = "Xiaomi Vacuum cleaner" DATA_KEY = "vacuum.xiaomi_vacuum" PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( { vol.Required(CONF_HOST): cv.string, vol.Required(CONF_TOKEN): vol.All(str, vol.Length(min=32, max=32)), vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, }, extra=vol.ALLOW_EXTRA, ) ATTR_STATUS = "status" ATTR_ERROR = "error" ATTR_FAN_SPEED = "fan_speed" ATTR_CLEANING_TIME = "cleaning_time" ATTR_CLEANING_AREA = "cleaning_area" ATTR_MAIN_BRUSH_LIFE_LEVEL = "main_brush_life_level" ATTR_SIDE_BRUSH_LIFE_LEVEL = "side_brush_life_level" ATTR_FILTER_LIFE_LEVEL = "filter_life_level" SUPPORT_XIAOMI = ( SUPPORT_STATE | SUPPORT_BATTERY | SUPPORT_LOCATE | SUPPORT_RETURN_HOME | SUPPORT_START | SUPPORT_STOP | SUPPORT_PAUSE | SUPPORT_FAN_SPEED ) STATE_CODE_TO_STATE = { 1: STATE_IDLE, 2: STATE_CLEANING, 3: STATE_PAUSED, 4: STATE_ERROR, 5: STATE_DOCKED, 6: STATE_RETURNING, } SPEED_CODE_TO_NAME = { 0: "Silent", 1: "Standard", 2: "Strong", 3: "Turbo", } ERROR_CODE_TO_ERROR = { 0: "NoError", 1: "Left_wheel_motor", 2: "Right_wheel_motor", 3: "Cliff", 4: "Battery_low", 5: "Bumper", 6: "Brush", 7: "Side_brush", 8: "Fan", 9: "Dustbin", 10: "Charging", 11: "No_wate", 12: "Pick_up", } async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Xiaomi vacuum cleaner robot platform.""" if DATA_KEY not in hass.data: hass.data[DATA_KEY] = {} host = config.get(CONF_HOST) token = config.get(CONF_TOKEN) name = config.get(CONF_NAME) # Create handler _LOGGER.info("Initializing with host %s (token %s...)", host, token) vacuum = MyVacuum(host, token) mirobo = MiroboVacuum(name, vacuum) hass.data[DATA_KEY][host] = mirobo async_add_entities([mirobo], update_before_add=True) class MiroboVacuum(StateVacuumEntity): """Representation of a Xiaomi Vacuum cleaner robot.""" def __init__(self, name, vacuum): """Initialize the Xiaomi vacuum cleaner robot handler.""" self._name = name self._vacuum = vacuum self._fan_speeds = None self._fan_speeds_reverse = None self.vacuum_state = None self.vacuum_error = None self.battery_percentage = None self._current_fan_speed = None self._main_brush_life_level = None self._side_brush_life_level = None self._filter_life_level = None self._cleaning_area = None self._cleaning_time = None @property def name(self): """Return the name of the device.""" return self._name @property def state(self): """Return the status of the vacuum cleaner.""" if self.vacuum_state is not None: try: return STATE_CODE_TO_STATE[int(self.vacuum_state)] except KeyError: _LOGGER.error( "STATE_CODE not supported: %s", self.vacuum_state, ) return None @property def error(self): """Return the error of the vacuum cleaner.""" if self.vacuum_error is not None: try: return ERROR_CODE_TO_ERROR.get(self.vacuum_error, "Unknown") except KeyError: _LOGGER.error( "ERROR_CODE not supported: %s", self.vacuum_error, ) return None @property def battery_level(self): """Return the battery level of the vacuum cleaner.""" if self.vacuum_state is not None: return self.battery_percentage @property def fan_speed(self): """Return the fan speed of the vacuum cleaner.""" if self.vacuum_state is not None: speed = self._current_fan_speed if speed in self._fan_speeds_reverse: return SPEED_CODE_TO_NAME.get(self._current_fan_speed, "Unknown") _LOGGER.debug("Unable to find reverse for %s", speed) return speed @property def fan_speed_list(self): """Get the list of available fan speed steps of the vacuum cleaner.""" return list(self._fan_speeds_reverse) @property def device_state_attributes(self): """Return the specific state attributes of this vacuum cleaner.""" if self.vacuum_state is not None: return { ATTR_STATUS: STATE_CODE_TO_STATE[int(self.vacuum_state)], ATTR_ERROR: ERROR_CODE_TO_ERROR.get(self.vacuum_error, "Unknown"), ATTR_FAN_SPEED: SPEED_CODE_TO_NAME.get(self._current_fan_speed, "Unknown"), ATTR_MAIN_BRUSH_LIFE_LEVEL: self._main_brush_life_level, ATTR_SIDE_BRUSH_LIFE_LEVEL: self._side_brush_life_level, ATTR_FILTER_LIFE_LEVEL: self._filter_life_level, ATTR_CLEANING_AREA: self._cleaning_area, ATTR_CLEANING_TIME: self._cleaning_time, } @property def supported_features(self): """Flag vacuum cleaner robot features that are supported.""" return SUPPORT_XIAOMI async def _try_command(self, mask_error, func, *args, **kwargs): """Call a vacuum command handling error messages.""" try: await self.hass.async_add_executor_job(partial(func, *args, **kwargs)) return True except DeviceException as exc: _LOGGER.error(mask_error, exc) return False async def async_locate(self, **kwargs): """Locate the vacuum cleaner.""" await self._try_command("Unable to locate the botvac: %s", self._vacuum.find) async def async_start(self): """Start or resume the cleaning task.""" await self._try_command( "Unable to start the vacuum: %s", self._vacuum.start) async def async_stop(self, **kwargs): """Stop the vacuum cleaner.""" await self._try_command("Unable to stop: %s", self._vacuum.stop) async def async_pause(self): """Pause the cleaning task.""" await self._try_command("Unable to set start/pause: %s", self._vacuum.stop) async def async_return_to_base(self, **kwargs): """Set the vacuum cleaner to return to the dock.""" await self._try_command("Unable to return home: %s", self._vacuum.return_home) async def async_set_fan_speed(self, fan_speed, **kwargs): """Set fan speed.""" if fan_speed in self._fan_speeds_reverse: fan_speed = self._fan_speeds_reverse[fan_speed] else: try: fan_speed = int(fan_speed) except ValueError as exc: _LOGGER.error( "Fan speed step not recognized (%s). Valid speeds are: %s", exc, self.fan_speed_list, ) return await self._try_command( "Unable to set fan speed: %s", self._vacuum.set_fan_speed, fan_speed) def update(self): """Fetch state from the device.""" try: state = self._vacuum.status() self.vacuum_state = state.status self.vacuum_error = state.error self._fan_speeds = SPEED_CODE_TO_NAME self._fan_speeds_reverse = {v: k for k, v in self._fan_speeds.items()} self.battery_percentage = state.battery self._current_fan_speed = state.fan_speed self._main_brush_life_level = state.brush_life_level self._side_brush_life_level = state.side_brush_life_level self._filter_life_level = state.filter_life_level self._cleaning_area = state.clean_area self._cleaning_time = state.clean_time except OSError as exc: _LOGGER.error("Got OSError while fetching the state: %s", exc)
Thank you very much!!
Hello, I am coming here to see if you can help me starting the vacuum from the command line interface from a debian where the python module miio has been installed. I have the IP address, the token and the Device ID. The device ID has been obtained by using a little executable from my windows computer.
If i use the command :
miiocli device --ip 192.168.98.56 --token 89QS7D897SQ8D789QS7D8SQ789D7QS info
I do have this answer :
Model: mijia.vacuum.v2 Hardware version: esp32 Firmware version: 2.0.8
The model is well the Mop Essential - MJSTG1
I did try the following lines
miiocli device --ip 192.168.98.56 --token 89QS7D897SQ8D789QS7D8SQ789D7QS raw_command "method":"action","params":{"did":"56445231231","siid":2,"aiid":1}
miiocli vacuum --ip 192.168.98.56 --token 89QS7D897SQ8D789QS7D8SQ789D7QS raw_command "method":"action","params":{"did":"56445231231","siid":2,"aiid":1}
Gives me the following error :
Traceback (most recent call last):
File "/usr/local/bin/miiocli", line 10, in <module>
sys.exit(create_cli())
File "/usr/local/lib/python3.7/dist-packages/miio/cli.py", line 63, in create_cli
return cli(auto_envvar_prefix="MIIO")
File "/usr/local/lib/python3.7/dist-packages/miio/click_common.py", line 59, in __call__
return self.main(*args, **kwargs)
File "/usr/local/lib/python3.7/dist-packages/click/core.py", line 782, in main
rv = self.invoke(ctx)
File "/usr/local/lib/python3.7/dist-packages/click/core.py", line 1259, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/usr/local/lib/python3.7/dist-packages/click/core.py", line 1257, in invoke
sub_ctx = cmd.make_context(cmd_name, args, parent=ctx)
File "/usr/local/lib/python3.7/dist-packages/click/core.py", line 700, in make_context
self.parse_args(ctx, args)
File "/usr/local/lib/python3.7/dist-packages/click/core.py", line 1048, in parse_args
value, args = param.handle_parse_result(ctx, opts, args)
File "/usr/local/lib/python3.7/dist-packages/click/core.py", line 1623, in handle_parse_result
value = self.full_process_value(ctx, value)
File "/usr/local/lib/python3.7/dist-packages/click/core.py", line 1589, in full_process_value
value = self.process_value(ctx, value)
File "/usr/local/lib/python3.7/dist-packages/click/core.py", line 1579, in process_value
return self.type_cast_value(ctx, value)
File "/usr/local/lib/python3.7/dist-packages/click/core.py", line 1568, in type_cast_value
return _convert(value, (self.nargs != 1) + bool(self.multiple))
File "/usr/local/lib/python3.7/dist-packages/click/core.py", line 1565, in _convert
return self.type(value, self, ctx)
File "/usr/local/lib/python3.7/dist-packages/click/types.py", line 46, in __call__
return self.convert(value, param, ctx)
File "/usr/local/lib/python3.7/dist-packages/miio/click_common.py", line 107, in convert
return ast.literal_eval(value)
File "/usr/lib/python3.7/ast.py", line 46, in literal_eval
node_or_string = parse(node_or_string, mode='eval')
File "/usr/lib/python3.7/ast.py", line 35, in parse
return compile(source, filename, mode, PyCF_ONLY_AST)
File "<unknown>", line 1
method:action,params:siid:2
^
SyntaxError: invalid syntax
I also did try this lines :
miiocli device --ip 192.168.98.56 --token 89QS7D897SQ8D789QS7D8SQ789D7QS raw_command app_start
miiocli vacuum --ip 192.168.98.56 --token 89QS7D897SQ8D789QS7D8SQ789D7QS raw_command app_start
mirobo device --ip 192.168.98.56 --token 89QS7D897SQ8D789QS7D8SQ789D7QS raw_command app_start
That gives me the following error
Running command raw_command
Error: {'code': -9999, 'message': 'undefined command'}
So i do understand that the method:action seems to not be well written, but I did not succeed on finding the good way. I have read the documentation without success also.
Thanks if you can give me some help on this.
This should be supported now with #867 being merged so I'm closing this. @TaGGoU91 please try the current git master, miiocli g1vacuum
should work without raw commands.
To execute custom actions, you cannot use mirobo nor miiocli device (but miiocli miotdevice
should work):
$ miiocli miotdevice --ip 127.0.0.1 --token 12341234123412341234123412341234 call_action_by --help
WARNING:miio.miot_device:Neither the class nor the parameter defines the mapping
Usage: miiocli miotdevice call_action_by [OPTIONS] SIID AIID [PARAMS]
Call an action.
where SIID
and AIID
are required (and params is the payload, if needed).
Hi,
I have an issue getting a token:
miiocli discover
INFO:miio.miioprotocol:Sending discovery to <broadcast> with timeout of 5s..
INFO:miio.miioprotocol: IP 192.168.0.248 (ID: 1d670515) - token: b'ffffffffffffffffffffffffffffffff'
The device is found on the correct IP address, but the token returned does not work, obviously. Any ideas?
Before submitting a new request, use the search to see if there is an existing issue for the device.
Device information:
Use
miiocli device --ip <ip address> --token <token>
.Model: mijia.vacuum.v1 Hardware version: esp32 Firmware version: 2.1.3