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

Added getter_callback to Characteristic #90

Merged
merged 15 commits into from
May 9, 2018
4 changes: 2 additions & 2 deletions pyhap/accessory_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ def get_characteristics(self, char_ids):
rep = {HAP_REPR_AID: aid, HAP_REPR_IID: iid}
char = self.accessory.get_characteristic(aid, iid)
try:
rep[HAP_REPR_VALUE] = char.value
rep[HAP_REPR_VALUE] = char.get_value()
rep[HAP_REPR_STATUS] = CHAR_STAT_OK
except CharacteristicError:
logger.error("Error getting value for characteristic %s.", id)
Expand Down Expand Up @@ -446,7 +446,7 @@ def set_characteristics(self, chars_query, client_addr):
# TODO: status needs to be based on success of set_value
char.client_update_value(cq[HAP_REPR_VALUE])
if "r" in cq:
response[HAP_REPR_VALUE] = char.value
response[HAP_REPR_VALUE] = char.get_value()

chars_response.append(response)
return {HAP_REPR_CHARS: chars_response}
Expand Down
31 changes: 23 additions & 8 deletions pyhap/characteristic.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class Characteristic:
"""

__slots__ = ('display_name', 'type_id', 'properties', 'broker',
'setter_callback', 'value')
'value', 'getter_callback', 'setter_callback')

def __init__(self, display_name, type_id, properties):
"""Initialise with the given properties.
Expand All @@ -98,8 +98,9 @@ def __init__(self, display_name, type_id, properties):
self.type_id = type_id
self.properties = properties
self.broker = None
self.setter_callback = None
self.value = self._get_default_value()
self.getter_callback = None
self.setter_callback = None

def __repr__(self):
"""Return the representation of the characteristic."""
Expand All @@ -114,6 +115,15 @@ def _get_default_value(self):
value = HAP_FORMAT_DEFAULTS[self.properties[PROP_FORMAT]]
return self.to_valid_value(value)

def get_value(self):
Copy link
Owner

Choose a reason for hiding this comment

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

Documentation stating that this calls the getter if any to update the .value

"""
This is to allow for calling `getter_callback`
:return: Current Characteristic Value
"""
if self.getter_callback:
self.value = self.to_valid_value(value=self.getter_callback())
return self.value

def to_valid_value(self, value):
"""Perform validation and conversion to valid value"""
if self.properties.get(PROP_VALID_VALUES):
Expand Down Expand Up @@ -168,6 +178,12 @@ def set_value(self, value, should_notify=True):
If not set_value will be aborted and an error message will be
displayed.

`Characteristic.setter_callback`
You may also define a `setter_callback` on the `Characteristic`.
This will be called with the value being set as the arg.

.. seealso:: Characteristic.value

:param value: The value to assign as this Characteristic's value.
:type value: Depends on properties["Format"]

Expand All @@ -184,12 +200,11 @@ def set_value(self, value, should_notify=True):
def client_update_value(self, value):
"""Called from broker for value change in Home app.

Change self.value to value and call callback.
Call set_value and call callback.
"""
logger.debug('client_update_value: %s to %s',
self.display_name, value)
self.value = value
self.notify()
# Call setter_callback
Copy link
Contributor

@cdce8p cdce8p Apr 22, 2018

Choose a reason for hiding this comment

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

The same here. It would be quite confusion if a client_update_value call cause a set_value log output as well.
Instead use:

        self._value = value
        self.notify()

Copy link
Contributor

Choose a reason for hiding this comment

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

Can you please revert the changes to client_update_value? I don't think they are necessary for get_value.

if self.setter_callback:
self.setter_callback(value)

Expand Down Expand Up @@ -221,10 +236,10 @@ def to_HAP(self):
hap_rep.update({k: self.properties[k] for k in
self.properties.keys() & PROP_NUMERIC})
elif self.properties[PROP_FORMAT] == HAP_FORMAT_STRING:
if len(self.value) > 64:
hap_rep[HAP_REPR_MAX_LEN] = min(len(self.value), 256)
if len(self.get_value()) > 64:
Copy link
Owner

Choose a reason for hiding this comment

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

Maybe do value = self.get_value() at the beginning of the method, otherwise you could potentially call the callback two times in this if

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yup, thanks for checking. Pushed changes.

hap_rep[HAP_REPR_MAX_LEN] = min(len(self.get_value()), 256)
if HAP_PERMISSION_READ in self.properties[PROP_PERMISSIONS]:
hap_rep[HAP_REPR_VALUE] = self.value
hap_rep[HAP_REPR_VALUE] = self.get_value()

return hap_rep

Expand Down
4 changes: 3 additions & 1 deletion pyhap/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def get_characteristic(self, name):
raise ValueError('Characteristic not found')

def configure_char(self, char_name, properties=None, valid_values=None,
value=None, setter_callback=None):
value=None, setter_callback=None, getter_callback=None):
"""Helper method to return fully configured characteristic."""
char = self.get_characteristic(char_name)
if properties or valid_values:
Expand All @@ -59,6 +59,8 @@ def configure_char(self, char_name, properties=None, valid_values=None,
char.set_value(value, should_notify=False)
if setter_callback:
char.setter_callback = setter_callback
if getter_callback:
char.getter_callback = getter_callback
return char

def to_HAP(self):
Expand Down