gpio-webhook-arduino/gpio-webhook-arduino.ino

132 lines
3.1 KiB
Arduino
Raw Normal View History

2020-05-06 21:05:51 +00:00
#include "config.h"
#include "wifi.h"
#include <ArduinoJson.h>
2020-05-06 21:05:51 +00:00
// 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};
2020-05-06 21:05:51 +00:00
// 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.
2020-05-06 21:05:51 +00:00
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++) {
2020-05-06 21:05:51 +00:00
// 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.
2020-05-06 21:05:51 +00:00
digitalWrite(PIN_MAP[i][0], LOW);
pin_states[i] = OLD_HIGH;
}
}
return MOMENTARY_PERIOD;
2020-05-06 21:05:51 +00:00
}
// poll_server makes the actual HTTP request and handles
// the result. It returns false if an error occurred.
bool poll_server() {
2020-05-14 18:26:02 +00:00
String data = FetchURL(WEBHOOK_URL);
if (data == "") return false;
parse_webhook_response(data);
return true;
2020-05-06 21:05:51 +00:00
}
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());
2020-05-06 21:05:51 +00:00
}
JsonArray data = doc.as<JsonArray>();
int i = 0;
for (JsonVariant item : data) {
2020-05-06 21:05:51 +00:00
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.");
2020-05-06 21:05:51 +00:00
}
}
2020-05-14 18:26:02 +00:00
// 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);
}
}
2020-05-06 21:05:51 +00:00
// Uses the current pin_states to actually write to the pins
2020-05-14 18:26:02 +00:00
void writePins() {
for (int i = 0; i < NUM_PINS; i++) {
2020-05-06 21:05:51 +00:00
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;
}
2020-05-14 18:26:02 +00:00
void setup() {
Serial.begin(9600);
initPins();
InitWifi();
}
void loop() {
poll_server();
writePins();
int elapsed = handle_momentary();
Serial.flush();
delay(REQUEST_RATE - elapsed);
}