Closed Asdertila closed 5 years ago
Looks like it uses a different protocol, so someone needs to find out what commands it supports.
What does mirobo discover
report?
Unfortunately, the device I had only a few days on the test and I can not explore it in more detail. What I managed to find, dig into device plugin 13653.apk
Thanks for getting back with some info!
Prefixing the methods can be done easily, however, we need a way to detect the device type and what are the supported features, which may require some refactoring.
File contents for future reference:
{
"voice_pkg_version": 2,
"voice_push_pic":"https://awsbj0.fds.api.xiaomi.com/sapphire/app/voice-pkg/pic/banner.png",
"voice_list": [
{
"voice_id":1,
"version":1,
"applicable":["prc", "tw", "us", "de"],
"lang":"prc",
"default":"prc",
"voice_pri": 1,
"bg_pic": "https://awsbj0.fds.api.xiaomi.com/sapphire/app/voice-pkg/pic/biaozhun.png",
"voice_title": "标准普通话版",
"voice_sub_title": "经典女声",
"voice_pkg_url": "https://awsbj0.fds.api.xiaomi.com/sapphire/app/voice-pkg/package/chinese.pkg",
"voice_pkg_md5": "37d6bd928a4b0ba9123fa7f0b06f971e",
"voice_pre_listen": "https://awsbj0.fds.api.xiaomi.com/sapphire/app/voice-pkg/pre_listen/pre_listen_dalu.wav"
},
{
"voice_id":3,
"version":1,
"applicable":["prc", "tw", "us", "de", "kr"],
"lang":"en",
"voice_pri": 3,
"bg_pic": "https://awsbj0.fds.api.xiaomi.com/sapphire/app/voice-pkg/pic/eng_ch.png",
"voice_title": "English",
"voice_sub_title": "female voice",
"voice_pkg_url": "https://awsbj0.fds.api.xiaomi.com/sapphire/app/voice-pkg/package/english.pkg",
"voice_pkg_md5": "37d6bd928a4b0ba9123fa7f0b06f971e",
"voice_pre_listen": "https://awsbj0.fds.api.xiaomi.com/sapphire/app/voice-pkg/pre_listen/pre_listen_eng.wav"
},
{
"voice_id":105,
"version":1,
"applicable":["prc", "tw"],
"voice_pri": 105,
"bg_pic": "https://awsbj0.fds.api.xiaomi.com/sapphire/app/voice-pkg/pic/transformer.png",
"voice_title": "机器人版",
"voice_sub_title": "重金属音",
"voice_pkg_url": "https://awsbj0.fds.api.xiaomi.com/sapphire/app/voice-pkg/package/transformer.pkg",
"voice_pkg_md5": "fc8f45999775089449019df9dbc3b2a9",
"voice_pre_listen": "https://awsbj0.fds.api.xiaomi.com/sapphire/app/voice-pkg/pre_listen/transformer_pre_listen.wav"
},
{
"voice_id":104,
"version":1,
"applicable":["prc", "tw"],
"voice_pri": 104,
"bg_pic": "https://awsbj0.fds.api.xiaomi.com/sapphire/app/voice-pkg/pic/ertong.png",
"voice_title": "动漫儿童版",
"voice_sub_title": "吼吼吼,我要开始扫地喽~",
"voice_pkg_url": "https://awsbj0.fds.api.xiaomi.com/sapphire/app/voice-pkg/package/labixiaoxin.pkg",
"voice_pkg_md5": "8219e3b6a1cde9701dd40ceb8ab1c2df",
"voice_pre_listen": "https://awsbj0.fds.api.xiaomi.com/sapphire/app/voice-pkg/pre_listen/pre_listen_xiaoxin.wav"
},
{
"voice_id":103,
"version":1,
"applicable":["prc", "tw"],
"voice_pri": 103,
"bg_pic": "https://awsbj0.fds.api.xiaomi.com/sapphire/app/voice-pkg/pic/pinifei.png",
"voice_title": "后宫嫔妃版",
"voice_sub_title": "本宫例行巡视时间到~",
"voice_pkg_url": "https://awsbj0.fds.api.xiaomi.com/sapphire/app/voice-pkg/package/concubine.pkg",
"voice_pkg_md5": "efb18a0fb464813851cb3a14d64e8006",
"voice_pre_listen": "https://awsbj0.fds.api.xiaomi.com/sapphire/app/voice-pkg/pre_listen/pre_listen_hougong.wav"
},
{
"voice_id":102,
"version":1,
"applicable":["prc", "tw"],
"voice_pri": 102,
"bg_pic": "https://awsbj0.fds.api.xiaomi.com/sapphire/app/voice-pkg/pic/mengmei.png",
"voice_title": "萌妹子版",
"voice_sub_title": "宝宝开始清扫喽~",
"voice_pkg_url": "https://awsbj0.fds.api.xiaomi.com/sapphire/app/voice-pkg/package/cutegirl.pkg",
"voice_pkg_md5": "67e957e6f86941319129f1951fe34ae0",
"voice_pre_listen": "https://awsbj0.fds.api.xiaomi.com/sapphire/app/voice-pkg/pre_listen/pre_listen_mengmei.wav"
},
{
"voice_id":101,
"version":1,
"applicable":["prc", "tw"],
"voice_pri": 101,
"bg_pic": "https://awsbj0.fds.api.xiaomi.com/sapphire/app/voice-pkg/pic/boyinyuan.png",
"voice_title": "播音员版",
"voice_sub_title": "标准男声",
"voice_pkg_url": "https://awsbj0.fds.api.xiaomi.com/sapphire/app/voice-pkg/package/coolman.pkg",
"voice_pkg_md5": "64d0f49ed56bec4dd38ea89d8a2f55d1",
"voice_pre_listen": "https://awsbj0.fds.api.xiaomi.com/sapphire/app/voice-pkg/pre_listen/pre_listen_boyinyuan.wav"
},
{
"voice_id":100,
"version":1,
"applicable":["prc", "tw"],
"voice_pri": 100,
"bg_pic": "https://awsbj0.fds.api.xiaomi.com/sapphire/app/voice-pkg/pic/yueyu.png",
"voice_title": "粤语版",
"voice_sub_title": "你今日扫佐地未呀?",
"voice_pkg_url": "https://awsbj0.fds.api.xiaomi.com/sapphire/app/voice-pkg/package/cantonese.pkg",
"voice_pkg_md5": "062e3f7a95adb789de333c443d4d9024",
"voice_pre_listen": "https://awsbj0.fds.api.xiaomi.com/sapphire/app/voice-pkg/pre_listen/pre_llisten_yueyu.wav"
}
]
}
Methods for Xiaowa E20 from device 13653.apk
.class public Lcom/rockrobo/utils/Constants;
.super Ljava/lang/Object;
# static fields
.field public static final AGREE_USER_ACCESS_PROTOCOL_PREF_KEY:Ljava/lang/String; = "user_access_protocol_"
.field public static final AGREE_USER_IMPROVE_PLAN_PREF_KEY:Ljava/lang/String; = "user_improve_plan_"
.field public static final APP_BUCKET_NAME:Ljava/lang/String; = "sapphire"
.field public static final BUTTON_DISABLE_ALPHA:F = 0.38f
.field public static final BUTTON_ENABLE_ALPHA:F = 1.0f
.field public static final CALL_METHOD_JSON_OBJECT_API_LEVEL:I = 0x1d
.field public static final CLEAN_MODE_PREF_KEY:Ljava/lang/String; = "clean_mode_"
.field public static final CLEAR_MAP_SHARE_FILE_NAME:Ljava/lang/String; = "sapphire_map_share.jpeg"
.field public static final COMMON_RETRY_CNT:I = 0x7
.field public static final COMMON_RETRY_CNT_3:I = 0x3
.field public static final CURRENT_SOUND_LANGUAGE_KEY:Ljava/lang/String; = "language"
.field public static final CURRENT_SOUND_LOCATION_KEY:Ljava/lang/String; = "location"
.field public static final EVENT_BACK_TO_DOCK:Ljava/lang/String; = "event.back_to_dock"
.field public static final EVENT_BACK_TO_DOCK_NEARBY:Ljava/lang/String; = "event.back_to_dock_nearby"
.field public static final EVENT_BACK_TO_ORIGIN_FAIL:Ljava/lang/String; = "event.back_to_origin_fail"
.field public static final EVENT_BACK_TO_ORIGIN_SUCCESS:Ljava/lang/String; = "event.back_to_origin_succ"
.field public static final EVENT_BIN_FULL:Ljava/lang/String; = "event.bin_full"
.field public static final EVENT_CLEAN_COMPLETE:Ljava/lang/String; = "event.clean_complete"
.field public static final EVENT_ERROR_CODE:Ljava/lang/String; = "event.error_code"
.field public static final EVENT_FIND_ME_STOPPED:Ljava/lang/String; = "event.find_me_stopped"
.field public static final EVENT_LOW_POWER_BACK:Ljava/lang/String; = "event.low_power_back"
.field public static final EVENT_NO_DISTURB_END:Ljava/lang/String; = "event.no_disturb_end"
.field public static final EVENT_NO_DISTURB_START:Ljava/lang/String; = "event.no_disturb_start"
.field public static final EVENT_POWER_RESUME_CLEAN:Ljava/lang/String; = "event.power_resume_clean"
.field public static final EVENT_RELOCATE_FAIL:Ljava/lang/String; = "event.relocate_fail"
.field public static final EVENT_STATUS:Ljava/lang/String; = "event.status"
.field public static final EVENT_TIMED_CLEAN_END:Ljava/lang/String; = "event.robot_timed_ended"
.field public static final EVENT_TIMED_CLEAN_START:Ljava/lang/String; = "event.robot_timed_started"
.field public static final FDS_APP_ACCESS_KEY_ENCODED:Ljava/lang/String; = "NTE2MTc1MTEyNDMzMQ=="
.field public static final FDS_APP_ACCESS_SECRET_ENCODED:Ljava/lang/String; = "S01IV2p4bzRwNGZucktiTzl6c1JCUT09"
.field public static final FDS_BEIJING_CDN_HOST:Ljava/lang/String; = "cdn.awsbj0.fds.api.mi-img.com"
.field public static final FDS_BEIJING_HOST:Ljava/lang/String; = "awsbj0.fds.api.xiaomi.com"
.field public static final FDS_SINGAPORE_HOST:Ljava/lang/String; = "awssgp0.fds.api.xiaomi.com"
.field public static final FULL_FAN_POWER:I = 0x64
.field public static final GET_GLOBAL_SERVER_INFO2_API_LEVEL:I = 0x3c
.field public static final GET_GLOBAL_SERVER_INFO_API_LEVEL:I = 0x16
.field public static final LICENSE_AGREE:Ljava/lang/String; = "Y"
.field public static final LICENSE_CONTENT_PREF_KEY_PREFIX:Ljava/lang/String; = "user_access_protocol_content_key_"
.field public static final LOCAL_PING_API_LEVEL:I = 0x20
.field public static final LOG_LEVEL_ACCEPT_USER_IMPROVE_PLAN:I = 0xf
.field public static final LOG_LEVEL_DENY_USER_IMPROVE_PLAN:I = 0xb
.field public static final LOG_LEVEL_NONE:I = 0x0
.field public static final LOG_LEVEL_UNKNOWN:I = -0x6f
.field public static final LOG_UPLOAD_STATUS_PREF_KEY:Ljava/lang/String; = "log_upload_status"
.field public static final MAP_STORE_DIR:Ljava/lang/String; = "rr_map_store"
.field public static final METHOD_APP_GET_LOCALE:Ljava/lang/String; = "app_get_locale"
.field public static final METHOD_CHARGE:Ljava/lang/String; = "user.app_charge"
.field public static final METHOD_CLEAR_CLEAN_RECORDS:Ljava/lang/String; = "clear_clean_records"
.field public static final METHOD_CLOSE_DND_TIMER:Ljava/lang/String; = "user.close_dnd_timer"
.field public static final METHOD_DEL_TIMER:Ljava/lang/String; = "user.del_timer"
.field public static final METHOD_ENABLE_LOG_UPLOAD:Ljava/lang/String; = "user.enable_log_upload"
.field public static final METHOD_FIND_ME:Ljava/lang/String; = "user.find_me"
.field public static final METHOD_GET_CARPET_MODE:Ljava/lang/String; = "user.get_carpet_mode"
.field public static final METHOD_GET_CLEAN_RECORD:Ljava/lang/String; = "user.get_clean_record"
.field public static final METHOD_GET_CLEAN_RECORD_MAP:Ljava/lang/String; = "user.get_clean_record_map"
.field public static final METHOD_GET_CLEAN_SUMMARY:Ljava/lang/String; = "user.get_clean_summary"
.field public static final METHOD_GET_CONSUMABLE:Ljava/lang/String; = "user.get_consumable"
.field public static final METHOD_GET_CURRENT_SOUND:Ljava/lang/String; = "user.get_current_sound"
.field public static final METHOD_GET_DND_TIMER:Ljava/lang/String; = "user.get_dnd_timer"
.field public static final METHOD_GET_FW_FEATURES:Ljava/lang/String; = "get_fw_features"
.field public static final METHOD_GET_LOG_LEVEL:Ljava/lang/String; = "user.get_log_upload_status"
.field public static final METHOD_GET_MAP_V1:Ljava/lang/String; = "user.get_map"
.field public static final METHOD_GET_SERIAL_NUMBER:Ljava/lang/String; = "user.get_serial_number"
.field public static final METHOD_GET_SOUND_PROGRESS:Ljava/lang/String; = "get_sound_progress"
.field public static final METHOD_GET_STATUS:Ljava/lang/String; = "user.get_status"
.field public static final METHOD_GET_TIMER:Ljava/lang/String; = "user.get_timer"
.field public static final METHOD_GET_TIMEZONE:Ljava/lang/String; = "user.get_timezone"
.field public static final METHOD_GET_VOLUME:Ljava/lang/String; = "get_sound_volume"
.field public static final METHOD_INSTALL_SOUND:Ljava/lang/String; = "user.dnld_install_sound"
.field public static final METHOD_PARAM_FILTER_WORK_TIME:Ljava/lang/String; = "user.filter_work_time"
.field public static final METHOD_PARAM_MAIN_BRUSH_WORK_TIME:Ljava/lang/String; = "user.main_brush_work_time"
.field public static final METHOD_PARAM_SENSORS_MAINTAIN_WORK_TIME:Ljava/lang/String; = "user.sensor_dirty_time"
.field public static final METHOD_PARAM_SIDE_BRUSH_WORK_TIME:Ljava/lang/String; = "user.side_brush_work_time"
.field public static final METHOD_PAUSE:Ljava/lang/String; = "user.app_pause"
.field public static final METHOD_RESET_CONSUMABLE:Ljava/lang/String; = "user.reset_consumable"
.field public static final METHOD_SET_CARPET_MODE:Ljava/lang/String; = "user.set_carpet_mode"
.field public static final METHOD_SET_CUSTOM_MODE:Ljava/lang/String; = "user.set_custom_mode"
.field public static final METHOD_SET_DND_TIMER:Ljava/lang/String; = "user.set_dnd_timer"
.field public static final METHOD_SET_TIMER:Ljava/lang/String; = "user.set_timer"
.field public static final METHOD_SET_TIMEZONE:Ljava/lang/String; = "user.set_timezone"
.field public static final METHOD_SET_VOLUME:Ljava/lang/String; = "change_sound_volume"
.field public static final METHOD_SPOT:Ljava/lang/String; = "user.app_spot"
.field public static final METHOD_START:Ljava/lang/String; = "user.app_start"
.field public static final METHOD_TEST_VOLUME:Ljava/lang/String; = "test_sound_volume"
.field public static final METHOD_UPD_TIMER:Ljava/lang/String; = "user.upd_timer"
.field public static final METHOD_WAKE_UP:Ljava/lang/String; = "miIO.wake_up_mcu"
.field public static final MODEL_V1:Ljava/lang/String; = "roborock.vacuum.e2"
.field public static final MODEL_V2:Ljava/lang/String; = "roborock.sweeper.e2v2"
.field public static final MODEL_V3:Ljava/lang/String; = "roborock.sweeper.e2v3"
.field public static final MOP_FAN_POWER:I = 0x29
.field public static final MSG_NUMBER_UP_LIMIT:I = 0x3e8
.field public static final MSG_RESULT_KEY:Ljava/lang/String; = "result"
.field public static final MSG_STATUS_STATE_KEY:Ljava/lang/String; = "state"
.field public static final MSG_STATUS_VERSION_KEY:Ljava/lang/String; = "msg_ver"
.field public static final NO_DISTURB_END_HOUR_PREF_KEY:Ljava/lang/String; = "no_disturb_end_hour"
.field public static final NO_DISTURB_END_MINUTE_PREF_KEY:Ljava/lang/String; = "no_disturb_end_minute"
.field public static final NO_DISTURB_START_HOUR_PREF_KEY:Ljava/lang/String; = "no_disturb_start_hour"
.field public static final NO_DISTURB_START_MINUTE_PREF_KEY:Ljava/lang/String; = "no_disturb_start_minute"
.field public static final NO_DISTURB_SWITCH_PREF_KEY:Ljava/lang/String; = "no_disturb_switch"
.field public static final POWER_FAN_POWER:I = 0x4f
.field public static final PRIVACY_POLICY_CONTENT_PREF_KEY_PREFIX:Ljava/lang/String; = "privacy_policy_content_pref_key_"
.field public static final PUSH_SWITCH_PREF_KEY:Ljava/lang/String; = "push_switch"
.field public static final RC_RESULT_CODE:I = 0x1
.field public static final RC_TYPE_PREF_KEY_PREFIX:Ljava/lang/String; = "rc_type_"
.field public static final REMOTE_CMD_EXPIRE_DURATION:I = 0x1f4
.field public static final RESOURCE_ID_UNKNOWN:I = -0x1
.field public static final ROBOT_MSG_VERSION_FIRMWARE_FEATURES:I = 0x8
.field public static final ROBOT_MSG_VERSION_NONE:I = 0x0
.field public static final ROBOT_MSG_VERSION_TIME_ZONE_MODIFY:I = 0x6
.field public static final ROBOT_VELOCITY:D = 0.3
.field public static final RR_SHARED_PREF_KEY:Ljava/lang/String; = "rockrobo"
.field public static final SERIAL_NO_PREF_PREF_KEY:Ljava/lang/String; = "serial_number_"
.field public static final SILENT_FAN_POWER:I = 0x32
.field public static final STANDARD_FAN_POWER:I = 0x44
.field public static final TEST_VOICE_PKG_INFO_OBJ_PATH_PREFIX:Ljava/lang/String; = "app/voice-pkg/debug/info"
.field public static final TIME_ZONE_SAVE_KEY_PREFIX:Ljava/lang/String; = "time_zone_save_key_"
.field public static final TimeZoneConfigFileName:Ljava/lang/String; = "tz.json"
.field public static final USER_GUIDE_PREF_KEY:Ljava/lang/String; = "user_guide_"
.field public static final USER_IMPROVE_PLAN_ACCEPT:Ljava/lang/String; = "ACCEPT"
.field public static final USER_IMPROVE_PLAN_DENY:Ljava/lang/String; = "DENY"
.field public static final USER_IMPROVE_PLAN_UNKNOWN:Ljava/lang/String; = "UNKNOWN"
.field public static final VOICE_PKG_CURRENT_VP_ID_PREFIX:Ljava/lang/String; = "voice_pkg_current_vp_id_"
.field public static final VOICE_PKG_CUR_VOICE_VERSION_PREFIX:Ljava/lang/String; = "voice_pkg_cur_voice_version_"
.field public static final VOICE_PKG_INFO_OBJ_PATH_PREFIX:Ljava/lang/String; = "app/voice-pkg/info"
.field public static final XM_LICENSE_DIALOG_API_LEVEL:I = 0x30
.field public static final XM_UPDATE_DEVICE_API_LEVEL:I = 0x1b
# direct methods
.method public constructor <init>()V
.locals 0
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
Hello guys, Today I received my shiny new Xiaowa E352 vacuum and once again I had to say I should just read more informations before ordering. I found some amazing howtos for rooting the vacuum with custom firmware, pushing live maps to other systems like HomeAssistant, but today, after spending few hours in search of manual, I found out that these new vacuums use completely another system and probably it could not be rooted like the gen 2. I found out that the communication module is from espressif so some esp8266 or esp32 is onboard, and the vacuum itself is communicating with some amazon AWS server ( in my case Europe servers set in Mi home app)
And my question here is , do you have some new progress with decrypting messages from these new devices ? Or better, can I help somehow with supporting this process ? thanks
Trying to connect to new Roborock Xiaowa E20 - getting an error. Unfortunately I can not exactly confirm - the problem is in my environment or the protocol has changed in the new version. There are no previous generation devices for testing.
mirobo --ip=192.168.0.102 --token=233fa59afbccfda0f9e47ca7fb74a906 --debug status INFO:miio.vacuum_cli:Debug mode active DEBUG:miio.vacuum_cli:Connecting to 192.168.0.102 with token 233fa59afbccfda0f9e47ca7fb74a906 DEBUG:miio.protocol:Unable to decrypt, returning raw bytes: b'' DEBUG:miio.device: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\x03k\x99\x7f\x00\x01\x03\x93' (total 16) value = Container: length = 32 unknown = 0 device_id = b'\x03k\x99\x7f' (total 4) ts = 1970-01-01 18:27:31 offset1 = 0 offset2 = 16 length = 16 checksum = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' (total 16) DEBUG:miio.device:Discovered 036b997f with ts: 1970-01-01 18:27:31, token: b'00000000000000000000000000000000' DEBUG:miio.device:192.168.0.102:54321 >>: {'id': 1, 'method': 'get_status'} DEBUG:miio.device:192.168.0.102:54321 (ts: 1970-01-01 18:27:31, id: 1) << {'id': 1, 'error': {'code': -32600, 'message': 'Req object invalid.'}} DEBUG:miio.click_common:Exception: {'code': -32600, 'message': 'Req object invalid.'} Traceback (most recent call last): File "/usr/local/lib/python3.6/dist-packages/miio/click_common.py", line 54, in call return self.main(args, kwargs) File "/usr/local/lib/python3.6/dist-packages/click/core.py", line 697, in main rv = self.invoke(ctx) File "/usr/local/lib/python3.6/dist-packages/click/core.py", line 1066, in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) File "/usr/local/lib/python3.6/dist-packages/click/core.py", line 895, in invoke return ctx.invoke(self.callback, ctx.params) File "/usr/local/lib/python3.6/dist-packages/click/core.py", line 535, in invoke return callback(args, kwargs) File "/usr/local/lib/python3.6/dist-packages/click/decorators.py", line 64, in new_func return ctx.invoke(f, obj, *args[1:], *kwargs) File "/usr/local/lib/python3.6/dist-packages/click/core.py", line 535, in invoke return callback(args, kwargs) File "/usr/local/lib/python3.6/dist-packages/miio/vacuum_cli.py", line 106, in status res = vac.status() File "/usr/local/lib/python3.6/dist-packages/miio/vacuum.py", line 164, in status return VacuumStatus(self.send("get_status")[0]) File "/usr/local/lib/python3.6/dist-packages/miio/device.py", line 270, in send raise DeviceError(m.data.value["error"]) miio.exceptions.DeviceError: {'code': -32600, 'message': 'Req object invalid.'} Error: {'code': -32600, 'message': 'Req object invalid.'}