Read original post here
Today I worked on improving the operability of my M5Stick-C Tally Indicator project, Talyte.
Prior to today’s change, selecting the wireless network to join, as well as the WebSockets server address of OBS was not a quick task. The credentials and addresses were hardcoded into the binary, requiring you to recompile the sources and flash the device after you changed the data in the source code.
During the last wedding livestream I worked at, I did not have ample time to prepare and test that Talyte would work on streaming computer (thankfully it did though). I arbitrarily hardcoded the wireless network and address data, compiled and flashed the M5Stick-C devices. I definitely wanted to make sure to implement a proper configurator down the line.
To implement this configurator, I needed to do two main things, the frontend page, and the backend. I knew that there was a ready-made (and much better written) wireless setup utility library called WiFiManager, however I wasn’t sure how extensible it was (i.e. adding my own custom inputs fields etc) - So as per usual I wrote my own!
I did definitely use that library as a boilerplate to understanding the WiFi.h
and WebServer.h
libraries so thanks tzapu and co!
Frontend
Technologies: Svelte (w/ Sapper), Bulma
I built a pretty simple webpage with Svelte (my go-to JS/HTML framework of choice) that would effectively just be some input elements, and a submit button. I haven’t used the Bulma CSS framework for a while, so I decided to give that a whirl again.
Originally I had planned to have the WiFi configuration page separate to the Tally configuration page - and so I had used the Sapper framework to handle multi-page navigation… But eventually I had consolidated both settings pages into just a single page… I kept using Sapper though so that I could feed stub data to the client whilst developing it on my computer.
The page makes two calls to the backend to retrieve a list of scanned wireless networks, and to get the previous configuration. I’m not sure if I want it to send the wireless passwords back and forth though, as it currently is.. 🤔
Backend
Technologies: C++, WebServer.h, Preferences.h, RapidJSON
Since the rest of the Talyte code is written in C++, I went to figure out what C/C++ libraries were available to use.
To store data, I opted to use the Preferences.h
non-volatile memory library over the EEPROM library, although honestly I have no clue if it’s better or not. There were some comments in the docs about the wear leveling being better with the non-volatile memory over the EEPROM, as writing to the exact same spot in the EEPROM will eventually use up the semiconductor’s rated write cycles. Makes sense I guess.
Linking
Communication of data between the frontend and backend was done over HTTP, through the WebServer.h
library. It didn’t seem to have native JSON body content parsing, so I changed the form submission on the frontend to send it as form data, rather than a JSON payload. Otherwise all is well
SPIFFS
To get my frontend code served by the Arduino code, I had to either hardcode the page data into the firmware (as done by WifiManager), or use the internal 4MB of storage on the M5Stick-C.
Unfortunately, file paths are restricted to 31 bytes (the entire path), so I ran into issues where the files exported by Sapper were too large, and it would cause the building of the filesystem image to fail. I settled upon extending the export script to naively rename/replace any instances of /client/
or /legacy/
to something shorter.
So far so good, and the world hasn’t burst into flames yet 😅
Whilst testing the devices, I was slightly scared for a bit that the MAC address assignments weren’t actually random - as I had two devices with the starting prefix 94:B9:7E
… in fact they even shared the same fourth byte - however the fifth and six bytes were (thankfully) different, so my addresses were still unique.
On a high level there wasn’t really too much to add and change. Modify the hardcoded references to some function that retrieves data from the device memory, create a HTML page with data, and pass between the two ends.
Ironically it took me around 12 hours, with lots of time for debugging and things just not working 🙃. Maybe starting a project when you’re half asleep is probably not the best of time to do it. But hey I recorded the entire coding session so the future me can laugh at how dumb I am at time.