Code for a smart light built using an esp8266
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

184 lines
6.2 KiB

-- Never change these unless the board changes
trig_pin = 5
light_on = false
function reset_light()
gpio.write(trig_pin, gpio.LOW)
tmr.delay(100000)
gpio.write(trig_pin, gpio.HIGH)
tmr.delay(100000)
gpio.write(trig_pin, gpio.LOW)
end
function toggle_light()
print("toggling")
reset_light()
light_on = not light_on
file.putcontents("./light_status", light_on and "on" or "off")
end
function turn_light_on()
if not light_on then
toggle_light()
end
end
function turn_light_off()
if light_on then
toggle_light()
end
end
light_status = file.getcontents("./light_status")
if light_status == "on" then
turn_light_on()
end
print("Booted up")
gpio.mode(trig_pin, gpio.OUTPUT)
gpio.write(trig_pin, gpio.LOW)
function hex_to_char(x)
return string.char(tonumber(x, 16))
end
function get_time()
local t = tmr.time()
local hours = t/3600
local seconds_leftover = t % 3600
return tostring(hours) .. " hours, " .. tostring(minutes_leftover)
end
function urldecode(url)
if url == nil then
return
end
url = url:gsub("+", " ")
url = url:gsub("%%(%x%x)", hex_to_char)
return url
end
function get_info(group)
local info = node.info(group)
local result = "<table><thead><tr><th colspan='2'>" .. tostring(group) .. "</th></thead><tbody>"
for key, value in pairs(info) do
result = result .. "<tr><td>" .. tostring(key) .. "</td><td>" .. tostring(value) .. "</td></tr>"
end
return result .. "</tbody></table>"
end
function startup()
sntp.sync(
nil,
function(sec, usec, server, info)
print('synced ntp ', sec, usec, server)
end,
function()
print('failed to sync ntp')
end,
1 -- auto-repeat sync
)
if file.open("init.lua") == nil then
print("init.lua deleted or renamed")
else
cron_error = nil
file.close("init.lua")
print("Starting up")
require("httpserver").createServer(8080, function(req, res)
--print("+R", req.method, req.url, node.heap())
req.ondata = function(self, chunk)
--print("+B", chunk and #chunk, node.heap())
print(req.url)
if chunk ~= nil then
if req.url == "/toggle" then
toggle_light()
elseif req.url == "/on" then
turn_light_on()
elseif req.url == "/off" then
turn_light_off()
elseif req.url == "/add_job" then
post_data = urldecode(chunk)
if string.len(post_data) > 6 then
local a, b = string.find(post_data, "=")
local cron_expression = post_data:sub(a+1)
local ran, error_msg = pcall(cron.schedule, cron_expression, toggle_light)
print(error_msg)
else
ran = false
error_msg = "invalid"
end
if not ran then
print("post_data = " .. post_data)
cron_error = error_msg
end
elseif req.url == "/reset_light" then
reset_light()
elseif req.url == "/clear_jobs" then
cron.reset()
elseif req.url == "/reboot" then
cron.reset()
node.restart()
end
end
if not chunk then
local toggle_status = light_on and "On" or "Off"
local color = light_on and "green" or "black"
-- reply
if req.url == "/" then
res:send(nil, 200)
res:send_header("Content-Type", "text/html")
res:send_header("Connection", "close")
res:send("<style>.button{text-decoration:underline;}.body{padding:0; margin:0;}.par{display:flex;flex-direction:row;}.a{margin: auto;width:50%;}.b{margin: auto;width:50%;}</style><html><body><div class='par'><div class='a'><span>Uptime: ".. tostring(tmr.time()) .. " seconds</span><form action='/add_job' method='post'><div class='button'><label for='name'>Enter a cron expression (UTC)</label><input type='text' name='cron' id='cron' required></div><div><input type='submit' value='Add cron expression'></div></form><br/><form action='/clear_jobs' method='post'><button style=\"color:black;\">Clear Jobs</button></form><br/><form action='/toggle' method='post'><button style=\"color:black;\">Toggle</button><span style=\"color:" .. color .. ";\"> ".. toggle_status .. "</span></form><br/><form action='/reset_light' method='post'><button style=\"color:black;\">Reset Light</button></form><br/><form action='/reboot' method='post'><button style=\"color:red;\">Reboot</button></form><br/></div><div class='b'>" .. get_info("hw") .. get_info("build_config") .. get_info("sw_version") .. "</div></div></body></html>")
res:send("\r\n")
elseif req.url == "/toggle" or req.url == "/reset_light" then
res:send(nil, 303)
res:send_header("Location", "/")
res:send_header("Connection", "close")
res:send("switching light\r\n")
res:send("\r\n")
elseif req.url == "/add_job" then
if cron_error then
res:send(nil, 400)
res:send_header("Content-Type", "text/html")
res:send_header("Connection", "close")
res:send(cron_error .. "\r\n")
res:send("\r\n")
cron_error = nil
else
res:send(nil, 303)
res:send_header("Location", "/")
res:send_header("Connection", "close")
res:send("\r\n")
end
else
res:send(nil, 303)
res:send_header("Location", "/")
res:send_header("Connection", "close")
res:send("\r\n")
end
res:finish()
end
end
end)
end
end
enduser_setup.start(
function()
if wifi.sta.getip() ~= nil then
print("Connected to WiFi as:" .. wifi.sta.getip())
tmr.create():alarm(3000, tmr.ALARM_SINGLE, startup)
end
end,
function(err, str)
print("enduser_setup: Err #" .. err .. ": " .. str)
end,
print
)