Neato Connected support


#1

I just found a python API which gives access to the neato Connected vaccum so we could launch directly from home-assistant: https://github.com/stianaske/pybotvac

If anyone wants to implement it, i don’t think it should be a big challenge, otherwise I’ll do it once I finish my work for the Netatmo Welcome camera


#2

I don’t have the ability to implement. But id be more than happy to test if required.


#4

Hi All,

I plan to start the development of this feature soon, is there something that you want in priority. For the first release, I plan to do something really simple, just a switch which will start cleaning if turn on, and return to Dock if turn OFF


#5

That’s great news @jabesq :slight_smile: it would be cool to have battery life and current status implemented. But I’m sure I’m not alone in saying I’d be hugely greatful just having the switch.

As I said before I can’t contribute with code but if there is anything I could help with please let me know.


#6

hi all,

switch is indeed a “must-have” if we implement this kind of device.
The status “working/in charge/blocked” should be a good “nice to have” I think.

If you need help, i can do my best (which is a little… but better than nothing)


#7

Hi all,

the first draft for this component is available here: https://github.com/jabesq/home-assistant/blob/02a268c9ba1b4cdd2a785d17030f97e073cfb4c8/homeassistant/components/switch/neato.py.

You can try it by putting it inside <config_directory>/custom_components/switch/

To enable it the configuration in your configuration.yaml is the following one:
switch:
platform: neato
username:
password:

This will add a switch which will start a full home cleaning when turning ON and send the robot back to base when turning OFF

PS: This currently a beta, and I have experienced a crash of home-assistant last night (don’t know yet if this is related) but use this at your own risk


#8

Hi,

I installed your script, will see next hours if it crashs my HA.

Do you have a look to https://developers.neatorobotics.com/api/ ?
seems to be easier to get data and send command to neato robot.

I just add a look to your script (in the zip) and you seems to use that doc but it was just in case :slight_smile:


#9

No, I did not use https://developers.neatorobotics.com/api/ because I did not know it was existing, I think it’s quite a new website.

