2018-02-02 06:46:44 +00:00
|
|
|
#include <Arduino.h>
|
|
|
|
#include <ArduinoJson.h>
|
|
|
|
#include <ESP8266WiFi.h>
|
|
|
|
#include <ESP8266HTTPClient.h>
|
|
|
|
|
2018-02-06 02:31:54 +00:00
|
|
|
const char* WIFI_SSID = "Protospace";
|
|
|
|
const char* WIFI_PASS = "yycmakers";
|
|
|
|
char wifiMACAddr[18];
|
2018-09-16 07:58:15 +00:00
|
|
|
const String API_ROUTE = String("http://tools-socket.protospace.ca/api/lockout/");
|
2018-02-02 06:46:44 +00:00
|
|
|
|
2018-05-17 03:03:44 +00:00
|
|
|
#define RELAY_PIN D1
|
2018-09-17 23:55:20 +00:00
|
|
|
#define GREEN_BUTTON_PIN D3
|
|
|
|
#define RED_BUTTON_PIN D4
|
|
|
|
#define GREEN_LED_PIN D6
|
|
|
|
#define RED_LED_PIN D7
|
2018-02-02 06:46:44 +00:00
|
|
|
|
2018-09-12 02:45:20 +00:00
|
|
|
#define RELAY_CLOSED HIGH
|
2018-05-17 03:03:44 +00:00
|
|
|
#define RELAY_OPEN !RELAY_CLOSED
|
|
|
|
#define BUTTON_CLOSED LOW
|
|
|
|
#define BUTTON_OPEN !BUTTON_CLOSED
|
|
|
|
#define LED_ON HIGH
|
|
|
|
#define LED_OFF !LED_ON
|
2018-02-02 06:46:44 +00:00
|
|
|
|
2018-02-06 02:31:54 +00:00
|
|
|
#define LOGGING true
|
2018-02-02 06:46:44 +00:00
|
|
|
|
2018-02-06 02:31:54 +00:00
|
|
|
#define DELAY_TIME 10
|
2018-05-17 03:03:44 +00:00
|
|
|
#define COMM_IDLE_TIME 500 / DELAY_TIME
|
2018-02-02 06:46:44 +00:00
|
|
|
|
2018-02-06 02:31:54 +00:00
|
|
|
enum wifiStates
|
|
|
|
{
|
|
|
|
WIFI_DISCONNECTED,
|
|
|
|
WIFI_CONNECTING,
|
|
|
|
WIFI_CONNECTED,
|
|
|
|
} wifiState = WIFI_DISCONNECTED;
|
|
|
|
|
|
|
|
enum lockStates
|
|
|
|
{
|
|
|
|
LOCK_OFF,
|
2018-11-08 02:09:34 +00:00
|
|
|
LOCK_PREARM,
|
2018-02-06 02:31:54 +00:00
|
|
|
LOCK_ARMED,
|
|
|
|
LOCK_ON_PRESSED,
|
|
|
|
LOCK_ON,
|
|
|
|
} lockState = LOCK_OFF;
|
|
|
|
|
|
|
|
enum commStates
|
|
|
|
{
|
|
|
|
COMM_INIT,
|
|
|
|
COMM_IDLE,
|
|
|
|
COMM_SEND,
|
|
|
|
} commState = COMM_INIT;
|
|
|
|
|
|
|
|
void setup()
|
|
|
|
{
|
|
|
|
if (LOGGING) Serial.begin(115200);
|
|
|
|
if (LOGGING) Serial.println("[INFO] Serial started.");
|
|
|
|
|
|
|
|
pinMode(RELAY_PIN, OUTPUT);
|
2018-09-17 23:55:20 +00:00
|
|
|
pinMode(GREEN_BUTTON_PIN, INPUT_PULLUP);
|
|
|
|
pinMode(RED_BUTTON_PIN, INPUT_PULLUP);
|
|
|
|
pinMode(GREEN_LED_PIN, OUTPUT);
|
|
|
|
pinMode(RED_LED_PIN, OUTPUT);
|
2018-02-02 06:46:44 +00:00
|
|
|
}
|
|
|
|
|
2018-02-06 02:31:54 +00:00
|
|
|
void loop()
|
|
|
|
{
|
|
|
|
processWifiState();
|
|
|
|
processLockState();
|
|
|
|
processCommState();
|
2018-02-02 06:46:44 +00:00
|
|
|
|
2018-02-06 02:31:54 +00:00
|
|
|
delay(DELAY_TIME);
|
|
|
|
}
|
2018-02-02 06:46:44 +00:00
|
|
|
|
2018-02-06 02:31:54 +00:00
|
|
|
void processWifiState()
|
|
|
|
{
|
|
|
|
switch(wifiState) {
|
|
|
|
case WIFI_DISCONNECTED:
|
|
|
|
lockState = LOCK_OFF;
|
|
|
|
commState = COMM_INIT;
|
|
|
|
|
|
|
|
if (LOGGING) Serial.println("[INFO] Wifi is disconnected. Attempting to connect...");
|
|
|
|
WiFi.begin(WIFI_SSID, WIFI_PASS);
|
|
|
|
|
|
|
|
wifiState = WIFI_CONNECTING;
|
|
|
|
break;
|
|
|
|
case WIFI_CONNECTING:
|
|
|
|
lockState = LOCK_OFF;
|
|
|
|
commState = COMM_INIT;
|
|
|
|
|
|
|
|
if (WiFi.status() == WL_CONNECTED) {
|
|
|
|
if (LOGGING) Serial.println("[INFO] Wifi is connected.");
|
|
|
|
|
2018-02-06 06:59:47 +00:00
|
|
|
if (LOGGING) Serial.print("[INFO] Wifi IP Address: ");
|
2018-02-06 02:31:54 +00:00
|
|
|
if (LOGGING) Serial.println(WiFi.localIP());
|
|
|
|
byte ar[6];
|
|
|
|
WiFi.macAddress(ar);
|
|
|
|
sprintf(wifiMACAddr, "%02X%02X%02X%02X%02X%02X", ar[0], ar[1], ar[2], ar[3], ar[4], ar[5]);
|
2018-02-06 06:59:47 +00:00
|
|
|
if (LOGGING) Serial.print("[INFO] Wifi MAC Address: ");
|
2018-02-06 02:31:54 +00:00
|
|
|
if (LOGGING) Serial.println(wifiMACAddr);
|
|
|
|
|
|
|
|
wifiState = WIFI_CONNECTED;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case WIFI_CONNECTED:
|
|
|
|
if (WiFi.status() != WL_CONNECTED) {
|
|
|
|
wifiState = WIFI_DISCONNECTED;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (LOGGING) Serial.println("[ERROR] Invalid wifi state.");
|
|
|
|
wifiState = WIFI_DISCONNECTED;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-02-02 06:46:44 +00:00
|
|
|
|
2018-11-08 02:09:34 +00:00
|
|
|
bool greenButton() { return digitalRead(GREEN_BUTTON_PIN) == BUTTON_CLOSED; }
|
|
|
|
bool redButton() { return digitalRead(RED_BUTTON_PIN) == BUTTON_CLOSED; }
|
|
|
|
|
|
|
|
void greenLEDOn() { digitalWrite(GREEN_LED_PIN, LED_ON); }
|
|
|
|
void greenLEDOff() { digitalWrite(GREEN_LED_PIN, LED_OFF); }
|
|
|
|
void redLEDOn() { digitalWrite(RED_LED_PIN, LED_ON); }
|
|
|
|
void redLEDOff() { digitalWrite(RED_LED_PIN, LED_OFF); }
|
|
|
|
|
2018-02-06 02:31:54 +00:00
|
|
|
void processLockState()
|
|
|
|
{
|
|
|
|
switch (lockState) {
|
|
|
|
case LOCK_OFF:
|
2018-09-17 23:55:20 +00:00
|
|
|
digitalWrite(GREEN_LED_PIN, LED_OFF);
|
|
|
|
digitalWrite(RED_LED_PIN, LED_ON);
|
2018-02-06 02:31:54 +00:00
|
|
|
|
|
|
|
digitalWrite(RELAY_PIN, RELAY_OPEN);
|
|
|
|
break;
|
2018-11-08 02:09:34 +00:00
|
|
|
case LOCK_PREARM:
|
|
|
|
if (!greenButton() && !redButton()) {
|
|
|
|
if (LOGGING) Serial.println("[INFO] Arming interlock.");
|
|
|
|
lockState = LOCK_ARMED;
|
|
|
|
} else {
|
|
|
|
lockState = LOCK_OFF;
|
|
|
|
}
|
|
|
|
break;
|
2018-02-06 02:31:54 +00:00
|
|
|
case LOCK_ARMED:
|
2018-09-17 23:55:20 +00:00
|
|
|
digitalWrite(GREEN_LED_PIN, LED_OFF);
|
|
|
|
digitalWrite(RED_LED_PIN, LED_ON);
|
2018-02-06 02:31:54 +00:00
|
|
|
|
|
|
|
digitalWrite(RELAY_PIN, RELAY_OPEN);
|
|
|
|
|
2018-11-08 02:09:34 +00:00
|
|
|
if (redButton()) {
|
2018-02-06 02:31:54 +00:00
|
|
|
if (LOGGING) Serial.println("[INFO] Unarming interlock.");
|
|
|
|
lockState = LOCK_OFF_PRESSED;
|
2018-11-08 02:09:34 +00:00
|
|
|
} else if (greenButton()) {
|
2018-02-06 02:31:54 +00:00
|
|
|
if (LOGGING) Serial.println("[INFO] On button pressed.");
|
|
|
|
lockState = LOCK_ON_PRESSED;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LOCK_ON_PRESSED:
|
2018-11-08 02:09:34 +00:00
|
|
|
if (redButton()) {
|
|
|
|
if (LOGGING) Serial.println("[ERROR] Off button pressed, aborting.");
|
2018-02-06 02:31:54 +00:00
|
|
|
lockState = LOCK_OFF_PRESSED;
|
2018-11-08 02:09:34 +00:00
|
|
|
} else if (!greenButton()) {
|
2018-02-06 02:31:54 +00:00
|
|
|
if (LOGGING) Serial.println("[INFO] Turning machine on.");
|
|
|
|
lockState = LOCK_ON;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LOCK_ON:
|
2018-09-17 23:55:20 +00:00
|
|
|
digitalWrite(GREEN_LED_PIN, LED_ON);
|
|
|
|
digitalWrite(RED_LED_PIN, LED_OFF);
|
2018-02-06 02:31:54 +00:00
|
|
|
|
|
|
|
digitalWrite(RELAY_PIN, RELAY_CLOSED);
|
|
|
|
|
2018-11-08 02:09:34 +00:00
|
|
|
if (redButton()) {
|
2018-02-06 02:31:54 +00:00
|
|
|
if (LOGGING) Serial.println("[INFO] Off button pressed.");
|
|
|
|
lockState = LOCK_OFF;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (LOGGING) Serial.println("[ERROR] Invalid lock state.");
|
|
|
|
lockState = LOCK_OFF;
|
|
|
|
break;
|
|
|
|
}
|
2018-02-02 06:46:44 +00:00
|
|
|
}
|
|
|
|
|
2018-05-17 03:03:44 +00:00
|
|
|
// JSON functions to prevent memory leaking
|
2018-02-06 06:59:47 +00:00
|
|
|
String serializeJson(int lockState) {
|
|
|
|
// Generated with: https://arduinojson.org/assistant/
|
|
|
|
const size_t bufferSize = JSON_OBJECT_SIZE(1) + 50;
|
|
|
|
DynamicJsonBuffer jsonBuffer(bufferSize);
|
|
|
|
|
2018-05-17 03:03:44 +00:00
|
|
|
JsonObject& root = jsonBuffer.createObject();
|
|
|
|
root["lockState"] = (int) lockState;
|
2018-02-06 06:59:47 +00:00
|
|
|
String postData = String();
|
2018-05-17 03:03:44 +00:00
|
|
|
root.printTo(postData);
|
2018-02-06 06:59:47 +00:00
|
|
|
|
|
|
|
return postData;
|
|
|
|
}
|
|
|
|
|
2018-05-17 03:03:44 +00:00
|
|
|
String deserializeJson(String input) {
|
|
|
|
// Generated with: https://arduinojson.org/assistant/
|
|
|
|
const size_t bufferSize = JSON_OBJECT_SIZE(1) + 50;
|
|
|
|
DynamicJsonBuffer jsonBuffer(bufferSize);
|
|
|
|
JsonObject& root = jsonBuffer.parseObject(input);
|
|
|
|
|
|
|
|
String action = root["action"];
|
|
|
|
|
|
|
|
return action;
|
|
|
|
}
|
2018-02-06 06:59:47 +00:00
|
|
|
|
2018-02-06 02:31:54 +00:00
|
|
|
void processCommState()
|
|
|
|
{
|
|
|
|
static int commIdleCount = 0;
|
|
|
|
|
|
|
|
switch (commState) {
|
|
|
|
case COMM_INIT:
|
|
|
|
commIdleCount = 0;
|
|
|
|
commState = COMM_IDLE;
|
|
|
|
break;
|
|
|
|
case COMM_IDLE:
|
|
|
|
commIdleCount++;
|
|
|
|
if (commIdleCount >= COMM_IDLE_TIME) {
|
|
|
|
commState = COMM_SEND;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case COMM_SEND:
|
|
|
|
if (LOGGING) Serial.println("[INFO] HTTP begin.");
|
|
|
|
HTTPClient http;
|
|
|
|
//http.begin("https://url", "7a 9c f4 db 40 d3 62 5a 6e 21 bc 5c cc 66 c8 3e a1 45 59 38"); //HTTPS
|
|
|
|
http.begin(API_ROUTE + wifiMACAddr);
|
|
|
|
http.addHeader("Content-Type", "application/json");
|
|
|
|
|
|
|
|
if (LOGGING) Serial.print("[INFO] HTTP POST: ");
|
2018-02-06 06:59:47 +00:00
|
|
|
String postData = serializeJson(lockState);
|
2018-02-06 02:31:54 +00:00
|
|
|
if (LOGGING) Serial.println(postData);
|
|
|
|
int httpCode = http.POST(postData);
|
|
|
|
|
|
|
|
if (httpCode > 0) {
|
|
|
|
if (LOGGING) Serial.printf("[INFO] POST success, code: %d\n", httpCode);
|
|
|
|
|
|
|
|
if (httpCode == HTTP_CODE_OK) {
|
|
|
|
if (LOGGING) Serial.print("[INFO] Resource found, parsing response: ");
|
|
|
|
String payload = http.getString();
|
|
|
|
if (LOGGING) Serial.println(payload);
|
2018-05-17 03:03:44 +00:00
|
|
|
String action = deserializeJson(payload);
|
2018-02-06 06:59:47 +00:00
|
|
|
|
2018-11-08 02:09:34 +00:00
|
|
|
if (action == "arm" && lockState == LOCK_OFF) {
|
|
|
|
lockState = LOCK_PREARMED;
|
|
|
|
} else if (action == "disarm") {
|
2018-02-06 06:59:47 +00:00
|
|
|
lockState = LOCK_OFF;
|
|
|
|
}
|
2018-02-06 02:31:54 +00:00
|
|
|
|
2018-02-06 06:59:47 +00:00
|
|
|
if (LOGGING) Serial.println("[INFO] action: " + action);
|
2018-02-06 02:31:54 +00:00
|
|
|
} else {
|
|
|
|
if (LOGGING) Serial.println("[ERROR] Resource not found.");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (LOGGING) Serial.printf("[ERROR] POST failed, error: %s\n", http.errorToString(httpCode).c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
commState = COMM_INIT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|