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

Refactoring: Split Device class into Device+Protocol #592

Merged
merged 9 commits into from
Jan 13, 2020

Conversation

petrkotek
Copy link
Contributor

@petrkotek petrkotek commented Dec 8, 2019

Before adding support for the first MIoT device (#585) I thought it would be good to do a little bit of refactoring (i.e. to make the #585 smaller).

This PR extracts command-sending functionality from Device class to new Protocol class.

  • Basically the send(), discover() and do_discover() methods were moved from Device to Protocol
  • Protocol is instantiated in Device constructor.
  • Protocol#send() is deprecated & forwards the commands to CommandSender.

Note: tried discovery and looks to be working fine:

$ python miio/vacuum_cli.py discover
INFO:miio.discovery:Discovering devices with mDNS, press any key to quit...
INFO:miio.discovery:Found a supported 'Vacuum' at 192.168.0.10 - token: ffffffffffffffffffffffffffffffff
/Users/petrkotek/Workspace/python-miio/miio/discovery.py:177: UserWarning: Please consider using python-yeelight for more complete support.
  dev = device_cls(ip=addr)
INFO:miio.discovery:Found a supported 'Yeelight' at 192.168.0.17 - token: 00000000000000000000000000000000
INFO:miio.discovery:Found a supported 'AirQualityMonitor' at 192.168.0.2 - token: bb835d94f8e75c74a231e445c9716616
INFO:miio.discovery:Found a supported 'Yeelight' at 192.168.0.9 - token: 00000000000000000000000000000000

Edit: renames CommandSender to Protocol

@coveralls
Copy link

coveralls commented Dec 8, 2019

Coverage Status

Coverage increased (+0.08%) to 73.783% when pulling db0f53a on petrkotek:command-sender into 20413c2 on rytilahti:master.

@petrkotek petrkotek marked this pull request as ready for review December 8, 2019 10:36
@petrkotek
Copy link
Contributor Author

@rytilahti Looking forward to hear your feedback when you have a bit of time to review this. Thank you!

@petrkotek
Copy link
Contributor Author

@rytilahti friendly ping in case you missed it. If you're busy, that's ok :)

Copy link
Owner

@rytilahti rytilahti left a comment

Choose a reason for hiding this comment

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

Hi and sorry for the delay, I added some comments, but my concerns are mostly:

  • Users of the device classes should have no need to know about implementation details, that's why the protocol handling should simply by wrapped and invisible to users. (concerns send() etc.).
  • For tests, simply pass the existing self.return_values to the dummy implementation directly afterwards. This will keep the history cleaner as there is no real reason to overwrite those parts from my understanding.

Ping @syssi

miio/command_sender.py Outdated Show resolved Hide resolved
miio/device.py Outdated Show resolved Hide resolved
miio/device.py Outdated Show resolved Hide resolved
miio/discovery.py Outdated Show resolved Hide resolved
"send_cmd": lambda x: self._send_input_validation(x),
"set_power": lambda x: self._set_power(x),
}
)
Copy link
Owner

Choose a reason for hiding this comment

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

Please keep the self.return_values for now, and simply pass it as a parameter to the implementation. This will keep the diff much more readable and there is no real need to modify these parts at the moment (imo).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was thinking that we don't really need the self.return_values anymore and wanted to clean it up.

The diff is a bit smaller when ignoring whitespaces :badpokerface: https://github.com/rytilahti/python-miio/pull/592/files?w=1

Is that alright?

Copy link
Owner

Choose a reason for hiding this comment

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

Honestly I'd prefer it that'd be done in a separate PR. This PR contains already so many lines to review, and as these are tests, not having return_values does not really bring much.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fair enough. I'm initialising the DummyProtocol in DummyDevice now and passing in self so it can access return_values. That way the diff is indeed smaller.

Had to add call to the parent constructor for some dummy devices in tests and add inheritance from DummyDevice, but that should faily uncontroversial :)

miio/vacuum.py Outdated Show resolved Hide resolved
@rytilahti rytilahti requested a review from syssi December 17, 2019 01:19
Petr Kotek added 2 commits January 8, 2020 01:38
Rename do_discover() to send_handshake() & create a proxy method send_handshake() in Device class
Copy link
Contributor Author

@petrkotek petrkotek left a comment

Choose a reason for hiding this comment

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

pushed additional commits to address most of the feedback (otherwise commented with a question)

miio/device.py Outdated Show resolved Hide resolved
miio/command_sender.py Outdated Show resolved Hide resolved
miio/device.py Outdated Show resolved Hide resolved
miio/discovery.py Outdated Show resolved Hide resolved
"send_cmd": lambda x: self._send_input_validation(x),
"set_power": lambda x: self._set_power(x),
}
)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was thinking that we don't really need the self.return_values anymore and wanted to clean it up.

