Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for KIWI Door Locks #14485

Merged
merged 20 commits into from
Jun 12, 2018
Merged

Conversation

c7h
Copy link
Contributor

@c7h c7h commented May 16, 2018

Description:

Added support for the KIWI Door lock platform (https://kiwi.ki).

Pull request in home-assistant.github.io with documentation (if applicable): home-assistant/home-assistant.io#5381

Example entry for configuration.yaml (if applicable):

lock:
  - platform: kiwi
    username: email@example.com
    password: supersecretpassword

Checklist:

  • The code change is tested and works locally.

If user exposed functionality or configuration variables are added/changed:

If the code communicates with devices, web services, or third-party tools:

  • Local tests with tox run successfully. Your PR cannot be merged unless tests pass
  • New dependencies have been added to the REQUIREMENTS variable (example).
  • New dependencies are only imported inside functions that use them (example).
  • New dependencies have been added to requirements_all.txt by running script/gen_requirements_all.py.
  • New files were added to .coveragerc.

c7h added 7 commits May 16, 2018 12:16
bugfixes

improved attribute display

flake8

more style adjustments
reordered imports and flake8

attempt to pelase a very picky linter

also pleasing pylint now :)
@fabaff fabaff changed the title New Component: KIWI Door Lock Add support for KIWI Door Locks May 16, 2018
@fabaff
Copy link
Member

fabaff commented May 16, 2018

Successor of #12304

def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the KIWI lock platform."""
from kiwiki import KiwiClient
kiwi = KiwiClient(config.get(CONF_USERNAME), config.get(CONF_PASSWORD))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for get, you already require those parameters in the schema

def __init__(self, kiwi_lock, client):
"""Initialize the lock."""
self._sensor = kiwi_lock
self._device_attrs = None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to set it to None if you assign it four lines down

@property
def is_locked(self):
"""Return true if lock is locked."""
return True
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can it never be unlocked?

Copy link
Contributor Author

@c7h c7h May 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, there's no way to detect the actual locked state. Therefore, the assumed state is locked (devices automatically lock after unlock within 5 seconds)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could use this approach: #14419 Just change the state for some seconds.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please implement the suggested approach. It changes the state of the lock for a short period of time and makes automations easier.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok

ATTR_CAN_INVITE: kiwi_lock.get('can_invite')}

self._device_attrs.update(address)
self._device_attrs.update({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do extract lat/lng and add it again separately? You could update the content of address and add it to the list by **address:

self._device_attrs {
      ATTR_ID: self.lock_I'd,
      **address
}

Copy link
Contributor Author

@c7h c7h May 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok this can be nested structure? cool - i'll change it 👍

def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the KIWI lock platform."""
from kiwiki import KiwiClient
kiwi = KiwiClient(config[CONF_USERNAME], config[CONF_PASSWORD])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess that there will be a traceback if the credentials are wrong. The setup should fails otherwise the users end up with a non-working platform.

@fabaff
Copy link
Member

fabaff commented Jun 2, 2018

c7h/kiwiki_client#1 should be addressed upstream and the requirement updated.

"""Set up the KIWI lock platform."""
from kiwiki import KiwiClient
kiwi = KiwiClient(config[CONF_USERNAME], config[CONF_PASSWORD])
add_devices([KiwiLock(lock, kiwi) for lock in kiwi.get_locks()], True)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A log entry that there are no locks found would help the users. Also, the setup can be terminated if there are no locks.

@property
def is_locked(self):
"""Return true if lock is locked."""
if self._state is not None:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this check. It doesn't add anything.

kiwi = KiwiClient(config[CONF_USERNAME], config[CONF_PASSWORD])
except KiwiException as e:
_LOGGER.error(e.msg)
return False
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't return False. Just return.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is horrible to read. I prefer return False - there is no room for misinterpretation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing is checking the return value.

Copy link
Contributor Author

@c7h c7h Jun 2, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check the platform example -
False is returned here on login failed. It makes sense even if its not checked because it improves the readability. https://developers.home-assistant.io/docs/en/creating_platform_example_light.html

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That example needs updating.

It doesn't improve readability. It gives the wrong impression what happens when the function returns.

It also makes the return inconsistent.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I created an Issue (home-assistant/developers.home-assistant#21) and will change it to return

if not available_locks:
# No locks found; abort setup routine.
_LOGGER.info("No KIWI locks found in your account.")
return False
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

Copy link
Member

@MartinHjelmare MartinHjelmare left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I missed this one.

_LOGGER.error("failed to open door")
else:
self._state = STATE_UNLOCKED
async_call_later(self.hass, UNLOCK_MAINTAIN_TIME,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a callback so have to be run from within the event loop. Use hass.add_job to schedule async_call_later on the event loop.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't async_call_later already do that for you?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

async_call_later schedules the passed in callback yes, but async_call_later itself needs to be called from within the event loop. The unlock method here will not be run within the event loop but in a worker thread. So to make sure that async_call_later is called from the event loop, we need to use hass.add_job.

self.hass.add_job(
    async_call_later, self.hass, UNLOCK_MAINTAIN_TIME, self.clear_unlock_state)

@ghost ghost added the in progress label Jun 7, 2018
from kiwiki import KiwiClient, KiwiException
try:
kiwi = KiwiClient(config[CONF_USERNAME], config[CONF_PASSWORD])
except KiwiException as e:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Linter is failing here. Please use eg exc instead of e.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's sad.... 😢

@MartinHjelmare MartinHjelmare merged commit 6755ae2 into home-assistant:dev Jun 12, 2018
@ghost ghost removed the in progress label Jun 12, 2018
@balloob balloob mentioned this pull request Jun 22, 2018
@home-assistant home-assistant locked and limited conversation to collaborators Dec 10, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants