From 0ff40d99e0d9db70311a78011ad52e603beec0ab Mon Sep 17 00:00:00 2001 From: Aki Date: Mon, 22 Jan 2024 21:35:45 +0100 Subject: Implemented deep sleep that does not work currently Doesn't seem to react to rstime.dsleep with RST connected to GPIO16 --- wakeup.lua | 133 +++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 82 insertions(+), 51 deletions(-) (limited to 'wakeup.lua') diff --git a/wakeup.lua b/wakeup.lua index 8b9a893..ec8b78a 100644 --- a/wakeup.lua +++ b/wakeup.lua @@ -15,6 +15,21 @@ function magic_packet (mac) 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, + } +end + + --- Perform the most basic preparations right after device booted up. function wakeup:boot () gpio.write(4, gpio.HIGH) @@ -29,6 +44,18 @@ end wakeup.step = wakeup.boot +--- Will tick for N [[ticks]] and then switch into a state [[after]]. +local +function start_timeout (ticks, after) + local self = new_counter(ticks) + return function (wakeup) + if not self:up() then + wakeup = after + end + end +end + + --- 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...") @@ -43,7 +70,7 @@ end function wakeup:connect () - self.step = self.wait_for_ip + self.step = start_timeout(10, self.soft_failure) wifi.eventmon.register(wifi.eventmon.STA_GOT_IP, function () self.step = self.sync_time end) @@ -52,21 +79,8 @@ function wakeup:connect () end -function wakeup:wait_for_ip () - -- no-op -- TODO: soft_failure if too long? -end - - -function wakeup:now () - local time = rtctime.epoch2cal(rtctime.get()) - time.year = nil - time.sec = nil - return time -end - - function wakeup:sync_time () - self.step = self.wait_for_time + self.step = start_timeout(10, self.soft_failure) sntp.sync( self.sntp, function () @@ -79,37 +93,6 @@ function wakeup:sync_time () 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 - if time[key] ~= value then - return false - end - end - return true -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, - } -end - - --- Creates new state machine action that sends out Wake-on-LAN magic packets to configured host N [[times]]. local function start_sendout (times) @@ -121,24 +104,72 @@ function start_sendout (times) 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) + wifi.setmode(wifi.NULLMODE, false) + timer:interval(61000) + self.step = self.soft_failure print("Done") end end end +--- Current UTC wall clock time. +local +function now () + local time = rtctime.epoch2cal(rtctime.get()) + return {hour = time.hour, min = time.min} +end + + +--- Time in minutes to next occurrence of [[pattern]] starting from [[time]]. +local +function upcoming (pattern, time) + local hours = 0 + if pattern.hour then + hours = pattern.hour - time.hour + if hours < 0 then + hours = hours + 24 + end + end + local minutes = 0 + if pattern.min then + minutes = pattern.min - time.min + if minutes < 0 then + minutes = minutes + 60 + if hours > 0 then + hours = hours - 1 + end + end + end + return hours * 60 + minutes +end + + function wakeup:check_time (timer) - if compare(self:now(), self.when) then + local left = upcoming(self.when, now()) + if left == 0 then gpio.write(4, gpio.LOW) self.step = start_sendout(5) + elseif left > 5 then + print(string.format("Need to wait total %d minutes", left)) + left = left - 5 + if left > 50 then + left = 50 + end + self.left = left + self.step = start_timeout(3, self.sleep) + print(string.format("Going to sleep %d minutes", left)) else - print("Not yet time") - timer:unregister() + print(string.format("Wake-up in %d minutes", left)) + timer:interval(15000) end end +function wakeup:sleep () + rtctime.dsleep(self.left * 6e7, 1) +end + + return wakeup -- cgit v1.1