I used python API which was created by someone else (https://github.com/stianaske/pybotvac) using reverse engineering, but I check this website to see if I can improve this API (which is currently doing the job fine)


#10

Extra information about my component, it has been tested only with a Neato Connected but not with the Neato botvac D3 and D5 (as I don’t have them)


#11

Thanks @jabesq I’ve just added the component and its working for me on my Neato Botvac Connected will report back any crashing.


#13

Hi,

just like to conform, for me, it is not working with botvac d3.

I take a look at the API-Documentation and found a way to get my D3 working with the existing Component, after editing the robot.py

Just read a little bit in the API-Documentation.

Heres my Code. Just had to adopt some JSON-Calls

import requests
import hmac
import time
import os.path

# Disable warning due to SubjectAltNameWarning in certificate
requests.packages.urllib3.disable_warnings()


class Robot:
    """Data and methods for interacting with a Neato Botvac Connected vacuum robot"""

    def __init__(self, serial, secret, name=''):
        """
        Initialize robot

        :param serial: Robot serial
        :param secret: Robot secret
        :param name: Name of robot (optional)
        """
        self.name = name
        self.serial = serial
        self.secret = secret

        self._url = 'https://nucleo.neatocloud.com/vendors/neato/robots/{}/messages'.format(self.serial)
        self._headers = {'Accept': 'application/vnd.neato.nucleo.v1'}

    def __str__(self):
        return "Name: %s, Serial: %s, Secret: %s" % (self.name, self.serial, self.secret)

    def _message(self, json):
        """
        Sends message to robot with data from parameter 'json'
        :param json: dict containing data to send
        :return: server response
        """

        cert_path = os.path.join(os.path.dirname(__file__), 'cert', 'neatocloud.com.crt')
        response = requests.post(self._url,
                                 json=json,
                                 verify=cert_path,
                                 auth=Auth(self.serial, self.secret),
                                 headers=self._headers)
        response.raise_for_status()
        return response

    def start_cleaning(self):
        json = {'reqId': "1",
                'cmd': "startCleaning",
                'params': {
                    'category': 2,
                    'navigationMode': 2}
                }
        return self._message(json)

    def pause_cleaning(self):
        return self._message({'reqId': "77", 'cmd': "pauseCleaning"})

    def resume_cleaning(self):
        return self._message({'reqId': "77", 'cmd': "resumeCleaning"})

    def stop_cleaning(self):
        return self._message({'reqId': "77", 'cmd': "stopCleaning"})

    def send_to_base(self):
        return self._message({'reqId': "77", 'cmd': "sendToBase"})

    def get_robot_state(self):
        return self._message({'reqId': "1", 'cmd': "getRobotState"})

    def enable_schedule(self):
        return self._message({'reqId': "1", 'cmd': "enableSchedule"})

    def disable_schedule(self):
        return self._message({'reqId': "1", 'cmd': "disableSchedule"})

    def get_schedule(self):
        return self._message({'reqId': "1", 'cmd': "getSchedule"})

    @property
    def schedule_enabled(self):
        return self.get_robot_state().json()['details']['isScheduleEnabled']

    @schedule_enabled.setter
    def schedule_enabled(self, enable):
        if enable:
            self.enable_schedule()
        else:
            self.disable_schedule()

    @property
    def state(self):
        return self.get_robot_state().json()


class Auth(requests.auth.AuthBase):
    """Create headers for request authentication"""

    def __init__(self, serial, secret):
        self.serial = serial
        self.secret = secret

    def __call__(self, request):
        date = time.strftime('%a, %d %h %Y %H:%M:%S', time.gmtime()) + ' GMT'

        signing = hmac.new(key=self.secret.encode('utf8'),
                           msg='\n'.join([self.serial.lower(), date, request.body.decode('utf8')]).encode('utf8'),
                           digestmod='sha256')

        request.headers['Date'] = date
        request.headers['Authorization'] = "NEATOAPP " + signing.hexdigest()

        return request

Any Chance to implement this to the existing Component? Or can someone with an older connected Model if this also works?

BR

Lukas


#15

When I launch my HA, I get the following error :

Feb 13 10:48:20 raspberrypi hass[2008]: INFO:homeassistant.loader:Loaded switch.neato from homeassistant.components.switch.neato
Feb 13 10:48:20 raspberrypi hass[2008]: INFO:homeassistant.bootstrap:Setting up switch
Feb 13 10:48:20 raspberrypi hass[2008]: INFO:homeassistant.components.switch:Setting up switch.neato
Feb 13 10:48:20 raspberrypi hass[2008]: ERROR:homeassistant.components.switch:Error while setting up platform neato
Feb 13 10:48:20 raspberrypi hass[2008]: Traceback (most recent call last):
Feb 13 10:48:20 raspberrypi hass[2008]: File “/srv/homeassistant/homeassistant_venv/lib/python3.4/site-packages/homeassistant/helpers/entity_component.py”, line 151, in _async_setup_platform
Feb 13 10:48:20 raspberrypi hass[2008]: entity_platform.add_entities, discovery_info
Feb 13 10:48:20 raspberrypi hass[2008]: File “/usr/lib/python3.4/asyncio/futures.py”, line 388, in iter
Feb 13 10:48:20 raspberrypi hass[2008]: yield self # This tells Task to wait for completion.
Feb 13 10:48:20 raspberrypi hass[2008]: File “/usr/lib/python3.4/asyncio/tasks.py”, line 286, in _wakeup
Feb 13 10:48:20 raspberrypi hass[2008]: value = future.result()
Feb 13 10:48:20 raspberrypi hass[2008]: File “/usr/lib/python3.4/asyncio/futures.py”, line 277, in result
Feb 13 10:48:20 raspberrypi hass[2008]: raise self._exception
Feb 13 10:48:20 raspberrypi hass[2008]: File “/usr/lib/python3.4/concurrent/futures/thread.py”, line 54, in run
Feb 13 10:48:20 raspberrypi hass[2008]: result = self.fn(*self.args, **self.kwargs)
Feb 13 10:48:20 raspberrypi hass[2008]: File “/srv/homeassistant/homeassistant_venv/lib/python3.4/site-packages/homeassistant/components/switch/neato.py”, line 26, in setup_platform
Feb 13 10:48:20 raspberrypi hass[2008]: if not hass.data[NEATO_ROBOTS]:
Feb 13 10:48:20 raspberrypi hass[2008]: KeyError: ‘neato_robots’


#16

Hi,

do you mean with my Changes?

For me its working well, i also see some errors in the Logs regarding the Neato Platform, but seems not to affect the Component or HA.


#17

not tried your change… i’ve a connected botvac, not a D3


#18

Hi
I’m new to the HA part of the automation world but I have searched for a way to integrate my Botvac D5 to my home system so that it automatically shuts off some z-wave motion sensors when the bot starts cleaning when I’m not at home and everything is armed.
Hopefully this will work =)

When I get everything set up I will test and see if this works with the D5 but I vote for a solution for the Neato component to be upgraded for all their connected models.


#19

Tested your robot.py and it works great with my D5.
How can we get the original Neato-component to be upgraded?


#20

Hi @runevad great to here it’s working for you. Since I’m not a developer I don’t really now how to do that. Maybe i have some time next wekk to investigate.

So long

Lukas


#21

@jabesq Now when the new “vacum”-component is implemented in version 0.5x it would be nice to see all of the connected series (Connected, D3 and D5) added as well.

I will look into the Neato API but I’m not a very good programmer and as @outrun said I have no idea of how to get this into the new vacum-component…

Anyone else out there, wanting to implement their Neato Botvac that could help?


#22

I would love if we could get Neato support. Now with the vacum component, i’ll hope this is something that could be done.


#23

Realise I’m jumping into an old threat but wanted to add to this discussion a request for support for the Kobold VR200 - basically a rebadged Neato. I’ve managed to find a Node script that I can get talking to it but my attempts to modify the existing Neato component have fallen flat.

Is the Neato component currently working for people who have a Neato (original - not even D3 or D5)?