Support for Roidmi NEX2 Pro
spupetic opened this issue · 14 comments
Hi!
The Roidmi cordless vacuum cleaners use BLE to communicate with the Xiaomi Home app, they need a connection to work. I have tried to get data via the method what works for the Mi Kettle (device ID), but I think that this device uses different method for authorization / encryption. I have extracted some data from the Xiaomi Cloud, the device ID is apparently 2145, but I am not sure about that, it did not work. There is also a token (24 chars. long) and a BLE key (32 chars. long).
The communication is described in the Xiaomi Home app plugin's source code, which is available here:
https://home.miot-spec.com/download-plugin/roidmi.cleaner.v382
The Bluetooth function can be used to view usage data, battery life, battery standby time and expected usage time, read error messages, set default motor speed and reset filter life.
UPD: extracted javascript https://gist.githubusercontent.com/devbis/8d43f97d1bf47831e38ed31d35f0529a/raw/roidmi.cleaner.v382.js
Can you please attach the file to this issue? I can't load the link
Of course.
roidmi.cleaner.v382.zip
Will you be able to test dev builds with this device? because I don't have one and it's hard to create an implementation without feedback
Yes, I will. Thank you.
I added an initial support with a part of possible sensors implemented.
Can you please install if from a branch and tell me if it works or send me logs.
pip3 install -U https://github.com/devbis/ble2mqtt/archive/refs/heads/roidme.zip --no-cache-dir --force-reinstall
Thank you very much for the initial support! It seems like something is happening, I get some data:
2024-01-21 23:54:27 INFO: [Roidmi_Vacuum_cleaner_mac] send state={'linkquality': None, 'state': 'unknown', 'voltage': 3303, 'battery': 100, 'total_use_seconds': 10326843, 'total_clean_seconds': 158087, 'hepa_used_seconds': 158087, 'speed_level': 'Medium'}
But I also get some errors, and and at some point, ble2mqtt crashes:
2024-01-22 00:01:10 INFO: Connected to MAC
2024-01-22 00:01:10 ERROR: Cannot connect to device Roidmi_ROIDMI_VC_3A_MAC
Traceback (most recent call last):
File "/home/pi/.local/lib/python3.7/site-packages/ble2mqtt/devices/base.py", line 147, in _read_with_timeout
**get_loop_param(self._loop),
File "/usr/lib/python3.7/asyncio/tasks.py", line 416, in wait_for
return fut.result()
File "/home/pi/.local/lib/python3.7/site-packages/bleak/__init__.py", line 637, in read_gatt_char
return await self._backend.read_gatt_char(char_specifier, **kwargs)
File "/home/pi/.local/lib/python3.7/site-packages/bleak/backends/bluezdbus/client.py", line 723, in read_gatt_char
char_specifier
bleak.exc.BleakError: Characteristic with UUID 00002a26-0000-1000-8000-00805f9b34fb could not be found!
2024-01-22 00:01:10 WARNING: Roidmi_Vacuum_cleaner_MAC name: Vacuum cleaner, version: V0.1.3
2024-01-22 00:01:11 WARNING: Roidmi_Vacuum_cleaner_MAC initial state: CleanerState(battery=100, voltage=3300, total_use_seconds=10327227, numeric_display_type=100, total_clean_seconds=158087, hepa_used_seconds=158087, speed_level=<SpeedOption.Medium: 80>, low_speed_lv_power=2560, state=<CleanerStateEnum.UNKNOWN: 'unknown'>)
2024-01-22 00:01:11 INFO: [Roidmi_Vacuum_cleaner_MAC] send state={'linkquality': None, 'state': 'unknown', 'voltage': 3300, 'battery': 100, 'total_use_seconds': 10327227, 'total_clean_seconds': 158087, 'hepa_used_seconds': 158087, 'speed_level': 'Medium'}
2024-01-22 00:01:11 WARNING: state_notification_handler: Roidmi_Vacuum_cleaner_MAC notification: 0000ffd2-0000-1000-8000-00805f9b34fb (Handle: 32): Vendor specific: a2 54 51 55 0c e4 02 92
2024-01-22 00:01:11 WARNING: voltage_notification_handler: Roidmi_Vacuum_cleaner_MAC notification: 0000ffd1-0000-1000-8000-00805f9b34fb (Handle: 28): Vendor specific: 42 0c e5 64 0a 00 01 a7
2024-01-22 00:01:12 WARNING: Error while connecting to Roidmi_Vacuum_cleaner_MAC, 'int' object has no attribute 'name' AttributeError("'int' object has no attribute 'name'"), failure_count=1
2024-01-22 00:01:12 WARNING: state_notification_handler: Roidmi_Vacuum_cleaner_MAC notification: 0000ffd2-0000-1000-8000-00805f9b34fb (Handle: 32): Vendor specific: a2 54 51 55 0c e4 02 92
2024-01-22 00:01:12 WARNING: voltage_notification_handler: Roidmi_Vacuum_cleaner_MAC notification: 0000ffd1-0000-1000-8000-00805f9b34fb (Handle: 28): Vendor specific: 42 0c e8 64 0a 00 01 aa
2024-01-22 00:01:12 WARNING: voltage_notification_handler: Roidmi_Vacuum_cleaner_MAC notification: 0000ffd1-0000-1000-8000-00805f9b34fb (Handle: 28): Vendor specific: 42 0c e8 64 0a 00 01 aa
2024-01-22 00:01:13 WARNING: state_notification_handler: Roidmi_Vacuum_cleaner_MAC notification: 0000ffd2-0000-1000-8000-00805f9b34fb (Handle: 32): Vendor specific: a2 54 51 55 0c e4 02 92
2024-01-22 00:01:13 WARNING: voltage_notification_handler: Roidmi_Vacuum_cleaner_MAC notification: 0000ffd1-0000-1000-8000-00805f9b34fb (Handle: 28): Vendor specific: 42 0c e7 64 0a 00 01 a9
2024-01-22 00:01:22 INFO: Connected to MAC
2024-01-22 00:01:22 ERROR: Cannot connect to device Roidmi_ROIDMI_VC_3A_MAC
It tries to restart Bluetooth:
2024-01-22 00:08:39 WARNING: Restarting bluetoothd...
Can't down device hci0: Operation not permitted (1)
[....] Restarting bluetooth (via systemctl): bluetooth.service==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ===
Authentication is required to restart 'bluetooth.service'.
Authenticating as: ,,, (pi)
Password: 2024-01-22 00:08:40 WARNING: Error while connecting to Roidmi_Vacuum_cleaner_MAC, failed to discover services, device disconnected BleakError('failed to discover services, device disconnected'), failure_count=2
2024-01-22 00:08:40 ERROR: Connection lost. Will retry in 10 seconds.
Traceback (most recent call last):
File "/home/pi/.local/lib/python3.7/site-packages/ble2mqtt/ble2mqtt.py", line 302, in _connect_mqtt_forever
await self._run_device_tasks(mqtt_connection.disconnect_reason)
File "/home/pi/.local/lib/python3.7/site-packages/ble2mqtt/ble2mqtt.py", line 273, in _run_device_tasks
await handle_returned_tasks(*finished)
File "/home/pi/.local/lib/python3.7/site-packages/ble2mqtt/tasks.py", line 79, in handle_returned_tasks
await task_for_raise
File "/home/pi/.local/lib/python3.7/site-packages/ble2mqtt/manager.py", line 427, in manage_device
async with BLUETOOTH_RESTARTING:
File "/usr/lib/python3.7/asyncio/locks.py", line 92, in __aenter__
await self.acquire()
File "/usr/lib/python3.7/asyncio/locks.py", line 192, in acquire
await fut
RuntimeError: Task <Task pending coro=<DeviceManager.manage_device() running at /home/pi/.local/lib/python3.7/site-packages/ble2mqtt/manager.py:427> cb=[_wait.<locals>._on_completion() at /usr/
I will check tomorrow, if the data is the same as in the app.
I have not supplied any authentication data. Is that needed? Isn't encryption used like with other Xiaomi ecosystem devices?
I made some updates according to the log. Can you please reinstall with the same command?
Thanks a lot, now it works very well, the data is correct, only the voltage displays without decimal places, it says 3300 V. The sensor what is missing is the total clean area, and the ability to reset the HEPA filter life. But more importantly, when an error happens, the device only displays a small graphics, and the error's description message can be found in the app. It would be really useful to implement such messages as well:
else if (cUUID == 'FFD6') {
if (bytes[0] == 0xa6) {
deviceInfoModel.dustAbnormalValue = bytes[1];
deviceInfoModel.brushAbnormalValue = bytes[2];
deviceInfoModel.dustFullAbnormalValue = bytes[3];
deviceInfoModel.tempHightAbnormalValue = bytes[4];
if (deviceInfoModel.brushAbnormalValue == 0x54) {
deviceInfoModel.brushAbnormalValue = kVCErrorCode.MotorAbnormal;
}
(0, _RMLog.default)("dustAbnormalValue: " + deviceInfoModel.dustAbnormalValue);
(0, _RMLog.default)("brushAbnormalValue: " + deviceInfoModel.brushAbnormalValue);
(0, _RMLog.default)("dustFullAbnormalValue: " + deviceInfoModel.dustFullAbnormalValue);
(0, _RMLog.default)("tempHightAbnormalValue: " + deviceInfoModel.tempHightAbnormalValue);
this.updateWarningCode();
}
....
var kVCErrorCode = {
OK: 0x51,
DustUnInstall: 0x54,
BrushBlocked: 0x52,
BrushDischarge: 0x53,
MotorAbnormal: 0x3857,
DustFull: 0x55,
TemperatureHigh: 0x56,
MIFDateout: 0xf9,
Unknown: 0x9999
};
Thank you again!
I added an error sensor and a button to reset hepa. Though, the button is a new entity for this app, so please, test it
Additionally, I removed the voltage sensor in favor of battery percentage as I don't know if it is a real volts * 1000.
The filter reset function works as expected, and the HEPA duration left percentage is really useful, also the actual power, because as I have tried, the low_speed_power sets power in real time, while the device is operating (which is new to me, I did not know, that it is possible to change the vacuum power remotely while cleaning). The total clean area sensor is also accurate. Yeah, the voltage sensor is not needed, the battery percentage is more useful and precise. Thanks a lot!
Update: The error detection is not working, I have had a BrushBlocked error, and the device showed that it sent data to the app, but in HA, it stayed 'OK' without a change.
@spupetic I'm sorry, I forgot to subscribe to error updates. Now it is in the branch, can you please check it once again?
Can you please append logs to get more information on notifications' meta data (handles and characteristics).
It's okay, thanks for the update, now the error notifications are working fine.
2024-01-25 00:04:04 WARNING: Roidmi_ROIDMI_VC_3A_mac initial state: CleanerState(battery=100, voltage=3309, total_use_seconds=10481133, numeric_display_type=100, total_clean_seconds=158407, hepa_used_seconds=17, speed_level=<SpeedOption.Low: 'Low'>, low_speed_lv_power=<SpeedLvPower._60W: 2550>, state=<CleanerStateEnum.UNKNOWN: 'unknown'>, dust_abnormal_value=<ErrorCode.OK: 81>, brush_abnormal_value=<ErrorCode.BrushBlocked: 82>, dust_full_abnormal_value=<ErrorCode.OK: 81>, temp_high_abnormal_value=<ErrorCode.OK: 81>)
2024-01-25 00:04:05 INFO: [Roidmi_ROIDMI_VC_3A_mac] send state={'linkquality': None, 'state': 'unknown', 'battery': 100, 'mif_duration_left': 99, 'total_use_seconds': 10481133, 'total_clean_seconds': 158407, 'total_clean_area': 2112, 'hepa_used_seconds': 17, 'actual_power': '60W', 'error': 'BrushBlocked'}
2024-01-25 00:04:05 WARNING: state_notification_handler: Roidmi_ROIDMI_VC_3A_mac notification: 0000ffd2-0000-1000-8000-00805f9b34fb (Handle: 32): Vendor specific: a2 54 51 55 10 68 02 1a
2024-01-25 00:04:05 WARNING: voltage_notification_handler: Roidmi_ROIDMI_VC_3A_mac notification: 0000ffd1-0000-1000-8000-00805f9b34fb (Handle: 28): Vendor specific: 42 0c eb 64 0a 00 01 ad
...
2024-01-25 00:16:10 INFO: [Roidmi_ROIDMI_VC_3A_mac] send state={'linkquality': None, 'state': 'charging', 'battery': 99, 'mif_duration_left': 99, 'total_use_seconds': 10481581, 'total_clean_seconds': 158630, 'total_clean_area': 2115, 'hepa_used_seconds': 240, 'actual_power': '60W', 'error': 'OK'}
2024-01-25 00:16:10 WARNING: state_notification_handler: Roidmi_ROIDMI_VC_3A_mac notification: 0000ffd2-0000-1000-8000-00805f9b34fb (Handle: 32): Vendor specific: a2 54 51 55 09 f6 02 a1
2024-01-25 00:16:10 WARNING: voltage_notification_handler: Roidmi_ROIDMI_VC_3A_mac notification: 0000ffd1-0000-1000-8000-00805f9b34fb (Handle: 28): Vendor specific: 42 0c ff 63 0a 00 01 c0
Thanks again.