I finally broke down and deployed an init.lua. This autoexec's the software at boot time. I added an emergency bypass mechanism.
Up until now I have been hesitant to deploy init.lua. This is the 'autoexec' module that causes the program to be loaded on boot. The reason for holding back is fear of 'bricking' the NodeMCU board with broken, but autoexeced, code. It wouldn't really have been bricked, but it would be less-than-convenient to recover.
But the project is pretty stable now, and I thought about adding a simple fail-safe: Have init.lua check if the 'user' button is pressed. If it is pressed, skip running the program and fall back to the Lua shell.
Easy-peasy, or so it seemed. It turns out that the 'user' button is special in a way. Even just looking at it on the schematic, you can see it is kind of funky:
The GPIO 16 (board numbered as 0) can be used as an input to read the button, or an output to light the lamp. And apparently that's not the end of the story, because it is also used for some other ESP8266 function ('wakeup'?).
When operated in the straightforward mode of setting the pin as an input (with pullup) and reading it, the button did read as high when not pressed, and low when pressed, but then stayed reading as low even when it was released. Maybe that's some interaction with the other ESP8266 function.
Anyway, I worked around that oddity by being super explicit around where I sample the button to restore it to it's prior state. The result is this init.lua:
-- if we hold down the user button during boot, we will skip running our program gpio.mode(0,gpio.INPUT,gpio.PULLUP) -- you have to go through this sequence local nUser = gpio.read(0) -- print ( "nUser = "..nUser ) gpio.write(0,gpio.HIGH) gpio.mode(0,gpio.OUTPUT) -- the GPIO 16 (index 0) requires special treatment if ( gpio.LOW == nUser ) then print ( "Skipping running because user button down" ) else -- call invoke the _init on the LFS; this will wire in the LFS in useful ways if ( not pcall(node.flashindex("_init")) ) then -- no LFS print ( "Horror; no LFS _init" ) else --local ok, msg = pcall ( function() return dofile("kosbo.lua") end ) end end
So, I flashed that and verified it was working. So now, when I plug in the clock, it will automatically run the program and set the time from the Internet.
Strictly, I can consider the project 'done' now. It boots up, connects to WiFi, synchronizes time via SNTP, resets the clock immediately, and then periodically thereafter at 2 AM daily.
Now it's time for fun oddities. I am thinking about some web service protocol so that a web app can control it in some way.
Some sort of server.