-- Never change these unless the board changes started = false light_pin = 5 motion_pin = 7 --turn_off_timeout = 1000*60*1 -- for turning off if it triggered via sensor turn_off_timer = tmr.create() timeout_settings = {["turn_off_timeout"]=1000*60*30, ["turn_off_timeout_minutes"]=30} gpio.mode(motion_pin, gpio.INT) function set_turn_off_timeout(new_timeout) if new_timeout > 0 and new_timeout < 1440 then timeout_settings["turn_off_timeout_minutes"] = new_timeout timeout_settings["turn_off_timeout"] = 1000*60*new_timeout end end function calc_duty_cycle(duty_cycle_factor) if duty_cycle_factor < 1 then return 0 else return 1023 / duty_cycle_factor end end global_duty_cycle = calc_duty_cycle(1) function debounce (func) local last = 0 local delay = 500000 return function (...) local now = tmr.now() local delta = now - last if delta < 0 then delta = delta + 2147483647 end if delta < delay then return end last = now return func(...) end end -- pwm.setup(pin, frequency, duty cycle) -- max duty cycle is 1023, min 1 pwm.setup(light_pin, 500, 1023) pwm.start(light_pin) current_mode = nil pins = {toggle_light_pin=light_pin} lights = {} if gpio.read(light_pin) == 1 then lights[light_pin] = true else lights[light_pin] = false end function turn_light_on(pin, duty_cycle, reset_timeout) lights[pin] = true pwm.setduty(pin, duty_cycle) if reset_timeout then turn_off_timer:stop() turn_off_timer:unregister() end end function to_percent(a, b) return (a*b)/100 end function get_duty_cycle_percentage(pin) local d = pwm.getduty(pin) return (d*100)/1023 end function set_light_brightness(pin, percentage) --print("percentage = " .. tostring(percentage)) local duty_cycle = to_percent(1023, percentage) --print("set light to " .. tostring(duty_cycle)) pwm.setduty(pin, duty_cycle) global_duty_cycle = duty_cycle if duty_cycle > 0 then lights[pin] = true else lights[pin] = false end end function turn_light_off(pin) if lights[pin] then pwm.setduty(pin, 0) lights[pin] = false end end function toggle_light(pin) --print("Toggling " .. tostring(pin)) if lights[pin] then turn_light_off(pin) else turn_light_on(pin, global_duty_cycle, true) end end function sensor_trigger_on(level, ts, evcount) if level == gpio.HIGH and gpio.read(light_pin) == 0 then --print("sensor pin is high") turn_light_on(light_pin, global_duty_cycle, true) turn_off_timer:register(timeout_settings["turn_off_timeout"], tmr.ALARM_SINGLE, function() turn_light_off(light_pin) end) turn_off_timer:start() end end gpio.trig(motion_pin, "up", sensor_trigger_on) function is_table(v) local is_it_a_table, _ = pcall(function() return v["is_table"] end) return is_it_a_table end function show_pair(key, value) -- TODO handle case of array and then call back to show_list if is_table(value) then return "("..tostring(key) .. " . " .. tostring(show_table(value)) .. ")" else return "("..tostring(key) .. " . " .. tostring(value) .. ")" end end function show_table(t) result = "" for key, value in pairs(t) do result = result .. show_pair(key, value) end return "(" .. result .. ")" end function show_list(ts) if is_table(12) or (not is_table({light_pin=12})) then return "" end result = "" for _, t in ipairs(ts) do if is_table(t) then result = result .. show_table(t) else result = result .. tostring(t) end end return "(" .. result .. ")" end print("Booted up") 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 extract_formdata(s) local cgi = {} for name, value in string.gmatch(s, "([^&=]+)=([^&=]+)") do cgi[name] = value end return cgi end function get_info(group) local info = node.info(group) local result = "" result = result .. "" for key, value in pairs(info) do result = result .. "" end return result .. "
" .. tostring(group) .. "
Uptime: ".. tostring(tmr.time()) .. " seconds
" .. tostring(key) .. "" .. tostring(value) .. "
" end function compose(f, g) return function(x) f(g(x)) end end function gen_select(name, id, options) local result = "" end function gen_range_select(name, id, options) local min = options["min"] local max = options["max"] local value = options["value"] return "" end function gen_num_select(name, id, options) local min = options["min"] local max = options["max"] local value = options["value"] return "" end function gen_form(form_name, name, endpoint, fields, gen_inputs) local result = "

" .. form_name .. "

" result = result .. gen_inputs(name, endpoint, fields) return result .. "
" end function gen_buttons(name, endpoint, fields) local result = "

" .. name .. "

" for key, value in pairs(fields) do result = result .. "
" result = result .. "" .. "status here" .. "
" end return result end function startup() sntp.sync( nil, function(sec, usec, server, info) print('synced ntp ', sec, usec, server) if not started then started = true end end, function() print('failed to sync ntp') end, 1 -- auto-repeat sync ) file.close("_init.lua") print("Starting up") local httpserver = node.LFS.get("httpserver")() print(httpserver) 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 local params = extract_formdata(urldecode(chunk)) if params["toggle"] ~= nil then toggle_light(pins[params["toggle"]]) end elseif req.url == "/reboot" then node.restart() elseif req.url == "/set_brightness" then local params = extract_formdata(urldecode(chunk)) if params["set_brightness"] ~= nil then local percentage = tonumber(params["set_brightness"]) set_light_brightness(light_pin, percentage) end elseif req.url == "/set_timeout" then local params = extract_formdata(urldecode(chunk)) if params["set_timeout"] ~= nil then local new_timeout = tonumber(params["set_timeout"]) set_turn_off_timeout(new_timeout) end end end if not chunk then -- reply if req.url == "/" then res:send(nil, 200) res:send_header("Content-Type", "text/html") res:send_header("Connection", "close") local current_dc_percent = tostring(get_duty_cycle_percentage(light_pin)) local toggle_lights_form = gen_form("Lights", "Toggle Lights", "toggle", {["toggle_light_pin"]="Light"}, gen_select) local set_brightness_form = gen_form("Brightness", "Set Brightness (%)", "set_brightness", {["min"]="0", ["max"]="100", ["value"]=current_dc_percent}, gen_range_select) local set_timeout_form = gen_form("Timeout", "Set Timeout (minutes)", "set_timeout", {["min"]="0", ["max"]="1440", ["value"]=timeout_settings["turn_off_timeout_minutes"]}, gen_num_select) res:send("

Light Config

" .. toggle_lights_form .. set_brightness_form .. set_timeout_form .. "
" .. get_info("hw") .. get_info("build_config") .. get_info("sw_version") .. "
") res:send("\r\n") elseif req.url == "/toggle" 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 == "/set_brightness" then res:send(nil, 303) res:send_header("Location", "/") res:send_header("Connection", "close") res:send("setting brightness\r\n") res:send("\r\n") elseif req.url == "/set_timeout" then res:send(nil, 303) res:send_header("Location", "/") res:send_header("Connection", "close") res:send("setting timeout\r\n") res:send("\r\n") 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 function connect_wifi() print("Turning lights off") if gpio.read(light_pin) == 1 then lights[light_pin] = true else lights[light_pin] = false end turn_light_off(light_pin) --wifi.sta.clearconfig() print("Trying to connect to wifi with captive portal") enduser_setup.start("Reading Light", function() print("in connection function") --print("Connected to WiFi as:" .. wifi.sta.getip()) tmr.create():alarm(3000, tmr.ALARM_SINGLE, startup) end, function(err, str) print("enduser_setup: Err #" .. err .. ": " .. str) end, print ) end connect_wifi()