diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | init.lua | 22 | ||||
-rw-r--r-- | run.lua | 81 |
3 files changed, 104 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fee9217 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.conf diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..1756628 --- /dev/null +++ b/init.lua @@ -0,0 +1,22 @@ +--- Somewhat safely loads "run.lua" module into a global variable RUN. Loaded module itself should be a function. If +--- everything seems fine, true is returned. +function init () + wifi.setmode(wifi.NULLMODE, false) + local l, r = pcall(require, "run") + if not l then + print("run.lua not found") + return + end + RUN = r + l, r = node.bootreason() + if l == 2 and (r == 2 or r == 4) then + print("Most likely an exception restarted last boot, run.lua loaded into RUN and left as is") + return + end + return true +end + + +if init() then + RUN() +end @@ -0,0 +1,81 @@ +local wol = { + port = 9, + timer = tmr.create(), +} + + +--- Reads configuration file at [[path]] and parses a pair of MAC and broadcast addresses from it. Builds a Wake-on-LAN +--- magic packet and saves it for later use with :worker(). Returns true if no errors were encountered, otherwise a nil. +function wol:configure (path) + local fd = file.open(path) + if not fd then + print("Config file not found", path) + return + end + local line = fd:readline() + fd:close() + fd = nil + self.mac, self.addr = line:match("^(%S+)%s+(%S+)") + self.data = "" + for octet in self.mac:gmatch("%x%x") do + self.data = self.data .. string.char(tonumber(octet, 16)) + end + if #self.data ~= 6 then + print(string.format("Invalid MAC\t%q", self.mac)) + return + end + self.data = string.char(0xff):rep(6) .. self.data:rep(16) + return true +end + + +--- Initializes and returns worker that implements :sendout(interval, times, callback) that attempts to wake up +--- designated host number of [[times]] each separated by [[interval]]. After all attempts [[callback]] is called. +function wol:worker () + return { + config = self, + udp = net.createUDPSocket(), + timer = tmr.create(), + count = 0, + sendout = function (self, interval, times, cb) + self.times = times + return self.timer:alarm(interval, tmr.ALARM_SEMI, function (timer) + self.count = self.count + 1 + if self.count <= self.times then + print("Waking up", self.config.mac, self.config.addr) + self.udp:send(self.config.port, self.config.addr, self.config.data) + timer:start() + else + timer:unregister() + cb() + end + end) + end, + } +end + + +wol.timer:register(1000, tmr.ALARM_SINGLE, function () + gpio.mode(4, gpio.OUTPUT) + gpio.write(4, gpio.HIGH) + if not wol:configure("wakeup.conf") then + error("Could not configure wakeup") + end + wifi.setmode(wifi.STATION, false) + + wifi.eventmon.register(wifi.eventmon.STA_GOT_IP, function () + local waker = wol:worker() + gpio.write(4, gpio.LOW) + waker:sendout(500, 5, function () + wifi.setmode(wifi.NULLMODE, false) + gpio.write(4, gpio.HIGH) + end) + end) + + wifi.sta.connect() +end) + + +return function () + wol.timer:start() +end |