Compare commits

...

2 Commits

Author SHA1 Message Date
42a3835b43 Rename project. 2020-05-20 18:09:32 +00:00
e74fe369e5 Numerous fixes, first working commit. 2020-05-14 18:26:02 +00:00
5 changed files with 134 additions and 83 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
config.h config.h
*.bin *.bin
*.elf *.elf
configs/

View File

@ -1,3 +1,7 @@
// Do not edit these two lines
#ifndef __CONFIG_H__
#define __CONFIG_H__
#define WIFI_SSID "myNetwork" #define WIFI_SSID "myNetwork"
#define WIFI_PASSWORD "myPassword" #define WIFI_PASSWORD "myPassword"
#define WEBHOOK_URL "example.com/aoeuhtns" #define WEBHOOK_URL "example.com/aoeuhtns"
@ -8,12 +12,58 @@
// //
// We would expect the webhook to return something like: // We would expect the webhook to return something like:
// //
// [1 0 1] // [1, 0, 1]
// //
// to activate the momentary switch, (pin 5) deactivate the first // to activate the momentary switch, (pin 5) deactivate the first
// latched switch, (pin 8) and activate the second latched switch. (pin 10) // latched switch, (pin 8) and activate the second latched switch. (pin 10)
const int PIN_MAP[][2] = { const int NUM_PINS = 3;
const int PIN_MAP[NUM_PINS][2] = {
{5, 1}, {5, 1},
{8, 1}, {8, 1},
{10, 1} {10, 1}
}; };
// The signing/root certificate for your webhook site.
// For internal installations this might be a self-signing cert.
// For public installations, acquire the root cert for the CA and
// place it here. You can get this for your target domain with:
//
// sudo openssl s_client -connect sss.annabunch.es:443 -showcerts
//
// Be sure that you copy the cert that is described as a "Root CA" or
// "Root Trust" certificate.
//
// The provided example is for letsencrypt.org
static const char ca_cert[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
-----END CERTIFICATE-----
)EOF";
// Do not edit this line
#endif

View File

@ -19,31 +19,6 @@ const int OLD_HIGH = 255;
// Gets read from by set_pins(). // Gets read from by set_pins().
int pin_states[NUM_PINS] = {0}; int pin_states[NUM_PINS] = {0};
void init_serial() {
Serial.begin(9600);
}
void init_pins() {
for (int i = 0; i < NUM_PINS; i++) {
digitalWrite(PIN_MAP[i][0], LOW);
}
}
void setup() {
init_pins();
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 // if any momentary pins went high this loop, we
// wait the agreed upon delay and then turn them off. // wait the agreed upon delay and then turn them off.
// if any momentary data input went low, we "reset" // if any momentary data input went low, we "reset"
@ -81,20 +56,10 @@ int handle_momentary() {
// poll_server makes the actual HTTP request and handles // poll_server makes the actual HTTP request and handles
// the result. It returns false if an error occurred. // the result. It returns false if an error occurred.
bool poll_server() { bool poll_server() {
client.begin(transport, WEBHOOK_URL); String data = FetchURL(WEBHOOK_URL);
int status = client.GET(); if (data == "") return false;
if (status < 0) { parse_webhook_response(data);
Serial.print("Client error communicating with server: "); return true;
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) { void parse_webhook_response(String raw_data) {
@ -122,8 +87,18 @@ void parse_webhook_response(String raw_data) {
} }
} }
// 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 // Uses the current pin_states to actually write to the pins
void set_pins() { void writePins() {
for (int i = 0; i < NUM_PINS; i++) { for (int i = 0; i < NUM_PINS; i++) {
if (tripped(i)) { if (tripped(i)) {
continue; continue;
@ -139,3 +114,18 @@ void set_pins() {
bool tripped(int i) { bool tripped(int i) {
return PIN_MAP[i][1] == 0 && pin_states[i] == OLD_HIGH; 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);
}

View File

@ -1,13 +1,14 @@
# Control I/O pins with a webhook # Control I/O pins with a webhook
This is an Arduino IDE sketch for a "smart" controller that can activate pins This is an Arduino IDE sketch for a "smart" controller that can activate pins
based on the state of some webpage. The motivating use cases are: based on the state of some webpage. (designed to be driven by [gpio webhook server](https://git.annabunch.es/annabunches/gpio-webhook-server))
The motivating use cases are:
* Controlling a PC power switch remotely, using a transistor wired to the power switch pins * Controlling a PC power switch remotely, using a transistor wired to the power switch pins
* Lighting specific LEDs to create a remotely controlled 'traffic light'. * Lighting specific LEDs to create a remotely controlled 'traffic light'.
This sketch currently targets only the ESP8266, and will probably not work with other This sketch currently targets only the ESP8266, and will probably not work with other
microcontrollers. Support for other boards may come if I run out of ESP8266's. microcontrollers. Support for other boards may come if I run out of ESP8266s.
## Configuration ## Configuration

79
wifi.h
View File

@ -1,17 +1,39 @@
#include "config.h"
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h> #include <ESP8266HTTPClient.h>
//#include <WifiClientSecureBearSSL.h> #include <WiFiClientSecureBearSSL.h>
#include <bearssl.h>
#include <FS.h>
HTTPClient client; HTTPClient client;
BearSSL::WifiClientSecure *transport; BearSSL::WiFiClientSecure *secure_transport;
BearSSL::Session *tls_session;
BearSSL::X509List cert_list; BearSSL::X509List cert_list;
void init_wifi() { void syncTime() {
transport = new WifiClientSecure(); // 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("");
}
Serial.println("Attempting to (re)connect to wifi"); void initTLS() {
secure_transport = new BearSSL::WiFiClientSecure();
syncTime();
cert_list.append(ca_cert);
secure_transport->setTrustAnchors(&cert_list);
tls_session = new BearSSL::Session();
secure_transport->setSession(tls_session);
}
void InitWifi() {
Serial.println("Attempting to connect to wifi");
WiFi.disconnect(); WiFi.disconnect();
WiFi.begin(WIFI_SSID, WIFI_PASSWORD); WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
int elapsed = 0; int elapsed = 0;
@ -25,36 +47,23 @@ void init_wifi() {
Serial.println("Wifi connected"); Serial.println("Wifi connected");
sync_time(); initTLS();
load_ca_cert();
} }
void load_ca_cert() { String FetchURL(const char *path) {
// read cert from file client.begin(*secure_transport, WEBHOOK_URL);
if (!SPIFFS.begin()) {
Serial.println("Failed to mount file system."); int status = client.GET();
return if (status < 0) {
Serial.print("Client error communicating with server: ");
Serial.println(status);
return "";
}
if (status >= 400) {
Serial.print("Received HTTP status code ");
Serial.println(status);
return "";
} }
File cert = SPIFFS.open("/ca_cert.pem", "r"); return client.getString();
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("");
} }