diff --git a/readme.md b/readme.md index 688a65c..b043293 100644 --- a/readme.md +++ b/readme.md @@ -37,7 +37,7 @@ only be high for a short time. 1 is for latched mode; the pin will stay high unt ## Building -**TODO** +Just run `make` to build the code. You need to have `config.h` and `data/ca_cert.pem` defined. ## Webhook data @@ -49,3 +49,9 @@ The webhook should always return a page in the following (JSON-compatible) forma Where index and state are both integers. If you are expecting momentary input, you should return the state to '0' after the page is served / the webhook is consumed. + + +## Future Improvements + +* make it actually work... +* use WifiManager? \ No newline at end of file diff --git a/smartswitch.ino b/smartswitch.ino index e17d02d..ad11834 100644 --- a/smartswitch.ino +++ b/smartswitch.ino @@ -1,6 +1,5 @@ #include "config.h" -#include -#include +#include "wifi.h" #include // how long to delay between each request to the @@ -18,32 +17,20 @@ 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; +int pin_states[NUM_PINS] = {0}; 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); +void init_pins() { + for (int i = 0; i < NUM_PINS; i++) { + digitalWrite(PIN_MAP[i][0], LOW); } - - Serial.println("Wifi connected"); } void setup() { + init_pins(); init_serial(); init_wifi(); } @@ -61,23 +48,40 @@ void loop() { // 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() { - for (int i = 0; i < sizeof(pin_states); i++) { + 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) { - // wait for the specified amount of time, then set the pin - // back to low. - delay(MOMENTARY_PERIOD); + 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() { - client.begin(WEBHOOK_URL); + client.begin(transport, WEBHOOK_URL); int status = client.GET(); if (status < 0) { Serial.print("Client error communicating with server: "); @@ -94,20 +98,6 @@ bool poll_server() { } 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; - // } - StaticJsonDocument<256> doc; DeserializationError err = deserializeJson(doc, raw_data); @@ -127,14 +117,14 @@ void parse_webhook_response(String raw_data) { i++; } - if (data.size() < sizeof(pin_states) / sizeof(*pin_states)) { + if (data.size() < NUM_PINS) { Serial.println("Did not receive data for all pins."); } } // Uses the current pin_states to actually write to the pins void set_pins() { - for (int i = 0; i < sizeof(PIN_MAP); i++) { + for (int i = 0; i < NUM_PINS; i++) { if (tripped(i)) { continue; } diff --git a/wifi.h b/wifi.h new file mode 100644 index 0000000..f59af8b --- /dev/null +++ b/wifi.h @@ -0,0 +1,60 @@ +#include +#include +//#include +#include +#include + +HTTPClient client; +BearSSL::WifiClientSecure *transport; +BearSSL::X509List cert_list; + +void init_wifi() { + transport = new WifiClientSecure(); + + 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"); + + sync_time(); + load_ca_cert(); +} + +void load_ca_cert() { + // read cert from file + if (!SPIFFS.begin()) { + Serial.println("Failed to mount file system."); + return + } + + File cert = SPIFFS.open("/ca_cert.pem", "r"); + if (!cert) { + Serial.println("Couldn't open cert file."); + return; + } + + cert_list.append(strdup(cert.readString().c_str())); + netClient->setTrustAnchors(&certList); +} + +void sync_time() { + // sync time + Serial.print("Syncing time"); + configTime(8 * 3600, 0, "pool.ntp.org", "time.nist.gov"); + time_t now = time(nullptr); + while (now < 8 * 3600 * 2) { + delay(500); + Serial.print("."); + now = time(nullptr); + } + Serial.println(""); +}