123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- -- 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
|