Eufy Robovac 35c Working with Home_Assistant - Updated 11/2020 - How To Guide - Now with Edge Cleaning!

Yeap.
I have it all set like that. No complains on the Home Assistant side apart from not showing me the device at all.
I guess that if cannot connect to the device, it will not even show on the list of devices, right?
This is what the modified Eufy APP shows me (which is the same info I get from the logcat):
image
(I blurred 4 digits on each “key”…)
My best guess tell me that the id is the “Device id” and the local key is the “Local code”, right ?
I tried running the python demo to check but it fails as I’ve explained above and in Home Assistant the device is not available.
Any ideas of where am I getting it wrong?

My modified Eufy App (from the link below) does not show my information in that form:

Dropbox - EufyHome_2.4.0_vevs.apk.zip - Simplify your life

It shows:

MAC Address
IP-address
Device ID
Local key

Your display seems to use other terms which is odd. Can you control the 11c through the app - I’m guessing you can.

My only suggestion is to post your logcat output (with any codes partially obscured with 'x’s but the right length obviously) so I can see what it contains.

This is what I got from the logcat:

09-19 23:19:55.989 23034 24243 D OkHttp  : {"res_code":1,"message":"","devices":[{"id":"238283f7-930e-****-abcb-0afeb230350b","sn":"","name":"RoboVac 11c","alias_name":"RoboVac","bluetooth":null,"wifi":{"mac":"XX.XX.XX.XX","wifi_ssid":"XXXXX","lan_ip_addr":"XXX.XXX.XXX.XXX"},"product":{"id":"1bb81bed-dd4a-XXXX-9458-0242ac130005","name":"11c","region":"US","default_name":"RoboVac","icon_url":"https://d1teb1w17vl5yo.cloudfront.net/eufyhome/products/T2103_addProductIcon.png","category":"Home","appliance":"Cleaning","connect_type":1,"pictures":[{"code":"addProductIcon","url":"https://d1teb1w17vl5yo.cloudfront.net/eufyhome/products/T2103_addProductIcon.png","description":""},{"code":"selectDeviceImage","url":"https://d1teb1w17vl5yo.cloudfront.net/eufyhome/products/T2103_selectDevice.png","description":""},{"code":"feedbackImage","url":"https://d1teb1w17vl5yo.cloudfront.net/eufyhome/products/T2103_feedback.png","description":""}],"description":"RoboVac 11c, Robotic Vacuum Cleaner","product_code":"T2103","wifi_ssid_prefix":"eufy RoboVac 11c","wifi_ssid_prefix_full":"eufy RoboVac 11c-","index":19,"create_time":1493114081,"update_time":1627876669,"is_show":false,"tuya_pid":""},"user_id":"128520","owner_info":null,"home_id":"4d3aa9a8-b547-XXXX-bab1-73000a0e59b0","home_name":"","room_id":"a46cf032-c8e4-XXXX-9c3c-5cdabf980078","room_name":"Default Room","connect_type":1,"grant_by":0,"software_version":"2.6","index":0,"device_key":"A117233C01E3XXXX","create_time":1528913714,"update_time":1528913732,"hardware_version":"","local_code":"50670B61A9F1XXXX","needUpdate":false,"setting":{"id":"","device_id":"","is_default":true},"device_status":{"device_id":"238283f7-930e-XXXX-abcb-0afeb230350b","user_id":"128520","product_code":"T2103","category":"Home","appliance":"Cleaning","update_time":1632089987,"update_time_ms":1632089987540,"sw_version":"","is_online":true,"mcu_version":"255.255","cleaning_status":{"mode":3,"points":[0,0],"direction":0,"speed":0,"stop":1,"room_mode":0,"cleanArea":0,"allArea":0,"cleanTime":0,"allTime":0,"phi":0,"battery_capacity":99,"water_tank_status":0,"find_me_status":0,"charger_status":1,"error_code":0,"wifi_rssi":0},"light_status":null,"color_light_status":null,"plug_status":null,"exists_timer":false,"current_timer":null,"away_timer":null},"update_packages":[]}],"groups":[]}

I had to dig to find this because that expression they recommend would not return anything for me.

Simplified version:

"id":"238283f7-930e-XXXX-abcb-0afeb230350b"
"id no space":"238283f7930eXXXXabcb0afeb230350b"
"lan_ip_addr":"XXX"
"product":{"id":"1bb81bed-dd4a-XXXX-9458-0242ac130005"
"product_code":"T2103"
"user_id":"128520"
"home_id":"4d3aa9a8-b547-XXXX-bab1-73000a0e59b0",
"room_id":"a46cf032-c8e4-XXXX-9c3c-5cdabf980078"
"device_key":"A117233C01E3XXXX"
"local_code":"50670B61A9F1XXXX"

That’s completely different to the Logcat output I get. When you say that the expression they recommend didn’t return anything - what expression was that?

this expression:
adb logcat -e ‘tuya.m.my.group.device.list’

I had this exact same problem.

I used the command: adb logcat -e 'tuya.m.my.group.device.list’

That expression actually didn’t produce any output on screen until I had written out the logfile using:

adb logcat -d > myfile

where ‘myfile’ is whatever filename you want. If you find that you can’t use the ‘-e’ option for whatever reason, the logfile will write to the screen and you can then cut and paste the log to Notepad or NotePad++

I’ve used this method 3-4 times and it took a lot of trial and error to get the output containing the keys.

When I use the adb above it retturns:

--------- beginning of system
--------- beginning of crash
--------- beginning of main

So I tried tho whole and cannot find it… Tried many times already … I can only get those that I’ve shown you.
In the big logcat file … What would be the exact words to look for ? “local key” ?

… and if you use adb logcat 'tuya.m.my.group.device.list’ (without the -e option) it doesn’t print anything to the screen?

The two keys are: ‘localKey’ and ‘devID’

It prints LOTs on the screen …
I tired to copy past a whole lot of it many times…
Still cant get the localkey thing
It look to me as if my communication with the eufy is all encrypted somehow …
I get a LOT of eufy encrypted this and that …
Maybe this is a new thing

If you’ve searched through all the output and not found the localKey then maybe this is something different about the 11c.

I presume you have tried this:

It references the 11c specifically.

Yeap. Tried it as well … no luck also :confused:
Well … I guess I’m out of luck with this one. Next vacuum robot in the future I’ll make sure it talks with my smart setup. xD
Thanks for the help man! I really appreciate. :wink:

That’s really annoying for you. Sorry I couldn’t help out this time.

Has anyone here managed to get the Eufy Robovac G30 (non-hybrid) to work with HA? I have the 15C Max version which works ok so far but need another for the 2nd floor :slight_smile:

Ok I picked up the G30 (model T2250) and connected it to HA but different model and here is what works so far:
image
All the commands here work but I cannot see the status or the battery % and every time I issue a command it logs this error:

2021-10-06 18:09:16 ERROR (MainThread) [homeassistant] Error doing job: Task exception was never retrieved
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 708, in _update_entity_states
    await asyncio.gather(*tasks)
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 451, in async_update_ha_state
    self._async_write_ha_state()
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 500, in _async_write_ha_state
    attr.update(self.state_attributes or {})
  File "/usr/src/homeassistant/homeassistant/components/vacuum/__init__.py", line 296, in state_attributes
    data = super().state_attributes
  File "/usr/src/homeassistant/homeassistant/components/vacuum/__init__.py", line 189, in state_attributes
    data[ATTR_BATTERY_ICON] = self.battery_icon
  File "/usr/src/homeassistant/homeassistant/components/vacuum/__init__.py", line 286, in battery_icon
    if self.status is not None:
  File "/config/custom_components/eufy_vacuum/vacuum.py", line 116, in status
    if self.robovac.error_code != robovac.ErrorCode.NO_ERROR:
  File "/config/custom_components/eufy_vacuum/property.py", line 36, in __get__
    value = self.type_cast(value)
  File "/usr/local/lib/python3.9/enum.py", line 384, in __call__
    return cls.__new__(cls, value)
  File "/usr/local/lib/python3.9/enum.py", line 702, in __new__
    raise ve_exc
ValueError: 0 is not a valid ErrorCode

I assume new code is needed to get this model to return these values and not error on the log anymore

Inside of vaccum.py there is this code:

@property
    def status(self):
        """Return the status of the vacuum cleaner."""
        if self.robovac.error_code != robovac.ErrorCode.NO_ERROR:
            return STATE_ERROR
        elif self.robovac.go_home:
            return STATE_RETURNING
        elif self.robovac.work_status == robovac.WorkStatus.RUNNING:
            return STATE_CLEANING
        elif self.robovac.work_status == robovac.WorkStatus.CHARGING:
            return STATE_DOCKED
        elif self.robovac.work_status == robovac.WorkStatus.RECHARGE_NEEDED:
            # Should be captured by `go_home` above, but just in case
            return STATE_RETURNING
        elif self.robovac.work_status == robovac.WorkStatus.SLEEPING:
            return STATE_IDLE
        elif self.robovac.work_status == robovac.WorkStatus.STAND_BY:
            return STATE_IDLE
        elif self.robovac.work_status == robovac.WorkStatus.COMPLETED:
            return STATE_DOCKED

The problem is that the 15C max has the error code as “no_error” and the new G30 just has “0”
I have tried unsuccessfully to update the code to:
self.robovac.error_code != robovac.ErrorCode.NO_ERROR or self.robovac.error_code != 0 which should account for both but still errors and no idea why.
Commenting out that whole IF statement does make the status and battery of the G30 sort of work but stuck in “returning”
image
Any ideas?

I have also commented out the “returning” part, and that gets it to work.

    @property
    def status(self):
        """Return the status of the vacuum cleaner."""
#        if self.robovac.error_code != robovac.ErrorCode.NO_ERROR:
#            return STATE_ERROR
#        elif self.robovac.go_home:
#            return STATE_RETURNING
        if self.robovac.work_status == robovac.WorkStatus.RUNNING:
            return STATE_CLEANING
        elif self.robovac.work_status == robovac.WorkStatus.CHARGING:
            return STATE_DOCKED
        elif self.robovac.work_status == robovac.WorkStatus.RECHARGE_NEEDED:
            # Should be captured by `go_home` above, but just in case
            return STATE_RETURNING
        elif self.robovac.work_status == robovac.WorkStatus.SLEEPING:
            return STATE_IDLE
        elif self.robovac.work_status == robovac.WorkStatus.STAND_BY:
            return STATE_IDLE
        elif self.robovac.work_status == robovac.WorkStatus.COMPLETED:
            return STATE_DOCKED

image

Perhaps try that ?

Hehe you beat me to it :smiley:
I actually found that myself and was going to put it here for everyone else and yeah it works fine for both my 15C max and the G30
Now if we can only find out how to send “reverse out” commands to make it come out of its batcave to be emptied.
Since the app can control it with directions there must be a way, maybe with vacuum.send_command service?

A good while ago, I had this working with my 30c and g30 Edge. I’ve recently reinstalled home assistant and have tried this integration. It all works, apart from the edge cleaning. Does anyone else have the edge cleaning working? If so, how do I go about getting it to work, as the GitHub link doesn’t appear to be valid anymore.

Update: Edge cleaning is now at this link. https://github.com/borski/eufy_robovac_edge_clean

I’m still unable to find edge_cleaning as a service though. I’ve probably missed something.

Mine is called vacuum.clean_edge did you try that?

Are you getting any of these errors in your logs?

Traceback (most recent call last):
  File "/config/custom_components/eufy_vacuum/tuya.py", line 551, in _async_handle_message
    response_data = await self.reader.readuntil(MAGIC_SUFFIX_BYTES)
  File "/usr/local/lib/python3.9/asyncio/streams.py", line 629, in readuntil
    raise exceptions.IncompleteReadError(chunk, None)