summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAki <please@ignore.pl>2024-01-22 18:37:04 +0100
committerAki <please@ignore.pl>2024-01-22 18:37:04 +0100
commit7b6c20b5c58014861e218e62cf0749bdd0ba727e (patch)
tree56101658210bc39d21631e7f1a90be363807d4d1
parent188b980b2597d39052004cb56277b1684df0007d (diff)
downloadnodemcu-wakeup-7b6c20b5c58014861e218e62cf0749bdd0ba727e.zip
nodemcu-wakeup-7b6c20b5c58014861e218e62cf0749bdd0ba727e.tar.gz
nodemcu-wakeup-7b6c20b5c58014861e218e62cf0749bdd0ba727e.tar.bz2
Use a state machine to perform preparation and wakeups
-rw-r--r--run.lua9
-rw-r--r--wakeup.lua150
2 files changed, 94 insertions, 65 deletions
diff --git a/run.lua b/run.lua
index 43f7cad..e5a7627 100644
--- a/run.lua
+++ b/run.lua
@@ -1,6 +1,11 @@
local wakeup = require("wakeup")
return function ()
- wakeup:init()
- tmr.create():alarm(1000, tmr.ALARM_SINGLE, function () wakeup:run() end)
+ tmr.create():alarm(
+ 500,
+ tmr.ALARM_AUTO,
+ function (timer)
+ wakeup:step(timer)
+ collectgarbage()
+ end)
end
diff --git a/wakeup.lua b/wakeup.lua
index 9b5b6a4..8b9a893 100644
--- a/wakeup.lua
+++ b/wakeup.lua
@@ -15,49 +15,45 @@ function magic_packet (mac)
end
-function wakeup:open ()
- self.udp = net.createUDPSocket()
+--- Perform the most basic preparations right after device booted up.
+function wakeup:boot ()
+ gpio.write(4, gpio.HIGH)
+ gpio.mode(4, gpio.OUTPUT)
+ self.data = magic_packet(self.mac)
+ self.step = self.connect
end
-function wakeup:close ()
- if self.udp then
- self.udp:close()
- end
+--- This is the current state action of the wake-up state machine. It is a callable that has [[(self, [timer]) -> nil]]
+--- signature. Steps are called sequentially, usually by a tmr.timer.
+wakeup.step = wakeup.boot
+
+
+--- Marks a failure that is pointless to attempt to recover from, e.g., if provided configuration is incomplete.
+function wakeup:hard_failure (timer)
+ print("Aborting...")
+ return timer:unregister()
end
---- Creates a new counter that has :up() method that returns true until it gets called N [[times]]. Then it returns only
---- false.
-local
-function new_counter (times)
- return {
- count = 0,
- times = times,
- up = function (self)
- self.count = self.count + 1
- return self.count <= self.times
- end,
- }
+--- Marks a failure that device may recover from by restarting itself.
+function wakeup:soft_failure ()
+ node.restart()
end
---- Begins to send Wake-on-LAN magic packets to the broadcast [[.addr]] for selected [[.mac]]. Packets are sent several
---- [[times]] each separated by [[interval]]. Callback is called [[after]] all packets are sent.
-function wakeup:sendout (interval, times, after)
- self:open()
- local count = new_counter(times)
- return tmr.create():alarm(interval, tmr.ALARM_SEMI, function (timer)
- if count:up() then
- print("Waking up", self.mac, self.addr)
- self.udp:send(self.port, self.addr, self.data)
- timer:start()
- else
- timer:unregister()
- self:close()
- after()
- end
+function wakeup:connect ()
+ self.step = self.wait_for_ip
+ wifi.eventmon.register(wifi.eventmon.STA_GOT_IP, function ()
+ self.step = self.sync_time
end)
+ wifi.setmode(wifi.STATION, false)
+ wifi.sta.connect()
+end
+
+
+function wakeup:wait_for_ip ()
+ -- no-op -- TODO: soft_failure if too long?
end
@@ -69,6 +65,25 @@ function wakeup:now ()
end
+function wakeup:sync_time ()
+ self.step = self.wait_for_time
+ sntp.sync(
+ self.sntp,
+ function ()
+ self.step = self.check_time
+ end,
+ function (code, err)
+ print("SNTP sync failed", code, err)
+ self.step = self.soft_failure
+ end)
+end
+
+
+function wakeup:wait_for_time ()
+ -- no-op -- TODO: soft_failure if too long?
+end
+
+
local
function compare (time, pattern)
for key, value in pairs(pattern) do
@@ -80,40 +95,49 @@ function compare (time, pattern)
end
-function wakeup:init ()
- gpio.write(4, gpio.HIGH)
- gpio.mode(4, gpio.OUTPUT)
- self.data = magic_packet(self.mac)
+--- Creates a new counter that has :up() method that returns true until it gets called N [[times]]. Then it returns only
+--- false.
+local
+function new_counter (times)
+ return {
+ count = 0,
+ times = times,
+ up = function (self)
+ self.count = self.count + 1
+ return self.count <= self.times
+ end,
+ }
+end
- wifi.eventmon.register(wifi.eventmon.STA_GOT_IP, function ()
- sntp.sync(
- self.sntp,
- function ()
- if compare(self:now(), self.when) then
- gpio.write(4, gpio.LOW)
- self:sendout(500, 5, function ()
- wifi.setmode(wifi.NULLMODE, false)
- gpio.write(4, gpio.HIGH)
- end)
- else
- print("Not yet time")
- wifi.setmode(wifi.NULLMODE, false)
- tmr.create():alarm(25000, tmr.ALARM_SINGLE, function ()
- self:run()
- end)
- end
- end,
- function (code, err)
- print("SNTP sync failed", code, err)
- node.restart()
- end)
- end)
+
+--- Creates new state machine action that sends out Wake-on-LAN magic packets to configured host N [[times]].
+local
+function start_sendout (times)
+ local self = new_counter(times)
+ self.udp = net.createUDPSocket()
+ return function (wakeup, timer)
+ if self:up() then
+ print("Waking up", wakeup.mac, wakeup.addr)
+ self.udp:send(wakeup.port, wakeup.addr, wakeup.data)
+ else
+ self.udp:close()
+ timer:unregister()
+ wifi.setmode(wifi.NULLMODE, false)
+ gpio.write(4, gpio.HIGH)
+ print("Done")
+ end
+ end
end
-function wakeup:run ()
- wifi.setmode(wifi.STATION, false)
- wifi.sta.connect()
+function wakeup:check_time (timer)
+ if compare(self:now(), self.when) then
+ gpio.write(4, gpio.LOW)
+ self.step = start_sendout(5)
+ else
+ print("Not yet time")
+ timer:unregister()
+ end
end