Created
July 17, 2019 08:21
-
-
Save williamdenton/51ef18c01b6f96a6f31f77a93eb371f0 to your computer and use it in GitHub Desktop.
HomebridgeSetup for Garage Door using https://github.com/washcroft/homebridge-http-garagedoorcontroller
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <ESP8266WiFi.h> | |
#include <WiFiClient.h> | |
#include <ESP8266WebServer.h> | |
#define STASSID "" | |
#define STAPSK "" | |
#define APIKEY "" | |
#define LED_ON LOW | |
#define LED_OFF HIGH | |
#define LIMIT_SWITCH_UP_POSITION D3 | |
#define LIMIT_SWITCH_DOWN_POSITION D8 | |
#define LIMIT_SWITCH_UP_ACTIVATED HIGH | |
#define LIMIT_SWITCH_DOWN_ACTIVATED HIGH | |
#define DOOR_RELAY D5 | |
#define DOOR_TRAVEL_TIME_MILLIS 15 * 1000 //15 sec | |
const char* ssid = STASSID; | |
const char* password = STAPSK; | |
const char* apiKey = APIKEY; | |
enum doorState { | |
isOpen, | |
isOpening, | |
isClosing, | |
isClosed, | |
isStopped, | |
isInvalid | |
}; | |
IPAddress ip (192, 168, 1 , 199); | |
IPAddress gateway(192, 168, 1 , 1 ); | |
IPAddress ipmask (255, 255, 255, 0 ); | |
IPAddress dns (192, 168, 1 , 2 ); | |
ESP8266WebServer server(80); | |
unsigned long lastKnownStateTime = 0; | |
doorState lastKnownState; | |
doorState getDoorState() { | |
//the polling/looping nature of the system means we can capture the last known state | |
//then can infer if opening or closing if door starts moving | |
bool isAtUpLimit = digitalRead(LIMIT_SWITCH_UP_POSITION) == LIMIT_SWITCH_UP_ACTIVATED; | |
bool isAtDownLimit = digitalRead(LIMIT_SWITCH_DOWN_POSITION) == LIMIT_SWITCH_DOWN_ACTIVATED; | |
if (isAtUpLimit && isAtDownLimit) { | |
return isInvalid; | |
} | |
if (isAtUpLimit) { | |
lastKnownState = isOpen; | |
lastKnownStateTime = millis(); | |
return isOpen; | |
} | |
if (isAtDownLimit) { | |
lastKnownState = isClosed; | |
lastKnownStateTime = millis(); | |
return isClosed; | |
} | |
if (isLastKnownStateRecent()) { | |
switch(lastKnownState){ | |
case isClosed: | |
return isOpening; | |
case isOpen: | |
return isClosing; | |
} | |
} | |
return isStopped; | |
} | |
bool isLastKnownStateRecent() { | |
return lastKnownStateTime > 0 && (millis() - lastKnownStateTime) < DOOR_TRAVEL_TIME_MILLIS; | |
} | |
void pushDoorTrigger() { | |
digitalWrite(DOOR_RELAY, HIGH); | |
delay(500); //hold button down | |
digitalWrite(DOOR_RELAY, LOW); | |
delay(500); // wait for door action to start and limit switches to disengage so status reports correctly | |
} | |
void handleStatus() { | |
digitalWrite(LED_BUILTIN, LED_ON); | |
if (!isAuthenticated()) { | |
rejectRequest(); | |
digitalWrite(LED_BUILTIN, LED_OFF); | |
return; | |
} | |
sendGarageDoorStatus(); | |
digitalWrite(LED_BUILTIN, LED_OFF); | |
} | |
void handleOpenDoor() { | |
digitalWrite(LED_BUILTIN, LED_ON); | |
if (!isAuthenticated()) { | |
rejectRequest(); | |
digitalWrite(LED_BUILTIN, LED_OFF); | |
return; | |
} | |
switch (getDoorState()) { | |
case isClosed: | |
case isClosing: | |
case isStopped: | |
case isInvalid: | |
pushDoorTrigger(); | |
break; | |
} | |
sendGarageDoorStatus(); | |
digitalWrite(LED_BUILTIN, LED_OFF); | |
} | |
void handleCloseDoor() { | |
digitalWrite(LED_BUILTIN, LED_ON); | |
if (!isAuthenticated()) { | |
rejectRequest(); | |
digitalWrite(LED_BUILTIN, LED_OFF); | |
return; | |
} | |
switch (getDoorState()) { | |
case isOpen: | |
case isOpening: | |
case isStopped: | |
case isInvalid: | |
pushDoorTrigger(); | |
break; | |
} | |
sendGarageDoorStatus(); | |
digitalWrite(LED_BUILTIN, LED_OFF); | |
} | |
String getStateForResponse() { | |
//https://github.com/KhaosT/HAP-NodeJS/blob/81319b35d1588453cfcb1a823805643de7df74dc/lib/gen/HomeKitTypes.js#L476-L481 | |
//https://github.com/washcroft/homebridge-http-garagedoorcontroller/blob/95924d796c0dae2110853d0f762791b8f24df9aa/index.js#L671-L687 | |
switch (getDoorState()) { | |
case isOpen: | |
return "OPEN"; | |
case isOpening: | |
return "OPENING"; | |
case isClosed: | |
return "CLOSED"; | |
case isClosing: | |
return "CLOSING"; | |
case isStopped: | |
return "STOPPED"; | |
default: | |
return "UNKNOWN"; | |
} | |
} | |
void sendGarageDoorStatus() { | |
server.send(200, "text/plain", getStateForResponse()); | |
} | |
void handleNotFound() { | |
digitalWrite(LED_BUILTIN, LED_ON); | |
if (!isAuthenticated()) { | |
rejectRequest(); | |
digitalWrite(LED_BUILTIN, LED_OFF); | |
return; | |
} | |
server.send(404, "text/plain", "That's totally not a thing that I can do, I'm a Garage Door not a genie"); | |
digitalWrite(LED_BUILTIN, LED_OFF); | |
} | |
bool isAuthenticated() { | |
if (server.hasHeader("x-api-key")) { | |
String suppliedApikey = server.header("x-api-key"); | |
if (suppliedApikey == apiKey) { | |
return true; | |
} | |
Serial.print("Auth Failed with supplied key: "); | |
Serial.println(suppliedApikey); | |
return false; | |
} | |
//TODO: header is not being send/parsed correctly | |
Serial.println("Auth Failed - No Api Key"); | |
return true; | |
return false; | |
} | |
void rejectRequest() { | |
server.send(403, "text/plain", "Unauthorized"); | |
} | |
void setup(void) { | |
pinMode(LIMIT_SWITCH_UP_POSITION, INPUT_PULLUP); | |
pinMode(LIMIT_SWITCH_DOWN_POSITION, INPUT); | |
pinMode(LED_BUILTIN, OUTPUT); | |
pinMode(DOOR_RELAY, OUTPUT); | |
Serial.begin(115200); | |
WiFi.config(ip, gateway, ipmask, dns); | |
WiFi.mode(WIFI_STA); | |
WiFi.begin(ssid, password); | |
Serial.println(""); | |
// Wait for connection | |
while (WiFi.status() != WL_CONNECTED) { | |
delay(500); | |
Serial.print("."); | |
} | |
Serial.println(""); | |
Serial.print("Connected to "); | |
Serial.println(ssid); | |
Serial.print("IP address: "); | |
Serial.println(WiFi.localIP()); | |
server.on("/status", HTTP_GET, handleStatus); | |
server.on("/open", HTTP_PUT, handleOpenDoor); | |
server.on("/close", HTTP_PUT, handleCloseDoor); | |
server.onNotFound(handleNotFound); | |
server.begin(); | |
Serial.println("HTTP server started"); | |
} | |
void loop(void) { | |
getDoorState(); | |
server.handleClient(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"bridge": { | |
"name": "Homebridge", | |
"username": "CC:22:3D:E3:CE:30", | |
"port": 51826, | |
"pin": "" | |
}, | |
"accessories": [ | |
{ | |
"accessory": "HttpGarageDoorController", | |
"name": "Garage Door", | |
"httpHost": "192.168.1.199", | |
"httpPort": 80, | |
"httpSsl": false, | |
"httpStatusPollMilliseconds": 2000, | |
"httpRequestTimeoutMilliseconds": 5000, | |
"httpHeaderName": "x-api-key", | |
"httpHeaderValue": "", | |
"apiConfig": | |
{ | |
"apiType": "Generic", | |
"doorOpenMethod": "PUT", | |
"doorOpenUrl": "/open", | |
"doorOpenSuccessContent": "OPENING", | |
"doorCloseMethod": "PUT", | |
"doorCloseUrl": "/close", | |
"doorCloseSuccessContent": "CLOSING", | |
"doorStateMethod": "GET", | |
"doorStateUrl":"/status" | |
} | |
} | |
], | |
"platforms": [] | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
notifications while tinkering get a bit excessive
