Overhaul garage door example (#93)
* script for controlling garage that is aware of door states * Overhaul garage door example Hardware now calls for reed relay in order to be able to tell the state of the switch. This way, we can have distinct open/close operations that error if the door is already in that state. Allows for potential better integration with home automation systems. * Prepare for push to GitHub * Restore defaults * Make HTTP auth realm match zeroconf networking name
This commit is contained in:
parent
a96ebc6196
commit
adde150009
32
http/garage_door.html
Normal file
32
http/garage_door.html
Normal file
@ -0,0 +1,32 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Garage control</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div align="center">
|
||||
|
||||
<h2>Door 1</h2>
|
||||
|
||||
<form action="garage_door.lua" method="post"/>
|
||||
<input type="hidden" name="door" value="1"/>
|
||||
<input type="submit" name="action" value="status"/>
|
||||
<input type="submit" name="action" value="open"/>
|
||||
<input type="submit" name="action" value="close"/>
|
||||
<input type="submit" name="action" value="toggle"/>
|
||||
</form>
|
||||
|
||||
<h2>Door 2</h2>
|
||||
|
||||
<form action="garage_door.lua" method="post"/>
|
||||
<input type="hidden" name="door" value="2"/>
|
||||
<input type="submit" name="action" value="status"/>
|
||||
<input type="submit" name="action" value="open"/>
|
||||
<input type="submit" name="action" value="close"/>
|
||||
<input type="submit" name="action" value="toggle"/>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
153
http/garage_door.lua
Normal file
153
http/garage_door.lua
Normal file
@ -0,0 +1,153 @@
|
||||
-- garage_door_open.lua
|
||||
-- Part of nodemcu-httpserver, example.
|
||||
-- Author: Marcos Kirsch
|
||||
|
||||
--[[
|
||||
This example assumed you have a Wemos D1 Pro to control a two-door garage.
|
||||
For each garage door, a Wemos relay shield is used to simulate a button (connect relay in
|
||||
parallel with the actual physical button) and a reed switch is used in order to know
|
||||
whether a door is currently open or closed (install switch so that it is in the closed
|
||||
position when your garage door is closed).
|
||||
|
||||
You can configure which GPIO pins you use for each function by modifying variable
|
||||
pinConfig below.
|
||||
]]--
|
||||
|
||||
local function pushTheButton(connection, pinConfig)
|
||||
-- push the button!
|
||||
gpio.write(pinConfig["controlPin"], gpio.HIGH)
|
||||
gpio.mode(pinConfig["controlPin"], gpio.OUTPUT, gpio.FLOAT)
|
||||
tmr.delay(300000) -- in microseconds
|
||||
gpio.mode(pinConfig["controlPin"], gpio.INPUT, gpio.FLOAT)
|
||||
gpio.write(pinConfig["controlPin"], gpio.LOW)
|
||||
end
|
||||
|
||||
|
||||
local function readDoorStatus(pinConfig)
|
||||
-- When the garage door is closed, the reed relay closes, grounding the pin and causing us to read low (0).
|
||||
-- When the garage door is open, the reed relay is open, so due to pullup we read high (1).
|
||||
gpio.write(pinConfig["statusPin"], gpio.HIGH)
|
||||
gpio.mode(pinConfig["statusPin"], gpio.INPUT, gpio.PULLUP)
|
||||
if gpio.read(pinConfig["statusPin"]) == 1 then return 'open' else return 'closed' end
|
||||
end
|
||||
|
||||
|
||||
local function sendResponse(connection, httpCode, errorCode, action, pinConfig, message)
|
||||
|
||||
-- Handle nil inputs
|
||||
if action == nil then action = '' end
|
||||
if pinConfig == nil then
|
||||
pinConfig = {}
|
||||
pinConfig["door"] = 0
|
||||
pinConfig["controlPin"] = 0
|
||||
pinConfig["statusPin"] = 0
|
||||
end
|
||||
if message == nil then message = '' end
|
||||
|
||||
connection:send("HTTP/1.0 "..httpCode.." OK\r\nContent-Type: application/json\r\nCache-Control: private, no-store\r\n\r\n")
|
||||
connection:send('{"error":'..errorCode..', "door":'..pinConfig["door"]..', "controlPin":'..pinConfig["controlPin"]..', "statusPin":'..pinConfig["statusPin"]..', "action":"'..action..'", "message":"'..message..'"}')
|
||||
end
|
||||
|
||||
|
||||
local function sendStatus(connection, pinConfig)
|
||||
connection:send("HTTP/1.0 200 OK\r\nContent-Type: application/json\r\nCache-Control: private, no-store\r\n\r\n")
|
||||
connection:send('{"error":0, "door":'..pinConfig["door"]..', "controlPin":'..pinConfig["controlPin"]..', "statusPin":'..pinConfig["statusPin"]..', "action":"status"'..', "status":"'..readDoorStatus(pinConfig)..'"}')
|
||||
end
|
||||
|
||||
|
||||
local function openDoor(connection, pinConfig)
|
||||
-- errors if door is already open.
|
||||
local doorStatus = readDoorStatus(pinConfig)
|
||||
if doorStatus == 'open' then
|
||||
return false
|
||||
else
|
||||
pushTheButton(connection, pinConfig)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function closeDoor(connection, pinConfig)
|
||||
-- errors if door is already closed.
|
||||
local doorStatus = readDoorStatus(pinConfig)
|
||||
if doorStatus == 'closed' then
|
||||
return false
|
||||
else
|
||||
pushTheButton(connection, pinConfig)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return function (connection, req, args)
|
||||
|
||||
-- The values for pinConfig depend on how your Wemo D1 mini Pro is wired.
|
||||
-- Adjust as needed.
|
||||
pinConfig = {}
|
||||
pinConfig["1"] = {}
|
||||
pinConfig["1"]["door"] = 1
|
||||
pinConfig["1"]["controlPin"] = 2
|
||||
pinConfig["1"]["statusPin"] = 5
|
||||
pinConfig["2"] = {}
|
||||
pinConfig["2"]["door"] = 2
|
||||
pinConfig["2"]["controlPin"] = 1
|
||||
pinConfig["2"]["statusPin"] = 6
|
||||
|
||||
-- Make this work with both GET and POST methods.
|
||||
-- In the POST case, we need to extract the arguments.
|
||||
print("method is " .. req.method)
|
||||
if req.method == "POST" then
|
||||
local rd = req.getRequestData()
|
||||
for name, value in pairs(rd) do
|
||||
args[name] = value
|
||||
end
|
||||
end
|
||||
|
||||
-- validate door input
|
||||
|
||||
if args.door == nil then
|
||||
sendResponse(connection, 400, -1, args.action, pinConfig[args.door], "No door specified")
|
||||
return
|
||||
end
|
||||
|
||||
if pinConfig[args.door] == nil then
|
||||
sendResponse(connection, 400, -2, args.action, pinConfig[args.door], "Bad door specified")
|
||||
return
|
||||
end
|
||||
|
||||
-- perform action
|
||||
|
||||
if args.action == "open" then
|
||||
if(openDoor(connection, pinConfig[args.door])) then
|
||||
sendResponse(connection, 200, 0, args.action, pinConfig[args.door], "Door opened")
|
||||
else
|
||||
sendResponse(connection, 400, -3, args.action, pinConfig[args.door], "Door is already open")
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if args.action == "close" then
|
||||
if(closeDoor(connection, pinConfig[args.door])) then
|
||||
sendResponse(connection, 200, 0, args.action, pinConfig[args.door], "Door closed")
|
||||
else
|
||||
sendResponse(connection, 400, -4, args.action, pinConfig[args.door], "Door is already closed")
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if args.action == "toggle" then
|
||||
pushTheButton(connection, pinConfig[args.door])
|
||||
sendResponse(connection, 200, 0, args.action, pinConfig[args.door], "Pushed the button")
|
||||
return
|
||||
end
|
||||
|
||||
if args.action == "status" then
|
||||
sendStatus(connection, pinConfig[args.door])
|
||||
return
|
||||
end
|
||||
|
||||
-- everything else is error
|
||||
|
||||
sendResponse(connection, 400, -5, args.action, pinConfig[args.door], "Bad action")
|
||||
|
||||
end
|
||||
@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" href="garage_door_opener.css">
|
||||
<link rel="stylesheet" type="text/css" href="garage_door_control.css">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
||||
<meta charset="UTF-8">
|
||||
<title>Garage Remote</title>
|
||||
@ -11,7 +11,7 @@
|
||||
|
||||
function pushTheButton(door)
|
||||
{
|
||||
var url = "/garage_door_opener.lua?door=" + door;
|
||||
var url = "/garage_door.lua?action=toggle&door=" + door;
|
||||
|
||||
xmlHttp = new XMLHttpRequest();
|
||||
xmlHttp.onreadystatechange = processRequest;
|
||||
@ -1,31 +0,0 @@
|
||||
-- garage_door_opener.lua
|
||||
-- Part of nodemcu-httpserver, example.
|
||||
-- Author: Marcos Kirsch
|
||||
|
||||
local function pushTheButton(connection, pin)
|
||||
|
||||
-- push the button!
|
||||
-- The hardware in this case is a Wemos D1 Pro with two relay shields.
|
||||
-- The first relay is controlled with D1.
|
||||
-- The second one was modified to be controlled with D2.
|
||||
gpio.write(pin, gpio.HIGH)
|
||||
gpio.mode(pin, gpio.OUTPUT, gpio.FLOAT)
|
||||
tmr.delay(300000) -- in microseconds
|
||||
gpio.mode(pin, gpio.INPUT, gpio.FLOAT)
|
||||
gpio.write(pin, gpio.LOW)
|
||||
|
||||
-- Send back JSON response.
|
||||
connection:send("HTTP/1.0 200 OK\r\nContent-Type: application/json\r\nCache-Control: private, no-store\r\n\r\n")
|
||||
connection:send('{"error":0, "message":"OK"}')
|
||||
|
||||
end
|
||||
|
||||
return function (connection, req, args)
|
||||
print('Garage door button was pressed!', args.door)
|
||||
if args.door == "1" then pushTheButton(connection, 1)
|
||||
elseif args.door == "2" then pushTheButton(connection, 2)
|
||||
else
|
||||
connection:send("HTTP/1.0 400 OK\r\nContent-Type: application/json\r\nCache-Control: private, no-store\r\n\r\n")
|
||||
connection:send('{"error":-1, "message":"Bad door"}')
|
||||
end
|
||||
end
|
||||
@ -27,7 +27,7 @@
|
||||
<li><a href="zipped.html.gz">Zipped</a>: Same exact file as served above. Server is smart enough to treat the .gz extension correctly (static but gzipped)</li>
|
||||
<li><a href="args.lua">Arguments</a>: Parses arguments passed in the URL and prints them. (Lua)</li>
|
||||
<li><a href="post.lua">Post</a>: A form that uses POST method. Displays different content based on HTTP method. (Lua)</li>
|
||||
<li><a href="garage_door_opener.html">Garage door opener</a>: Control GPIO lines via the server. (Lua)</li>
|
||||
<li><a href="garage_door.html">Garage door opener</a>: Control GPIO lines via the server. Or try this <a href="garage_door_control.html">simpler and nicer UI</a>. (Lua)</li>
|
||||
<li><a href="node_info.lua">NodeMCU info</a>: Shows some basic NodeMCU(Lua)</li>
|
||||
<li><a href="file_list.lua">List all server files</a>: Displays a list of all the server files. (Lua)</li>
|
||||
<li><a href="upload.html">Upload</a>: Update, remove, list files on the server. Beware security implications. By <a href="https://github.com/ATAMAH">ATAMAH</a>.</li>
|
||||
|
||||
@ -9,7 +9,7 @@ local auth = {}
|
||||
-- Set to true if you want to enable.
|
||||
auth.enabled = false
|
||||
-- Displayed in the login dialog users see before authenticating.
|
||||
auth.realm = "nodemcu-httpserver"
|
||||
auth.realm = "nodemcu"
|
||||
-- Add users and passwords to this table. Do not leave this unchanged if you enable authentication!
|
||||
auth.users = {user1 = "password1", user2 = "password2", user3 = "password3"}
|
||||
|
||||
|
||||
2
init.lua
2
init.lua
@ -4,7 +4,7 @@ local wifiConfig = {}
|
||||
|
||||
-- Possible modes: wifi.STATION : station: join a WiFi network
|
||||
-- wifi.SOFTAP : access point: create a WiFi network
|
||||
-- wifi.wifi.STATIONAP: both station and access point
|
||||
-- wifi.STATIONAP : both station and access point
|
||||
wifiConfig.mode = wifi.STATION
|
||||
|
||||
if (wifiConfig.mode == wifi.SOFTAP) or (wifiConfig.mode == wifi.STATIONAP) then
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user