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

Multiple changes #7

Open
wants to merge 48 commits into
base: master
Choose a base branch
from
Open

Multiple changes #7

wants to merge 48 commits into from

Conversation

kevinkk525
Copy link
Contributor

This pull request is merely to give you an overview of the changes I made, so you can have them in mind when looking at the code. I know you'll only start working on this once you check the module for the new hardware and retest the reliability. Thanks for your efforts with this module.

Changes:

  1. Sorted files and made a structure that made sense so you know which file belongs where without reading the documentation every time
  2. Made the repo a module to be used like from micropython_mqtt_as.mqtt_as import MQTTClient,
    making it possible to just clone the repo and copy it to espXXXX/modules also reducing file clutter in this directory.
  3. Adapted code to ESP32 loboris fork as sys.platform returns a different string as the official port and all workarounds for the official port are not needed in this fork except the Wifi credentials. [change already implemented in your repo by now]
  4. Changed MQTTClient constructor initialization from using a dictionary to using keywords with default parameters.
  5. Made a minimal version of mqtt_as for the ESP8266 [can redo this once you get a new version released]
  6. Added support for "unsubscribe" command
  7. Added support for recognizing a retained publication. This is also a breaking change as the "subs_cb" now has to accept 3 args: topic, msg, retained
  8. Improved reliability when (un-)subscribing to many topics in a short time (resulted in self.pkt being overwritten before response was received/processed, resulting in endless reconnects)
  9. Added Lock.release() as a workaround until bugfix is released in the next micropython update. Also added Lock.locked() to make it more generally compatible and useable.
  10. Updated all other files to work correctly with these changes
  11. Updated documentation to reflect all changes

Changed structure to be clearly arranged and to make it usable as
module.
Updated mqtt_as to not use some workarounds needed for ESP32 with
loboris port.
Updated README.
removed config dictionary to save ~100-200B which is especially
important on esp8266. Moved config dictionary to config.py to still make
it possible to configure the library using that dict.
Minimal version for esp8266 saving another 150-250B by removing
functions for esp32 and sonoff and by removing not needed functions.
extended class Lock with method locked() returning self._locked to make
it more useful outside of mqtt_as
Added misssing documentation about changes made for chaning the way the
constructor is called, usage in loboris fork and esp8266 minimal
version.
Also put all remote_mqtt tests in sepearate folder.
Development version is now master branch
Added information about all the changes compared to base repo of Peter Hinich
Added information about the changes compared to base repo of Peter Hinch
(sorry wrote your name wrong)
Added information about all the changes compared to base repo of Peter Hinich
Added information about the changes compared to base repo of Peter Hinch
(sorry wrote your name wrong)
When having many subscribe/unsubscribes in a short time, a reliability problem became apparent:
The next subscription had been send before the last one received its confirmation from the broker, resulting in an endless reconnect as the received pid did not match the last pid sent to the broker.
Solution: Added an additional Lock for subscribe/unsubscribe to wait until the confirmation is received or try again.
Increased reliability by putting qos>0 publications under a lock too, so self.pid can't get overwritten by another qos>0 publication. This is probably really improbable but this makes the reliability update complete.
@kevinkk525
Copy link
Contributor Author

The pyboard D commit looks good.
Will you take a look at these changes too?
Notably 1,2,4,6,7,8 and maybe the pause/resume feature I implemented on a different branch?

@peterhinch
Copy link
Owner

I haven't forgotten these, but they do impose substantial API changes on existing users. By contrast my latest commit has zero API changes :)

Re 1,2,4 I'm still unsure whether the gains, particularly from using a package and replacing the config dictionary, justify the API disruption. I originally started out with lots of constructor args and changed to the dict. This does have some advantages. For example it is initialised with default args in the library but you can modify it with project-level defaults in config.py. So, in a project where (say) the server IP or WiFi credentials change, you just distribute a new config.py. You can, of course, pass **config to the multi-parameter constructor, but if you're going to do that you might as well stick with the dict.

7 (retained messages) is definitely worth doing.
Re 6, 8 I'm not convinced about unsubscribing: are embedded applications likely to unsubscribe?

Right now I'm busy trying to understand some weird behaviour of Pyboard D applications and am trying to produce a decent test case.

@kevinkk525
Copy link
Contributor Author

kevinkk525 commented Apr 4, 2019

Thanks for your answer.
I can understand that you are worried about API changes to existing users. This however always slows down progress. Maybe an updated version with the current API can be kept on a separate branch that'll only receive bugfixes once stable?

1,2,4 would be nice to have if a new version already changes the API.
The advantages you see in using a dict are not what I can see. With normal constructor args you can have all those default values too and you will have a project-level config anyway that will store the needed values that will overwrite the default ones and can therefore still be easily swapped by distributing a new config.py.

7 (retained messages) is where the biggest API change lays because the function that is being called when a new message is received now takes 3 args instead of 2.

6 unsubscribe: I use it often. On topic "home/device/state" I keep the retained status that the device has. On topic "home/device/state/set" the device receives commands to change that state to a new state.
So on reboot my devices subscribes to the state topic ("home/device/state") to get the retained value and restores the state it had before its reboot. Then it unsubscribes that topic because it does not need that anymore to free resources (as you need a higher level subscription handler to know what function to call on which topic). Then it subscribes to the command topic ("home/device/state/set") and listens to changes that might even have occured during its outage.
I don't know if that's the best way for restoring device states but I did not find anything better yet.
Therefore I don't know if embedded applications are likely to use unsubscribe but mine do. It is however not a big code change to implement unsubscribe and does only extend the API, not break compatibility.

8 is also useful with only subscribe as I had problems subscribing from different uasyncio coros in short succession.

Pause/Resume might be helpful for battery powered devices to properly disconnect from the server to save power.

Once your new version is stable and ready, I can pull those changes and create pull requests only with the changes you want to implement. That will hopefully make it easier for you.

Good luck hunting down the problems with the Pyboard D! Hope you can find it soon.

@kevinkk525
Copy link
Contributor Author

Just as an update as time has passed:

  • Pulled your changes
  • Added support for the unix port
  • optional feature in a different branch: pause and resume to cleanly disconnect before shutting down wifi to save power and resume when starting wifi again (as requested by Mike, don't know about anyone else who wanted that feature)

� Conflicts:
�	tests/lowpower.py
�	tests/mqtt_as_cancel.py
Can be implemented similarly for unsubscribe and subscribe.
� Conflicts:
�	mqtt_as.py
�	mqtt_as_cancel.py
and removed locks added as workarounds.
Concurrent publish/(un)subscribe operations will now work correctly. The locks workaround making them execute after each other is not needed anymore.
which other components might depend on.
� Conflicts:
�	README_mqtt_as.md
�	mqtt_as.py
�	mqtt_as/mqtt_as_cancel.py
�	mqtt_as/ssl.py
�	mqtt_as_cancel.py
�	tests/mqtt_as_timeout.py
�	tests/range.py
�	tests/ssl.py
�	tests/tls.py
�	tests/tls32.py
�	tests/tls8266.py
the other timeout files and tests still need to be updated.
Copy link
Owner

@peterhinch peterhinch left a comment

Choose a reason for hiding this comment

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

This looks great, thank you.

I think the changes for the new uasyncio should be a separate PR rather than an addendum to this very large one. Then I could simply do a merge.

@kevinkk525
Copy link
Contributor Author

Ah yes, I forgot that this PR pulls all the changes from my master repository. I guess this can be closed since you won't be merging the remaining changes anyway.

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.

2 participants