-
Notifications
You must be signed in to change notification settings - Fork 638
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
flow-based programming #1521
base: dev
Are you sure you want to change the base?
flow-based programming #1521
Conversation
It is an actually cool approach at this 👍
And some notes about SPIFFS in general, as this is the first module using it:
|
I thought about some kind of broker but unfortunately, I don't know much about C++ and its memory management (I'm a Java developer) so local variables and in place calls is the best I can do :) For async actions component will be responsible for cloning variant object to process it later. But I'm open to any suggestions
Currently simple flow takes ~1 KB because uncompressed JSON is used. Version 6.0 of ArduinoJson library supports MessagePack format that is binary JSON and I think flow could be compressed up to 10 times after. And I hope in compressed format flow could be saved even to the EEPROM storage instead of SPIFFS.
Thanks, applied the fix |
Baseline to know about c++ objects: Nice magic is "smart" pointers like shared_ptr / unique_ptr, that can hold And main thing to remember - there is only so much KiB of RAM for the whole app 🎐 |
Thanks for the information about C++ object allocation! |
Wow, this is actually very cool, like node-red embedded... |
back when i coded several versions of espurna scripting, overhead and memory was my concern too. so i settled for a simple linter. |
Just for the record: I was also thinking on adding the RPNlib as an advanced schedule tool. It could easily be enhanced to perform actions on the relays based on time, sensor values, MQTT messages... But of course it's much more complex from the user point of view. |
Thanks for the link. Flows definitely will need something like this for math calculations Sorry for asking same question: what is the best way to store up to 1kb of binary data for devices having no spiffs storage? |
tldr; I'd use spiffs for now and not worry about it just yet. And build settings can be tweaked to make .bin smaller for some specific applications (like removing debug strings or web interfaceIt depends. Essentially, you only have EEPROM sector of 4KiB right at the end of usable flash that is expected to survive things like serial flash and OTA. Saving things in flash before the EEPROM is prone to overwriting by OTA, because flash writes are done in 4KiB blocks (For 1M, .bin is half the size most of the time) First 306 bytes of EEPROM are reserved (see |
I've decided to use MQTT retained messages to store flow configuration if SPIFFS is not available |
# Conflicts: # code/espurna/button.ino # code/espurna/mqtt.ino
Guys, I've finished with all changes planned for the day one
(and plus -DSPIFFS_SUPPORT=1 for devices having SPIFFS memory) Could you please review my changes and tell me if this feature could be merged to the main tree? |
Will check ASAP. I would also add following env to the platformio.ini:
And there's crash when spiffs is empty. Looks like response handler needs to check if flow file exists first. Or some manual labor beforehand:
|
Some things I should've mentioned earlier:
And something I had missed from ArduinoJson 5 => 6 changes (which is likely to be used in the future instead of 5) - JsonVariant changed and can no longer work without backing memory pool. Implementation is small enough though: union {...} with _type field to determine what is inside. You can just search for "union" in the ArduinoJson code |
fixed issue with millis() overflow |
code/espurna/flow.ino
Outdated
|
||
_queueSize++; | ||
} else { // reset | ||
_skipUntil = millis() + _time; |
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.
Essentially, timers should calculate relative time.
now_millis - recorded_millis > interval
And am I understanding this will create ticker per input? Can it use only a single instance? I'll cancel old timer and start a new one
btw Ticker can only work with maximum value of 1h40m (tried some time ago to reimplement scheduler using it: #678 (comment))
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.
And am I understanding this will create ticker per input?
Right, ticker per input, because there could be several inputs waiting in the queue and one ticker can handle only one timer.
Essentially, timers should calculate relative time.
I was going to slightly rework that code to do not use time comparison
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 see. Note that ticker function triggers in a system context, so does everything else in a process chain after that point. And with weird timing restriction, is it worth using it at all like that?
there are no problems right now, but using it inside loop() you can allow yourself to go back into the system via yield() / delay(), but not other way around
esp8266 arduino even has a nice abstraction for comparisons:
https://github.com/esp8266/Arduino/blob/master/cores/esp8266/PolledTimeout.h
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.
Amendment: new Ticker implements a special mechanism to execute function in a loop() context (aka CONT) by using schedule_function() (which I totally knew about...). see:
https://github.com/esp8266/Arduino/blob/64e30b270bcb8accde0c62d5998fd69907d764b6/libraries/Ticker/Ticker.h#L46
Schedule.h, .cpp
Note:
the hardcoded limit of 32 functions.
ticker functions not available in the 2.3.0
...or replicate them, place our handler at the end of the loop(), because a lot of Core libraries are using scheduled funcs
edit: i.e. it is probably better to reimplement such functionality - ticker callback queues the function, which is executed by handler running inside loop()
# Conflicts: # code/espurna/espurna.ino
# Conflicts: # code/espurna/config/prototypes.h # code/espurna/espurna.ino
Hello
This is a proof-of-concept draft for a new functionality named "flow" that supports creating user scenarios executed right at the ESP8266 device running espurna firmware. Such scenarios are created using flow editor that is similar to node-red and others flow-based programming systems
Now the editor is implemented as a separate web application that should be run at the local computer (https://github.com/eschava/espurna-flow-editor) because it is large enough (13 MB). It uses AJAX requests to load/save current flow from/to espurna device.
Currently, only three types of nodes are implemented: MQTT subscribe, MQTT publish and Debug just to check that concept is working and evaluate interest to this feature
Flow is saved as JSON file at the SPIFFS storage so only devices having SPIFFS are supported (I use Shelly1 for my experiments)
Screenshot of flow editor is attached
To build firmware with all required functionality I used next flags:
(WEB_REMOTE_DOMAIN is needed to allow AJAX requests to device from the remote site, by default it has http://tinkerman.cat value. I tried to host editor at the GitHub pages but it allows to use HTTPS only and it cannot access espurna device using HTTP due to security reasons)
I'm going to extend web flow editor with new features and implement new types of nodes (supporting buttons, relays, values comparison, etc) but created this pull request to get some feedback ASAP