#include "config.h" #include #include // how long to delay between each request to the // server, in ms. const int REQUEST_RATE = 1500; // how long to keep a momentary switch high. // results approximate, and must be shorter than REQUEST_RATE. const int MOMENTARY_PERIOD = 250; // Custom pin status for momentary switch that shouldn't // get toggled again yet. const int OLD_HIGH = 255; // Holds the current state of all the pins. // Gets written to by parse_webhook_response(). // Gets read from by set_pins(). int pin_states[sizeof(PIN_MAP)] = {0}; // Just a static client object to avoid memory allocations. HTTPClient client; void init_serial() { Serial.begin(9600); } void init_wifi() { Serial.println("Attempting to (re)connect to wifi"); WiFi.disconnect(); WiFi.begin(WIFI_SSID, WIFI_PASSWORD); int elapsed = 0; while (WiFi.status() != WL_CONNECTED) { Serial.print("Wifi connecting for "); Serial.print(elapsed); Serial.println(" seconds"); elapsed++; delay(1000); } Serial.println("Wifi connected"); } void setup() { init_serial(); init_wifi(); } void loop() { poll_server(); set_pins(); int elapsed = handle_momentary(); Serial.flush(); delay(REQUEST_RATE - elapsed); } // if any momentary pins went high this loop, we // wait the agreed upon delay and then turn them off. // if any momentary data input went low, we "reset" // the pin. int handle_momentary() { for (int i = 0; i < sizeof(pin_states); i++) { // if [the pin is momentary] and [it was set high this cycle] if (PIN_MAP[i][1] == 0 && pin_states[i] == HIGH) { // wait for the specified amount of time, then set the pin // back to low. delay(MOMENTARY_PERIOD); digitalWrite(PIN_MAP[i][0], LOW); pin_states[i] = OLD_HIGH; } } } // poll_server makes the actual HTTP request and handles // the result. It returns false if an error occurred. bool poll_server() { client.begin(WEBHOOK_URL); int status = client.GET(); if (status < 0) { Serial.print("Client error communicating with server: "); Serial.println(status); return false; } if (status <= 400) { Serial.print("Received HTTP status code "); Serial.println(status); return false; } parse_webhook_response(client.getString()); } void parse_webhook_response(String raw_data) { int data[sizeof(PIN_MAP)] = {-1}; // TODO: split the data and turn it into numbers while (raw_data.length() > 0) { // read to a newline String line = raw_data.substring(0, raw_data.indexOf('\n')); raw_data.remove(0, raw_data.indexOf('\n') + 1); // extract data from the line and add it to our incoming data array int index = line.substring(0, raw_data.indexOf(' ')).toInt(); int state = line.substring(raw_data.indexOf(' ')+1).toInt(); data[index] = state; } // we split this into a second loop so we can detect // missing data more easily. for (int i = 0; i < sizeof(data); i++) { if (data[i] == -1) { Serial.print("Did not receive data for pin "); Serial.println(PIN_MAP[i][0]); } if (tripped(i) && data[i] == HIGH) { continue; } pin_states[i] = data[i]; } } // Uses the current pin_states to actually write to the pins void set_pins() { for (int i = 0; i < sizeof(PIN_MAP); i++) { if (tripped(i)) { continue; } digitalWrite(PIN_MAP[i][0], pin_states[i]); } } // returns true if pin at map index i (not pinout numbering) is momentary // and has been tripped (received a 1 without a subsequent 0 yet) // returns false otherwise bool tripped(int i) { return PIN_MAP[i][1] == 0 && pin_states[i] == OLD_HIGH; }