#include "config.h" #include "wifi.h" #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[NUM_PINS] = {0}; // 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. // // returns the time spent delaying, if any. int handle_momentary() { bool need_delay = false; for (int i = 0; i < NUM_PINS; i++) { // if [the pin is momentary] and [it was set high this cycle] if (PIN_MAP[i][1] == 0 && pin_states[i] == HIGH) { need_delay = true; break; } } if (!need_delay) { return 0; } delay(MOMENTARY_PERIOD); for (int i = 0; i < NUM_PINS; i++) { // if [the pin is momentary] and [it was set high this cycle] if (PIN_MAP[i][1] == 0 && pin_states[i] == HIGH) { // set the pin back to low and make it 'sticky' until we read a low again. digitalWrite(PIN_MAP[i][0], LOW); pin_states[i] = OLD_HIGH; } } return MOMENTARY_PERIOD; } // poll_server makes the actual HTTP request and handles // the result. It returns false if an error occurred. bool poll_server() { String data = FetchURL(WEBHOOK_URL); if (data == "") return false; parse_webhook_response(data); return true; } void parse_webhook_response(String raw_data) { StaticJsonDocument<256> doc; DeserializationError err = deserializeJson(doc, raw_data); if (err) { Serial.print("Couldn't parse json data. Error code: "); Serial.println(err.c_str()); } JsonArray data = doc.as(); int i = 0; for (JsonVariant item : data) { if (tripped(i) && data[i] == HIGH) { continue; } pin_states[i] = item; i++; } if (data.size() < NUM_PINS) { Serial.println("Did not receive data for all pins."); } } // Set the pins to the right state, and set them all to high during // initialization. void initPins() { for (int i = 0; i < NUM_PINS; i++) { pinMode(PIN_MAP[i][0], OUTPUT); digitalWrite(PIN_MAP[i][0], HIGH); } } // Uses the current pin_states to actually write to the pins void writePins() { for (int i = 0; i < NUM_PINS; 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; } void setup() { Serial.begin(9600); initPins(); InitWifi(); } void loop() { poll_server(); writePins(); int elapsed = handle_momentary(); Serial.flush(); delay(REQUEST_RATE - elapsed); }