Kevo Plus door locks now working in Home Assistant

I re-enabled the component and restarted my hass setup at 10:50am CST. After reviewing the logs, I began receiving the following error on my front door at 11:28am CST. Oddly, the back lock is still functioning as expected.

2018-02-01 11:28:04 ERROR (MainThread) [homeassistant.helpers.entity] Update for lock.front_door fails
Traceback (most recent call last):
  File "/srv/hass/lib/python3.5/site-packages/homeassistant/helpers/entity.py", line 199, in async_update_ha_state
    yield from self.async_device_update()
  File "/srv/hass/lib/python3.5/site-packages/homeassistant/helpers/entity.py", line 306, in async_device_update
    yield from self.hass.async_add_job(self.update)
  File "/usr/lib/python3.5/asyncio/futures.py", line 380, in __iter__
    yield self  # This tells Task to wait for completion.
  File "/usr/lib/python3.5/asyncio/tasks.py", line 304, in _wakeup
    future.result()
  File "/usr/lib/python3.5/asyncio/futures.py", line 293, in result
    raise self._exception
  File "/usr/lib/python3.5/concurrent/futures/thread.py", line 55, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/srv/hass/lib/python3.5/site-packages/homeassistant/components/lock/kevo.py", line 69, in update
    self._state = self._kevo.GetBoltState().lower()
  File "/srv/hass/lib/python3.5/site-packages/pykevoplus/__init__.py", line 108, in _wrapped
    return method(self, *args, **kwargs)
  File "/srv/hass/lib/python3.5/site-packages/pykevoplus/__init__.py", line 272, in GetBoltState
    self.Refresh()
  File "/srv/hass/lib/python3.5/site-packages/pykevoplus/__init__.py", line 108, in _wrapped
    return method(self, *args, **kwargs)
  File "/srv/hass/lib/python3.5/site-packages/pykevoplus/__init__.py", line 223, in Refresh
    raise KevoError("Error getting lock info: {}".format(info_result.text))
pykevoplus.KevoError: Error getting lock info: {"status":"500","error":"Internal Server Error"}

That’s really strange. I’m not seeing that issue at all. My HA has been running for over 100 hours straight and I can still control both my locks with no issues. Also, since pykevoplus is the intermediate between the component and Kevo, the issue is somehow stemming there. I really don’t know what’s going on.

I’m just as lost as you are. Like I said previously, I’m running a couple python scripts every 30 seconds to check the lock status and separate scripts for locking and unlocking. They’re just interacting directly with pykevoplus and returning the response to hass. They haven’t been affected by the issue at all, but they log in separately every single time, rather than using the same session. Pykevoplus doesn’t pass on any useragent strings to kwikset, so I’m uncertain as to how they’re blocking only the kevo component, but not the python library.

from pykevoplus import KevoLock
lock = KevoLock.FromLockID("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "***USERNAME***", "***PASSWORD***")
print(lock.GetBoltState())

Hi Helpful People,

This Kevo stuff really interests me, I am setting up a new home assistant (hassio) on a pi zero, and would really like to see my two kevo locks (and I have a bridge). I found your git Bahnburner and have been working through setting up my hue lights and my motion sensors etc. but I can’t really follow the locks. if nothing else I have the feeling there are some python files that aren’t in the git.

Any chance of a full walk through of how everything fits together and what is needed?

Thanks,

You are correct that there are a few python scripts that aren’t included in my github. The reason for that is because of the way pykevoplus works, the scripts to check status and send lock/unlock requests contain not only the lockID, but also my Kevo username and password. I posted a walkthrough previously with step by step instructions on how to get things up and running, but it was quite some time ago, so I don’t fault you for being unable to find it.

Here’s a direct link.

You’re basically going to install the pykevocontrol library, get your lockIDs and then create a status, lock and unlock script for each lock. The scripts are called by a command line switch. The scan_interval line controls how frequently the locks are polled for their state.

Also, you can replace the first step with

pip3 install pykevocontrol

It’s a bit faster.

Thanks Bahnburner, I will look tonight after work and see if I can get it running.

No problem.

I think I can’t do this, I am using Hass.io, so can’t install python? am I reading this right?

Hmm, installing appDaemon, will see how I go, might take a bit more thinking

I do not believe you can use the scripts if you’re using Hass.io, however, you should be able to use the custom component I created (hopefully you don’t get the same issue that @Bahnburner has). If it works for you, it’s a very quick and easy integration.

OK I got the component working but I am getting the internal 500 error that are mentioned above. will keep looking.

The 500 error seems interesting. I actually just got the error myself but my lock status is still updating and I can control them. I don’t have any clue what’s going on.

I am unsure, but for me it got the status the first time, wouldn’t let me control the locks and then would just fill up the log with the 500 error. I tried using the python_scripts.xxx mechanism in hassio with Bahnburner’s code after your component installed all the dependencies, but that didn’t work, I assume that the imports need to be pointing at the right place, but I don’t know how to do that.

been busy here, but will look at the appdaemon tonight as it allows full python scripts.

Hey All, I have tried a few different things, and finally got something working today. Still got work to do but thought it better if I shared it here to let people comment if I am doing anything weird (as I am not a python programmer). This is built to go in the apps directory of appdaemon, after you have got hold of pykevoplus v2 and installed it and its dependencies, you copy the pykevoplus and bs4 directories into the appdaemon/apps directory and you should be right to go. you can then create as many app instances in the app.yaml (I haven’t shared this as it has my keys etc. in it). I have got one lock working and just debugging the other, still get the server 500 occasionally, but as it isn’t polling anything yet it is rare. Obviously this has issues as I don’t know if anyone plays with the lock manually yet. If you can recommend a way to do the polling that would be good.

Anyway hopefully this helps someone.

import appdaemon.plugins.hass.hassapi as hass
from pykevoplus import KevoLock

class DoorLock(hass.Hass):

lock_id = ""
k_user = ""
k_pass = ""
switch_name = ""
a_lock = ""

def initialize(self):
    global lock_id
    lock_id = self.args["lock_id"]
    global k_user
    k_user = self.args["k_user"]
    global k_pass
    k_pass = self.args["k_pass"]
    global switch_name
    switch_name = 'binary_sensor.' + self.args["switch_name"]
    global a_lock
    a_lock = KevoLock.FromLockID(lock_id, k_user, k_pass)

    self.set_state( switch_name, state= a_lock.GetBoltState())
    self.listen_state(self.watcher,  switch_name)

def watcher(self, entity, attribute, old, new, kwargs):

    self.log(entity + " " + old + " " + new)

    if entity == switch_name and new == "Locked" and a_lock.GetBoltState() == "Unlocked":
        a_lock.Lock()
    elif entity == switch_name and new == "Unlocked" and a_lock.GetBoltState() == "Locked":
        a_lock.Unlock()

    self.set_state(switch_name, state= a_lock.GetBoltState())

you will then get a binary_sensor.xxxx (what ever you call it in the apps.yaml file) with the state polled. you can also set the state manually (through input select or whatever) and it will lock or unlock the door.

I will state at the outset that all this is because of Bahnburner and gaggle331, I have just played about with their ideas and hard work. My many thanks go to those skilled individuals.

I have got the whole lot working in appdaemon, with IFTTT webhooks to provide a more ‘real-time’ connection. Here are the steps if anyone needs it for use in Hass.io

First install appdaemon v3 & the ssh component using the following Git - GitHub - hassio-addons/repository: Home Assistant Community Add-ons

Then once you have started the service, you will get an appdaemon folder in your config directory.

follow the instructions to turn on apps in the appdaemon.yaml file.

In the apps directory, in the apps.yaml file you will need to add in the following (one per lock)

    front-lock:
      module: locks
      class: DoorLockF
      lock_id: "YOUR LOCK ID"
      k_user: "YOUR KEVO USERNAME"
      k_pass: "YOUR KEVO PASSWORD"
      select_name: "xxxxx"

you need an input_select.xxxxx setup (in your config file) that looks like (one per lock)

xxxxx:
  name: Front Door
  options:
    - Locked
    - Unlocked
  initial: Locked
  icon: mdi:key-variant 

using ssh (add in the component from the repository) into your server, (/usr/bin/pip3) to install Bahnburner’s code

This will install them to /usr/lib/python3.6/site-packages/pykevoplus
or use
$ find / -name pykevoplus

use
$ cp -R /usr/lib/python3.6/site-packages/pykevoplus /config/appdaemon/apps
$ cp -R /usr/lib/python3.6/site-packages/bs4 /config/appdaemon/apps

then, in the apps directory in the appdaemon folder create a “kevo” folder

create a file called locks.py (I actually have a separate file for each lock, locksf.py, locksg.py) as the instances seemed to be getting mixed up

copy in the following code (same exact code for each file, all the differences are in the apps.yaml)

import appdaemon.plugins.hass.hassapi as hass
import datetime
from pykevoplus import KevoLock

class DoorLockF(hass.Hass):

    lock_id = ""
    k_user = ""
    k_pass = ""
    select_name = ""
    a_lock = ""

    def initialize(self):
        global lock_id
        lock_id = self.args["lock_id"]
        global k_user
        k_user = self.args["k_user"]
        global k_pass
        k_pass = self.args["k_pass"]
        global select_name
        select_name = 'input_select.' + self.args["select_name"]
        global a_lock
        a_lock = KevoLock.FromLockID(lock_id, k_user, k_pass)
 
        self.set_state(select_name, state= a_lock.GetBoltState())
        self.listen_state(self.changer,  select_name)
        ti = datetime.datetime.now()
        self.run_every(self.mode_status, ti, 15 * 60)
                  
    def changer(self, entity, attribute, old, new, kwargs):

        self.log("change " + entity + " " + select_name + " " + old + " " + new)

        if entity == select_name and new == "Locked" and a_lock.GetBoltState() == "Unlocked":
            a_lock.Lock()
        elif entity == select_name and new == "Unlocked" and a_lock.GetBoltState() == "Locked":
            a_lock.Unlock()

        self.set_state(select_name, state= a_lock.GetBoltState())
        
    def mode_status(self, kwargs):

        self.log("called updated")

        self.set_state(select_name, state= a_lock.GetBoltState())

this now has a check of every 15 minutes to see what the status of the locks is, as well as watching your input select control, and adjusting the lock to match the control. (it is relatively slow (10-20 seconds) but it works)

to do the real time stuff with IFTTT

You need to turn on api calls into the system, add to your configuration file

api:

You can then setup the webhooks IFTTT integration using the how to on the site. and then add the following in your recipe (2 receipes per lock);

https://YOUR_DOMAIN.duckdns.org:8123/api/states/input_select.xxxxxx?api_password=YOUR PASSWORD

As a POST with the following body

{“state”:“Unlocked”}
or
{“state”:“Locked”}


OK hopefully that helps someone else get this stuff running on Hass.io (I tried a few times with the component, but I continued to get the 500 errors and couldn’t control the locks).

Please note that all of this is down to Bahnburner and gaggle331. All the credit goes to those helpful people, and my many thanks, I have learnt a huge amount about this platform over the last few weeks, and without the help and examples and instructions I would have probably given up.

I’ve still been having problems with my kevo lock updating, and its getting worse. Almost as soon as I restart my HA (I’m running Hasbian), I get an error in the logs. The first error is always due to an auth token problem. Then each subsequent attempt to update fails due to a 500 error. I am able to replicate this via command line python if I request an update status rapid fire 10 or so times in a row. So if we can fix the initial auth token problem the other errors shouldn’t occur. Any suggestions?

Initial error:

Mon Mar 26 2018 14:40:21 GMT-0400 (Eastern Daylight Time)

Update for lock.side_door fails
Traceback (most recent call last):
  File "/srv/homeassistant/lib/python3.5/site-packages/homeassistant/helpers/entity.py", line 199, in async_update_ha_state
    yield from self.async_device_update()
  File "/srv/homeassistant/lib/python3.5/site-packages/homeassistant/helpers/entity.py", line 306, in async_device_update
    yield from self.hass.async_add_job(self.update)
  File "/usr/lib/python3.5/asyncio/futures.py", line 380, in __iter__
    yield self  # This tells Task to wait for completion.
  File "/usr/lib/python3.5/asyncio/tasks.py", line 304, in _wakeup
    future.result()
  File "/usr/lib/python3.5/asyncio/futures.py", line 293, in result
    raise self._exception
  File "/usr/lib/python3.5/concurrent/futures/thread.py", line 55, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/home/homeassistant/.homeassistant/custom_components/lock/kevo.py", line 68, in update
    self._state = self._kevo.GetBoltState().lower()
  File "/srv/homeassistant/lib/python3.5/site-packages/pykevoplus/__init__.py", line 105, in _wrapped
    Kevo.Login(self.session, self.username, self.password)
  File "/srv/homeassistant/lib/python3.5/site-packages/pykevoplus/__init__.py", line 59, in Login
    token = Kevo.GetAuthToken(session)
  File "/srv/homeassistant/lib/python3.5/site-packages/pykevoplus/__init__.py", line 46, in GetAuthToken
    raise KevoError("Could not find auth token on signin page")
pykevoplus.KevoError: Could not find auth token on signin page




Next error and each subsequent error:

Mon Mar 26 2018 14:40:52 GMT-0400 (Eastern Daylight Time)

Update for lock.side_door fails
Traceback (most recent call last):
  File "/srv/homeassistant/lib/python3.5/site-packages/homeassistant/helpers/entity.py", line 199, in async_update_ha_state
    yield from self.async_device_update()
  File "/srv/homeassistant/lib/python3.5/site-packages/homeassistant/helpers/entity.py", line 306, in async_device_update
    yield from self.hass.async_add_job(self.update)
  File "/usr/lib/python3.5/asyncio/futures.py", line 380, in __iter__
    yield self  # This tells Task to wait for completion.
  File "/usr/lib/python3.5/asyncio/tasks.py", line 304, in _wakeup
    future.result()
  File "/usr/lib/python3.5/asyncio/futures.py", line 293, in result
    raise self._exception
  File "/usr/lib/python3.5/concurrent/futures/thread.py", line 55, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/home/homeassistant/.homeassistant/custom_components/lock/kevo.py", line 68, in update
    self._state = self._kevo.GetBoltState().lower()
  File "/srv/homeassistant/lib/python3.5/site-packages/pykevoplus/__init__.py", line 108, in _wrapped
    return method(self, *args, **kwargs)
  File "/srv/homeassistant/lib/python3.5/site-packages/pykevoplus/__init__.py", line 272, in GetBoltState
    self.Refresh()
  File "/srv/homeassistant/lib/python3.5/site-packages/pykevoplus/__init__.py", line 108, in _wrapped
    return method(self, *args, **kwargs)
  File "/srv/homeassistant/lib/python3.5/site-packages/pykevoplus/__init__.py", line 223, in Refresh
    raise KevoError("Error getting lock info: {}".format(info_result.text))
pykevoplus.KevoError: Error getting lock info: {"status":"500","error":"Internal Server Error"}

I have the same errors and I surmised the cause of the erros aren’t a token issue but a throttle MyKevo probably setup on their web server. So when I left the scan_interval setting at the default, which I think is 30 seconds, I got the error a ton, I then changed it to 240 (4 minutes) and I got the error less, earlier today I changed it to 600 (10 minutes) and I don’t get the error at all - even after reboots… so far.

I know most would probably prefer the lock status to be instant but perhaps try decreasing your scan_interval and seeing if they fixes the issues.

I think you’re right. They’re definitely taking measures to attempt to hinder our usage of this component. I’m not sure what other options we have, as I would hope their security measures would be strong enough that intercepting data from the kevo plus bridge headed to their server would be completely off the table.

Honestly, I can’t blame Kevo either. If I was running a server that had 100s of people hit it every 30 seconds 24/7 to ask for the status of their lock, which hardly ever changes, I’d be annoyed as well and take measures to reduce hits.

The ideal solution would be allowing the bridge to communicate locally with your server so we could ping that device as much as we want without leaving the network but I doubt Kevo will ever introduce that because there wouldn’t be enough demand from the masses for it.

As of today, I feel like the best solution is to keep scraping their website but be considerate and get the status update on the lock at a significantly delayed rate. Since I changed my scan time to 10 minutes I haven’t seen the error message in my logs.

1 Like

I don’t blame them either, but I have automations that just aren’t worthwhile if I move to a 10 minute polling interval.

Unikey, the company behind Kevos’s tech, showed off a zwave bridge at CES a couple years ago, but unfortunately have yet to make it available.