summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAki <please@ignore.pl>2024-01-13 02:53:38 +0100
committerAki <please@ignore.pl>2024-01-13 02:53:38 +0100
commit6e430351816299521461739ce40af0493e358d8a (patch)
tree99d009ec11095de3ef9a7f6167be717f6880a204
downloadnodemcu-wakeup-6e430351816299521461739ce40af0493e358d8a.zip
nodemcu-wakeup-6e430351816299521461739ce40af0493e358d8a.tar.gz
nodemcu-wakeup-6e430351816299521461739ce40af0493e358d8a.tar.bz2
Implemented enough to wake up a sleepy server by connecting nodemcu to dc power
-rw-r--r--.gitignore1
-rw-r--r--init.lua22
-rw-r--r--run.lua81
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
diff --git a/run.lua b/run.lua
new file mode 100644
index 0000000..3c22c30
--- /dev/null
+++ b/run.lua
@@ -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