8000 zwave refactor, don't use ozw values directly in properties. by turbokongen · Pull Request #5961 · home-assistant/core · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

zwave refactor, don't use ozw values directly in properties. #5961

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

Merged
merged 17 commits into from
Feb 18, 2017

Conversation

turbokongen
Copy link
Contributor
@turbokongen turbokongen commented Feb 13, 2017

Description:
Refactor the use of values.
I think I got them all, but discussion open :)

Related issue (if applicable): fixes #4867

Possibly #5568

@mention-bot
Copy link

@turbokongen, thanks for your PR! By analyzing the history of the files in this pull request, we identified @balloob, @fabaff and @armills to be potential reviewers.

@pvizeli
Copy link
Member
pvizeli commented Feb 13, 2017

You forget the component :)

https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/zwave/__init__.py#L733-L783

This function can only be used inside callback (Need docstring or refactory):
https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/zwave/__init__.py#L684-L719

All stuff with: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/zwave/__init__.py#L260 are wrong. That should be run inside callback and don't be a problem.

All propertys need to access a cache instead zwave function. This cache will be update from callback

@andrey-git andrey-git self-assigned this Feb 13, 2017
zwave.ZWaveDeviceEntity.__init__(self, value, DOMAIN)

def update_properties(self):
"""Callback on data changes for node values."""
self._state = self.get_value(
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not just self._state = _value.data
You are potentially bringing in data from another binary sensor in the same node.

Also everywhere else.

@@ -51,12 +51,19 @@ class ZWaveBinarySensor(BinarySensorDevice, zwave.ZWaveDeviceEntity):
def __init__(self, value, device_class):
"""Initialize the sensor."""
self._sensor_type = device_class
self._state = None
zwave.ZWaveDeviceEntity.__init__(self, value, DOMAIN)
Copy link
Contributor

Choose a reason for hiding this comment

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

Move the base class call to be the first thing in the constructor

@@ -80,26 +87,28 @@ def __init__(self, value, device_class, hass, re_arm_sec=60):
self.invalidate_after = dt_util.utcnow() + datetime.timedelta(
seconds=self.re_arm_sec)
# If it's active make sure that we set the timeout tracker
if value.data:
if self._state:
Copy link
Contributor

Choose a reason for hiding this comment

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

self._state is still None at this point
Need another solution for this

Copy link
Member

Choose a reason for hiding this comment

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

We can remove this whole if-block.

We only need a timeout to reset the value to False again if it was True. Since it's not True here, we should be good.

track_point_in_time(
self._hass, self.async_update_ha_state,
self.invalidate_after)
self._state = self.get_value(
Copy link
Contributor

Choose a reason for hiding this comment

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

Call base class to update _state

@andrey-git
Copy link
Contributor
8000 andrey-git commented Feb 14, 2017

Currently discovery is not done in OZW thread, this means we can't touch zwave properties in constructors.

zwave.ZWaveDeviceEntity.__init__(self, value, DOMAIN)
self._sensor_type = device_class
self._state = None
self.update_properties()
Copy link
Contributor

Choose a reason for hiding this comment

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

This is not called on OZW thread, so can't call it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is done in all zwave components, and not doing it will result in no data until the device checks in. No problem with mains connected devices, but battery devices will not check in until the wakeup.
Can we accept this behaviour?


def close_cover(self):
"""Close the garage door."""
self._value.data = False
self.set_value(
Copy link
Contributor

Choose a reason for hiding this comment

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

I think self._value.data = False can stay.
doing it via set_value is not safer

@turbokongen
Copy link
Contributor Author

Currently discovery is not done in OZW thread, this means we can't touch zwave properties in constructors.
To be honest, I have no clue what that means.
I can't wrap my head around this threading issue, and caching.

Copy link
Member
@balloob balloob left a comment

Choose a reason for hiding this comment

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

I think that this is a great step forward in making sure we access self._value only inside the callbacks from Z-Wave.

@balloob
Copy link
Member
balloob commented Feb 16, 2017

I think that Andrey makes a good point with that we now don't set any data in the constructors.

We could consider to add a call to update properties in the constructor. That way we only violate thread safety on startup but not for the rest of the runtime of HASS. That should at least solve most issues.

@turbokongen
Copy link
Contributor Author

I did remove all the update_properties from all components, because it was considered unsafe. Most of the comonents did that.
However removing the call, leaves us with no data until the device checks in on the network, no problem for mains devices, but it will take some time with battery devices. Is this ok, or should we have the update properties call in the constructors?

@andrey-git
Copy link
Contributor

I think it is better to unsafe-call update_properties from constructor (or otherwise pull data if update_properties is doing too much) rather than be left with missing state.

We can further improve this in subsequent PR


def value_changed(self, value):

def update_properties(self):

Choose a reason for hiding this comment

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

too many blank lines (2)

self._hass, self.async_update_ha_state,
self.invalidate_after)
self._state = self._value.data
self.schedule_update_ha_state()
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this needed? Component calls this after update_properties()

@@ -115,11 +117,16 @@ class ZwaveGarageDoor(zwave.ZWaveDeviceEntity, CoverDevice):
def __init__(self, value):
"""Initialize the zwave garage door."""
ZWaveDeviceEntity.__init__(self, value, DOMAIN)
self._state = None
Copy link
Contributor

Choose a reason for hiding this comment

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

Call update_properties() instead?

@@ -294,11 +290,19 @@ def is_locked(self):

def lock(self, **kwargs):
"""Lock the device."""
self._value.data = True
self.set_value(
Copy link
Contributor

Choose a reason for hiding this comment

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

Set _value.data directly? Also for unlock.

@@ -53,6 +53,14 @@ class ZWaveSensor(zwave.ZWaveDeviceEntity):
def __init__(self, value):
"""Initialize the sensor."""
zwave.ZWaveDeviceEntity.__init__(self, value, DOMAIN)
self._state = None
Copy link
Contributor

Choose a reason for hiding this comment

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

You don;t need to set to None - you are calling update_properties to init those values

@@ -38,16 +38,30 @@ class ZwaveSwitch(zwave.ZWaveDeviceEntity, SwitchDevice):
def __init__(self, value):
"""Initialize the Z-Wave switch device."""
zwave.ZWaveDeviceEntity.__init__(self, value, DOMAIN)
self._state = None
Copy link
Contributor

Choose a reason for hiding this comment

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

You are initing this with update_properties()


def turn_on(self, **kwargs):
"""Turn the device on."""
self._value.node.set_switch(self._value.value_id, True)
self.set_value(
Copy link
Contributor

Choose a reason for hiding this comment

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

Why change the call? The lib api is more direct and compact.
Also for turn_off

self.update_properties()
self.schedule_update_ha_state()

def update_attributes(self):
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this should be protected, i.e. _update_attributes

Also, probably call this from constructor instead of setting to None-s

self.node_id = self._value.node.node_id
self.location = self._value.node.location
self.battery_level = self._value.node.get_battery_level()
self.wakeup_interval = _get_wakeup(self._value.node)
Copy link
Contributor

Choose a reason for hiding this comment

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

Since this is no longer called from device_state_attributes inline the function here without the reties.

attrs[ATTR_BATTERY_LEVEL] = battery_level

location = self._value.node.location
if self.battery_level:
Copy link
Contributor

Choose a reason for hiding this comment

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

battery_level and wakeup_interval could be 0, but those would still be legal values.

Use if self.battery_level is not None

E544

def unlock(self, **kwargs):
"""Unlock the device."""
self._value.data = False
self._value.date= False

Choose a reason for hiding this comment

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

missing whitespace around operator

@@ -294,11 +290,10 @@ def is_locked(self):

def lock(self, **kwargs):
"""Lock the device."""
self._value.data = True
self._value.date= True

Choose a reason for hiding this comment

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

missing whitespace around operator

@andrey-git andrey-git changed the title [WIP] zwave refactor, don't use ozw values directly in properties. zwave refactor, don't use ozw values directly in properties. Feb 17, 2017
@balloob
Copy link
Member
balloob commented Feb 18, 2017

👍 🐬

@balloob balloob merged commit 799fbe4 into home-assistant:dev Feb 18, 2017
@balloob
Copy link
Member
balloob commented Feb 18, 2017

In the future, no need to wait for me to merge Z-Wave things @turbokongen @armills @andrey-git . I can't test it locally so you are in control 👍

@home-assistant home-assistant locked and limited conversation to collaborators Jun 2, 2017
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.

Major Z-Wave bug since 0.33
7 participants
0