Lockitron Integration

I am not sure how to integrate a fully fledged component into HASS but Lockitron has an API very similar to the existing Garadget component.

Lock:

curl -X PUT -d state=lock "https://api.lockitron.com/v2/locks/-DEVICEID-?access_token=-ACCESSTOKEN-"

Unlock:

curl -X PUT -d state=unlock "https://api.lockitron.com/v2/unlock/-DEVICEID-?access_token=-ACCESSTOKEN-"

Status:

https://api.lockitron.com/v2/locks/-DEVICEID-?access_token=-ACCESSTOKEN-

I do not know enough about Python to write code to integrate into HASS, if someone can point me in the direction to learn I do not mind trying to learn how to do it. Or if someone wants to take the ball and run with it.

just use this: https://home-assistant.io/components/cover.command_line/

I know I could use the command_line to send unlock / lock commands, but that doesn’t provide any feedback on the current lock status, unless I don’t understand how to extract that from the JSON using command_line. I’d like to be able to view status of the lock as some sensor data, for example battery power and lock status. I’ve started to learn how to use the RESTful API in Python, but I have no real experience in either so nothing will be done any time soon.

FWIW

I am able to integrate a lockitron.py into HASS, it can parse unlock or lock status and can send the command from HASS to unlock/lock. However, all of the API information is hard coded into the python code, meaning it doesn’t interact with configuration.yaml at all. I’m trying to figure out how I read the configuration.yaml to pass the acces_token and device_id to lockitron.py.

Config values generally start with CONF_ … this defines required and optional params for example… If you grep existing components you can follow the flow

    vol.Required(CONF_HOST): cv.string,
    vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
    vol.Optional(CONF_PASSWORD): cv.string,
    vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
    vol.Optional(CONF_USERNAME): cv.string,
})```

Right now I’m integrating some z-wave stuff, once I am done I’ll go ahead and post my .py. If you don’t mind taking a look. I’m sure whatever I’m doing wrong is just stupid. But this attempt at making a component is the first time I’ve ever even touched python, so don’t be too hard on me.

I’m not much further ahead of you when it comes to python or components, but sure…

This is where I am right now. I know there are defined variables that aren’t called. I’m just trying to figure out how to make it work. Essentially, I know I need to get the variables in the def setup_platform but I don’t know how to then pass them to the class to be used. If I just re-modify this and hardcode my API and Device_ID instead of trying to use variables from configuration.yaml, it works as expected. Maybe you can point me in the right direction?

https://paste.ofcode.org/34X6J89v7PUrmRKPJDvPzMT

EDIT: To elaborate I’m working on the def setup_platform , the self._apiurl = 'https://api.particle.io' isn’t correct for example. I’m just trying to figure out how to get the variables to pass them to the class.

I’m fairly certain this code is correct:

    def lock(self, **kwargs):
        """Lock the device."""
        url = '{}/v2/locks/{}?access_token={}'.format(
            self._apiurl, 
            self.device_id, 
            self.access_token)
        ret = requests.put(url,  data = {'state':'lock'})
        self._state = STATE_LOCKED
        self.schedule_update_ha_state()
        return ret.json()

If I change it to:

    def lock(self, **kwargs):
        """Lock the device."""
        url = 'apiurlhere/v2/locks/deviceidhere?access_token=accesstokenhere'
        ret = requests.put(url,  data = {'state':'lock'})
        self._state = STATE_LOCKED
        self.schedule_update_ha_state()
        return ret.json()

I can set my lock to locked / unlocked. I think the formatting of the first code snip is correct for using variables instead of having it hard coded. But I am not sure how to get the variables from configuration.yaml

For them to accept your code upstream, you’ll have to use config constants defined in const.py…

Probably CONF_DEVICE and CONF_ACCESS_TOKEN?

Then do grep -nR CONF_ACCESS_TOKEN * in the HA directory to find some component examples and copy the approach they take to reading the values.

Another update.

I can confirm this works 100% and shows up in the HASS UI. It correctly reports if the lock is unlocked/locked and you can lock/unlock from the UI. I have my own deviceID and access_token hard coded in the class section, where I have ---REDACTED---. If someone wants to help me understand how to get the variables form configuration.yaml instead of hard coding, we could add this component to HASS. I’ve been beating my head against this for 4 days and I am unable to understand how to get the configuration information from configuration.yaml.

Code: https://paste.ofcode.org/g2RsjRGxrFKGehfFiZgCfJ

Another quick update. I’m not sure if this should work… But I moved my lockitron.py into my live HASS environment (instead of my dev environment) in custom_components/lock and changed my configuration.yaml to add the lockitron lock. In the live environment I get the following error:

Traceback (most recent call last):
  File "/usr/lib/python3.4/asyncio/tasks.py", line 237, in _step
    result = next(coro)
  File "/srv/homeassistant/lib/python3.4/site-packages/homeassistant/helpers/entity_component.py", line 336, in _async_process_entity
    new_entity, self, update_before_add=update_before_add
  File "/srv/homeassistant/lib/python3.4/site-packages/homeassistant/helpers/entity_component.py", line 205, in async_add_entity
    yield from entity.async_update_ha_state()
  File "/srv/homeassistant/lib/python3.4/site-packages/homeassistant/helpers/entity.py", line 213, in async_update_ha_state
    state = self.state
  File "/srv/homeassistant/lib/python3.4/site-packages/homeassistant/components/lock/__init__.py", line 180, in state
    locked = self.is_locked
  File "/home/homeassistant/.homeassistant/custom_components/lock/lockitron.py", line 45, in is_locked
    return data['state'] == 'lock'
KeyError: 'state'

Not sure why I get that error in live but not in dev?

Here, I got it pulling the config values…

https://paste.ofcode.org/38xE2hvALhiM9hk4SvpmLj4

Nice work! I made the changes you suggested and it’s up and working reading from the configruation.yaml. I’ll mess around with this and see about grabbing the lock name from the API and maybe some other information. But at least it’s working now!

BTW someone submitted initial work on Lockitron a couple weeks ago but it died before it got merged because it was implemented as a sensor instead of a lock. You can see it here.

I have been working on following the process of adding this as a component, now that Jumpkick solved the configuration issue. I am absolutely brand new to all of this, I am trying to learn how to do the tox check and then I need to learn how to submit it correctly to have it added. It’s all a learning process for me but I hope to submit it to the project so others can use it.