The diff is a bit smaller when ignoring whitespaces :badpokerface: https://github.com/rytilahti/python-miio/pull/592/files?w=1

Is that alright?

miio/vacuum.py Outdated Show resolved Hide resolved
@petrkotek petrkotek changed the title Refactoring: Split Device class into Device+CommandSender Refactoring: Split Device class into Device+Protocol Jan 9, 2020
@petrkotek
Copy link
Contributor Author

Actioned the 2nd round of review. Hope it looks better now.

Thank you for looking into this, @rytilahti!

Copy link
Owner

@rytilahti rytilahti left a comment

Choose a reason for hiding this comment

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

This start to look good, thanks for your efforts! I'm unsure if cleaning up the DeviceException import should be a part of this, but it's not a big deal. See my comments inline, I haven't yet tested this locally on my devices (I'll do that later this weekend), but otherwise it's almost ready to be merged :-)

miio/device.py Outdated Show resolved Hide resolved
miio/device.py Outdated
@@ -333,7 +139,7 @@ def raw_command(self, command, parameters):

:param str command: Command to send
:param dict parameters: Parameters to send"""
return self.send(command, parameters)
return self.protocol.send(command, parameters)
Copy link
Owner

Choose a reason for hiding this comment

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

I'm starting to have second thoughts on deprecating the send. This code would generally be much cleaner if we'd keep it as it is, and simply make it wrap the call to the private protocol. Thoughts on this? What are the pros for deprecating it (and making all other methods more complicated)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I guess the main reason why I decided to do that was to do less inheritance and more composition (to make things easier to follow). Keeping send, however, makes it more backwards compatible.

I've removed the deprecation.

miio/protocol.py Show resolved Hide resolved
…od to keep everything compatible.

Protocol: update docstring to reflect new code.
Vacuum: expose raw_id from the Protocol.
@petrkotek
Copy link
Contributor Author

petrkotek commented Jan 11, 2020

Done addressing the latest feedback.

Tested on my Air Quality Monitor:

(python-miio) bash-3.2$ python miio/cli.py airqualitymonitor --ip $AIR_IP --token $TOKEN status
Power: on
USB power: True
Battery: 100
AQI: 4
Temperature: None
Humidity: None
CO2: None
CO2e: None
PM2.5: None
TVOC: None
Display clock: False
(python-miio) bash-3.2$ python miio/cli.py airqualitymonitor --ip $AIR_IP --token $TOKEN raw_command get_prop "['power', 'aqi', 'battery', 'usb_state', 'time_state', 'night_state', 'night_beg_time', 'night_end_time', 'sensor_state']"
Running command raw_command
['on', 3, 100, 'on', 'off', 'on', 79200, 25200, 'ready']

Discovery worked too:

(python-miio) bash-3.2$ python miio/vacuum_cli.py discover
INFO:miio.discovery:Discovering devices with mDNS, press any key to quit...
INFO:miio.discovery:Found a supported 'AirQualityMonitor' at 192.168.0.2 - token: bb835d94<REDACTED>

Vacuum (S50)

$ python miio/cli.py vacuum --ip $AIR_IP --token $TOKEN status
Running command status
<VacuumStatus state=Charging, error=No error bat=100%, fan=100% cleaned 14.585 m² in 0:14:25>

I.e. what I've got works fine, however, I don't have any other devices handy, so further testing will be appreciated!

Copy link
Owner

@rytilahti rytilahti left a comment

Choose a reason for hiding this comment

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

I just tested this with the 1st gen vacuum and a powerstrip (zimi.powerstrip.v2). In my opinion this can be merged now, but I'd still like to have the MiIO protocol bits in a separate file already. This will avoid moving the pieces again shortly after introducing the support for miot and keeping the diffs more comprehensible for the future :-)

miio/protocol.py Outdated
@@ -217,3 +225,225 @@ def _decode(self, obj, context, path):
Checksum(Bytes(16), Utils.md5, Utils.checksum_field_bytes),
),
)


class Protocol:
Copy link
Owner

Choose a reason for hiding this comment

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

Could you move this to its own file (thus, avoid moving this again soonish and polluting the git logs), I'd say miioprotocol.py would be a good candidate.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

✅ Moved Protocol to miioprotocol.py as MiIOProtocol

Copy link
Owner

Choose a reason for hiding this comment

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

Great, thanks for the effort! 🎉

@rytilahti rytilahti merged commit 9a7c6c4 into rytilahti:master Jan 13, 2020
@petrkotek petrkotek deleted the command-sender branch January 13, 2020 06:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants