Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 50 additions & 24 deletions homeassistant/components/lock/zwave.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,21 @@
ATTR_LOCK_STATUS = 'lock_status'
ATTR_CODE_SLOT = 'code_slot'
ATTR_USERCODE = 'usercode'
CONFIG_ADVANCED = 'Advanced'

SERVICE_SET_USERCODE = 'set_usercode'
SERVICE_GET_USERCODE = 'get_usercode'
SERVICE_CLEAR_USERCODE = 'clear_usercode'

POLYCONTROL = 0x10E
DANALOCK_V2_BTZE = 0x2
POLYCONTROL_DANALOCK_V2_BTZE_LOCK = (POLYCONTROL, DANALOCK_V2_BTZE)
WORKAROUND_V2BTZE = 'v2btze'

DEVICE_MAPPINGS = {
POLYCONTROL_DANALOCK_V2_BTZE_LOCK: WORKAROUND_V2BTZE
}

LOCK_NOTIFICATION = {
1: 'Manual Lock',
2: 'Manual Unlock',
Expand Down Expand Up @@ -110,7 +120,7 @@

# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Find and return Z-Wave switches."""
"""Find and return Z-Wave locks."""
if discovery_info is None or zwave.NETWORK is None:
return

Expand Down Expand Up @@ -197,40 +207,68 @@ def clear_usercode(service):


class ZwaveLock(zwave.ZWaveDeviceEntity, LockDevice):
"""Representation of a Z-Wave switch."""
"""Representation of a Z-Wave Lock."""

def __init__(self, value):
"""Initialize the Z-Wave switch device."""
"""Initialize the Z-Wave lock device."""
zwave.ZWaveDeviceEntity.__init__(self, value, DOMAIN)

self._node = value.node
self._state = None
self._notification = None
self._lock_status = None
self._v2btze = None

# Enable appropriate workaround flags for our device
# Make sure that we have values for the key before converting to int
if (value.node.manufacturer_id.strip() and
value.node.product_id.strip()):
specific_sensor_key = (int(value.node.manufacturer_id, 16),
int(value.node.product_id, 16))
if specific_sensor_key in DEVICE_MAPPINGS:
if DEVICE_MAPPINGS[specific_sensor_key] == WORKAROUND_V2BTZE:
self._v2btze = 1
_LOGGER.debug("Polycontrol Danalock v2 BTZE "
"workaround enabled")
self.update_properties()

def update_properties(self):
"""Callback on data changes for node values."""
for value in self._node.get_values(
class_id=zwave.const.COMMAND_CLASS_DOOR_LOCK).values():
if value.type != zwave.const.TYPE_BOOL:
continue
if value.genre != zwave.const.GENRE_USER:
continue
self._state = value.data
_LOGGER.debug('Lock state set from Bool value and'
' is %s', value.data)
break

for value in self._node.get_values(
class_id=zwave.const.COMMAND_CLASS_ALARM).values():
if value.label != "Access Control":
continue
self._notification = LOCK_NOTIFICATION.get(value.data)
if self._notification:
self._state = LOCK_STATUS.get(value.data)
_LOGGER.debug('Lock state set from Access Control value and'
' is %s', value.data)
notification_data = value.data
if self._v2btze:
for value in (self._node.get_values(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I see this kind of code all over Z-Wave, what about we introduce a method like this:

(not including other filters already present on node.get_values)

get_values(node, class_id=None, index=None, data=None):
    result = []

    kwargs = {}
    if class_id is None:
        kwargs['class_id'] = class_id

    values = node.get_values(**kwargs).values()

    for value in values:
        if index is not None and value.index != index:
            continue

        if data is not None and value.data != data:
            continue

        results.append(value)

    return results

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I need some time to look over the code and see how this should be done. It's not totally consistent what is being used, some places uses type, genre, othe places label, and some places like your example. Could this be for an other PR?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yes, other PR.

class_id=zwave.const.COMMAND_CLASS_CONFIGURATION)
.values()):
if value.index != 12:
continue
if value.data == CONFIG_ADVANCED:
self._state = LOCK_STATUS.get(notification_data)
_LOGGER.debug('Lock state set from Access Control '
'value and is %s', notification_data)
break

break

for value in self._node.get_values(
class_id=zwave.const.COMMAND_CLASS_ALARM).values():
if value.label != "Alarm Type":
continue
alarm_type = LOCK_ALARM_TYPE.get(value.data)
if alarm_type:
self._state = LOCK_STATUS.get(value.data)
_LOGGER.debug('Lock state set from Alarm Type value and'
' is %s', value.data)
break

for value in self._node.get_values(
Expand All @@ -256,18 +294,6 @@ def update_properties(self):
self._lock_status = LOCK_ALARM_TYPE.get(alarm_type)
break

if not self._notification and not self._lock_status:
for value in self._node.get_values(
class_id=zwave.const.COMMAND_CLASS_DOOR_LOCK).values():
if value.type != zwave.const.TYPE_BOOL:
continue
if value.genre != zwave.const.GENRE_USER:
continue
self._state = value.data
_LOGGER.debug('Lock state set from Bool value and'
' is %s', value.data)
break

@property
def is_locked(self):
"""Return true if device is locked."""
Expand Down