-
Notifications
You must be signed in to change notification settings - Fork 119
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
Conversation
@jslay88 Can you rebase your branch into to current dev branch? That should solve the merge conflicts. |
As far as I understand it, the if self.getter_callback:
value = self.getter_callback() |
Yeah, you are probably right. This is what I get for trying to put something in late at night waiting on things to finish. Give me a day, I want to rework this now that I am looking at it again. |
Should we change the setter_callback to not use value as well? Seeing as how it is implied through |
Codecov Report
@@ Coverage Diff @@
## dev #90 +/- ##
==========================================
- Coverage 50.94% 50.93% -0.01%
==========================================
Files 14 14
Lines 1329 1337 +8
Branches 138 140 +2
==========================================
+ Hits 677 681 +4
- Misses 641 643 +2
- Partials 11 13 +2
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had it a bit backwards. The value
property you added should be the right way to go. Can you add the getter_callback
to service.configure_char?
Left some additional comments as well.
pyhap/characteristic.py
Outdated
:return: value | ||
""" | ||
if not getattr(self, '_value', None): | ||
self._value = self._get_default_value() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not leave that in __init__
with self._value = self.get_default_value()
? Currently you do the check every time char.value
is called, also it's only None
for the first time.
pyhap/characteristic.py
Outdated
if not getattr(self, '_value', None): | ||
self._value = self._get_default_value() | ||
if self.getter_callback: | ||
self._value = self.to_valid_value(self.getter_callback()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe change that to self._value = self.to_valid_value(value=self.getter_callback())
.
By adding value=
it might be a bit clearer what self.getter_callback()
will return.
pyhap/characteristic.py
Outdated
except ValueError: | ||
self.value = self._get_default_value() | ||
self.set_value(self._get_default_value(), should_notify=False) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
override_properties
shouldn't call set_value
. It would only trigger unnecessary calls, like the log output.
Just use:
try:
self._value = self.to_valid_value(self.value)
except ValueError:
self._value = self._get_default_value()
pyhap/characteristic.py
Outdated
self.display_name, value) | ||
# Set new value before anything else, set_value calls notify | ||
self.set_value(value) | ||
# Call setter_callback |
There was a problem hiding this comment.
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()
tests/test_characteristic.py
Outdated
char.value = 'aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeee' \ | ||
'ffffffffffgggggggggg' | ||
char.set_value('aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeee' | ||
'ffffffffffgggggggggg') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally I would prefer char._value =
instead. That would make it a bit clearer what is being tested and you don't have to be that careful what is being mocked when.
I think a more straightforward solution would be to make a new interface for getting a value from iOS clients. The calls that get the char value to give to iOS is in def get_value(self):
if self.getter_callback:
return self.getter_callback()
else:
return value However, we also need to use this when getting the value in the What are your thoughts? PS sorry for the late review! |
Well, that's kind of the intent behind making |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The thing is that you now need an odd-looking _value
and, thus, you have two sources of truth about a chars value. The only place you would need to touch code outside of the char file is one call in the driver (mentioned before). Furthermore, IMO properties are something that can be retrieved fairly quickly - the getter might read from a sensor which is slow and could be unexpected by the user.
Another point: having |
The breaking change with using the What I don't quite get is, why
An additional argument for not including the |
I didn’t quite get point 3 - the driver does not check the value - it just returns it. My argument about using get value in to HAP is that othwewise get_accessories and get_characteristics will have different semantics (one uses to hap, the other .value) |
I could have been a bit clearer. My idea for
I see. My idea was separation of |
Basically I see two use cases for how the value is retrieved - you retrieve a cached value or get it anew, where the latter is achieved with setting the getter_callback. Your point about regularly refreshing the value falls into the first case and can be achieved using the already established approach with the Having said that, I think it is flexible enough to have a From the set of sensors I have, there are some which have limited lifetime and these should be "read from" as rarely as possible. Thus, I have a 20/30 min Thoughts? |
Please correct me if I haven't understand something properly. What it comes done to, as I think of it, is to use In that case it might make sense to expand upon the current idea of using just: def get_value():
if self.getter_callback:
self._value = self.to_valid_value(value=self.getter_callback())
return self._value and incorporate the notify call if the new value is different. Something like: def get_value():
if not self.getter_callback:
raise ValueError('No getter_callback defined')
value = self.to_valid_value(value=self.getter_callback())
if value != self.value:
self.value = value
self.notify() Maybe a renaming to |
What if we were to have a bool on the char to define the state's requirements. Either that or we leave the Accessory.run method in and those that want to use a polling period can use that, people that want to have a fresh value every time, can define getter_callback. Just throwing more ideas out there. I really have no weight in which method we go with. |
@cdce8p I think getting a value should not trigger a notify, because the "gotten" value will be deliver to iOS anyway. Getter callback is intuitive for me - method to be called when a get happens. @jslay88 I think the getter should decide on that internally, i.e. no need to expose the bool in the char. Can we agree on: def get_value():
if self.getter_callback:
self.value = self.to_valid_value(value=self.getter_callback())
return self.value with no |
We can do that, although small changes for the async conversion might be necessary later. |
@jslay88 Are you fine with the above? |
Sure thing. Will make the changes here shortly.
…On Mon, Apr 30, 2018 at 12:03 Ivan Kalchev ***@***.***> wrote:
@jslay88 <https://github.com/jslay88> Are you fine with the above?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#90 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AF36UdZz40d_S-1azX0BUxMXomb2wfWmks5tt1HcgaJpZM4TXk6o>
.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a few comments. There are some changes from #99 that need to be done.
pyhap/characteristic.py
Outdated
""" | ||
logger.debug('client_update_value: %s to %s', | ||
self.display_name, value) | ||
logger.debug('%s: Client update value to %s', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed the log statement in one of the last merged PR #99
pyhap/characteristic.py
Outdated
logger.debug('%s: Client update value to %s', | ||
self.display_name, value) | ||
# Set new value before anything else, then notify client | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This and the comment below shouldn't be necessary.
tests/test_characteristic.py
Outdated
@@ -202,3 +202,162 @@ def test_from_dict(): | |||
assert char.display_name == 'Test Char' | |||
assert char.type_id == uuid | |||
assert char.properties == {'Format': 'int', 'Permissions': 'read'} | |||
|
|||
class TestCharacteristic(unittest.TestCase): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All tests in the TestCharacteristic
class got changed in #99 as well. They are now outside, so you should be able to remove the class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't forget that AccessoryDriver.get_characteristics
now needs to call get_value
instead. Also, get_value
should be called in to_HAP
as well.
@@ -114,6 +115,11 @@ def _get_default_value(self): | |||
value = HAP_FORMAT_DEFAULTS[self.properties[PROP_FORMAT]] | |||
return self.to_valid_value(value) | |||
|
|||
def get_value(self): |
There was a problem hiding this comment.
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
@jslay88 any issues with this? |
No, I just haven't had the chance to really get time to make the changes.
Will try and see if I can get around to it tonight.
Sorry for the delay.
…On Mon, May 7, 2018 at 10:59 AM Ivan Kalchev ***@***.***> wrote:
@jslay88 <https://github.com/jslay88> any issues with this?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#90 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AF36UfW7CUjjrWYX6hgehCDXy7zd7mR3ks5twH10gaJpZM4TXk6o>
.
|
Cool, no rush, just checking |
pyhap/characteristic.py
Outdated
@@ -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: |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just two small comments (see below).
Can you update the changelog
as well?
pyhap/characteristic.py
Outdated
self.value = value | ||
self.notify() | ||
# Call setter_callback |
There was a problem hiding this comment.
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
.
pyhap/characteristic.py
Outdated
@@ -217,14 +232,16 @@ def to_HAP(self): | |||
HAP_REPR_FORMAT: self.properties[PROP_FORMAT], | |||
} | |||
|
|||
value = self.get_value() | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A small one: value
is used in the block below, so why not delete the empty line?
So do you want the logger in
|
I see. The comment earlier was meant for |
Done |
Thanks! The code looks good IMO. |
Done |
Great work, thanks for addressing all comments! |
For #78