diff --git a/source/nodemcu/statusclient/certs.template b/source/nodemcu/statusclient/certs.template new file mode 100644 index 0000000..07679bb --- /dev/null +++ b/source/nodemcu/statusclient/certs.template @@ -0,0 +1,36 @@ +/* + * file: certs.template + * desc: This file is part of the Krautspace Doorstatus project. It contains + * certificates for the statusclient.ino programm, that runs on a NodeMCU + * with a ESP8266 chip. + * + * Replace the comments in certificate sections with our own certificates. + */ + + +const char SERVER_CERT[] PROGMEM = R"EOF( +-----BEGIN CERTIFICATE----- +/* + * lace for the public server certificate to authenticate the doorstatus + * server. + */ +-----END CERTIFICATE----- +)EOF"; + +const char CLIENT_CERT[] PROGMEM = R"EOF( +-----BEGIN CERTIFICATE----- +/* + * Place for the clients (this program) public certificate to authenticate + * client against the server. + */ +-----END CERTIFICATE----- +)EOF"; + +const char CLIENT_KEY[] PROGMEM = R"EOF( +-----BEGIN CERTIFICATE----- +/* + * Place for the clients private key file. + */ +-----END CERTIFICATE----- +)EOF"; + diff --git a/source/nodemcu/statusclient/config.h b/source/nodemcu/statusclient/config.h new file mode 100644 index 0000000..a9bbde5 --- /dev/null +++ b/source/nodemcu/statusclient/config.h @@ -0,0 +1,18 @@ +/* + * file: config.h + */ + +/* endpoint */ +#define SERVER_URL "status.kraut.space" +#define SERVER_PORT 10001 + +/* serial interface settings */ +#define BAUD_RATE 115200 +#define DEBUG true + +/* frequence to read the pin */ +#define FREQUENCY 10000 + +/* time server settings */ +#define NTP_URL "pool.ntp.org" +#define TZ_STRING "CET-1CDT,M3.5.0,M10.5.0/3" diff --git a/source/nodemcu/statusclient/credentials.template b/source/nodemcu/statusclient/credentials.template new file mode 100644 index 0000000..2ba711d --- /dev/null +++ b/source/nodemcu/statusclient/credentials.template @@ -0,0 +1,17 @@ +/* + * file: credentials.template + * desc: This file is part of the Krautspace Doorstatus project. It contains + * wifi ssid and passwords for the statusclient.ino programm, that runs on a + * NodeMCU with a ESP8266 chip. + * + * Rename this file into 'credentials.h' and adapt the values to your + * wifi conditions. + */ + +/* wifi credentials */ +#define SSID_1 "your_first__wlan_ssid" +#define PSK_1 "your_first_wlan_passwort" +#define SSID_2 "your_second_wlan_ssid" +#define PSK_2 "your_seconde_wlan_password" +#define SSID_3 "your_third_wlan_ssid" +#define PSK_3 "your_third_wlan_password" diff --git a/source/nodemcu/statusclient/statusclient.ino b/source/nodemcu/statusclient/statusclient.ino new file mode 100644 index 0000000..6ef9ded --- /dev/null +++ b/source/nodemcu/statusclient/statusclient.ino @@ -0,0 +1,202 @@ +/* + * file: statusclient.ino + * desc: This file is part of the Krautspace Doorstatus project. It's the + * main file for a client, who deals with the input from a reed sensor and + * push these values to a server. The code is make to run on a NodeMCU with + * ESP8266 chip. + */ + +#include +#include +#include + +#include "config.h" +#include "certs.h" +#include "credentials.h" + +const int LED_PIN = 16; // D0 +const int REED_PIN = 5; // D1 + +typedef enum { + DOOR_CLOSED = 0, + DOOR_OPEN = 1 +} door_state; +door_state current_door_state = DOOR_CLOSED; +door_state new_door_state = DOOR_CLOSED; + + +void init_serial() { + /* + * set baudrate and debug modus + */ + Serial.begin(BAUD_RATE); + Serial.setDebugOutput(DEBUG); + Serial.println(); + Serial.println("[Srl] Serial interface initialized"); +} + +void init_pins() { + /* + * set gpio for reed sensor and led + */ + pinMode(REED_PIN, INPUT_PULLUP); + pinMode(LED_PIN, OUTPUT); + digitalWrite(LED_PIN, LOW); + Serial.println("[Pin] LED and REED initialized"); +} + + +void init_wifi() { + /* + * first turn wifi off and than in access point mode + * maybe turn of is not needed! + */ + ESP8266WiFiMulti wifi; + WiFi.mode(WIFI_OFF); + WiFi.mode(WIFI_STA); + wifi.addAP(SSID_1, PSK_1); + wifi.addAP(SSID_2, PSK_2); + Serial.println("[Wifi] Wifi initialized"); + wifi.run(); + if (WiFi.status() == WL_CONNECTED) { + Serial.print("[Wif] Connected to "); + Serial.println(WiFi.SSID()); + Serial.print("[Wifi] IP: "); + Serial.println(WiFi.localIP()); + } else { + Serial.println("[Wifi] Error: Failed to connect"); + } +} + +door_state read_door_state() { + /* + * die initialisierung des reed-pin mit pullup bewirkt, daß am pin + * 3,3 volt anliegen. die verbindung des pins mit GND sorgt dafür, + * daß die spannung "abfließen" kann. dadurch hat der pin dann den + * status 'low'. + * geschlossene tür -> reed geschlossen -> low + * geöffnete tür -> reed offen -> high + */ + if (digitalRead(REED_PIN) == HIGH) { + return DOOR_OPEN; + } + return DOOR_CLOSED; +} + +void toggle_led(door_state state) { + /* + * turns onboard led on or depends on the door state + */ + if (state == DOOR_OPEN) { + digitalWrite(LED_PIN, LOW); + } else { + digitalWrite(LED_PIN, HIGH); + } + delay(500); +} + +void set_clock() { + + configTime(TZ_STRING, NTP_URL); + + Serial.print("Waiting for NTP time sync: "); + time_t now = time(nullptr); + while (now < 8 * 3600 * 2) { + delay(500); + Serial.print("."); + now = time(nullptr); + } + Serial.println(""); + struct tm timeinfo; + gmtime_r(&now, &timeinfo); + Serial.print("Current time: "); + Serial.print(asctime(&timeinfo)); +} + +int send_status(door_state state) { + + /* + * geht die initialisierung mit einem byte länge? + * terminiert strcpy den status mit \0? + */ + char status[2] = ""; + + if (state == DOOR_CLOSED) { + strncpy(status, "0", 1); + } else if (state == DOOR_OPEN) { + strncpy(status, "1", 1); + } else { + return 1; + } + + BearSSL::WiFiClientSecure client; + BearSSL::X509List server_cert(SERVER_CERT); + BearSSL::X509List client_cert(CLIENT_CERT); + BearSSL::PrivateKey client_key(CLIENT_KEY); + client.setTrustAnchors(&server_cert); + client.setClientRSACert(&client_cert, &client_key); + delay(500); + Serial.println("[Ctx] SSL Context initialized"); + Serial.print("[Ctx] Free Heap: "); + Serial.println(ESP.getFreeHeap()); + delay(500); + Serial.printf("[Send] Connect to %s:%i\n", SERVER_URL, SERVER_PORT); + client.connect(SERVER_URL, SERVER_PORT); + if (!client.connected()) { + Serial.println("[Send] Can't connect to server"); + Serial.print("[Send] SSL Error: "); + Serial.println(client.getLastSSLError()); + client.stop(); + return 1; + } else { + ESP.resetFreeContStack(); + uint32_t freeStackStart = ESP.getFreeContStack(); + Serial.println("[Send] Connection successful established"); + Serial.printf("[Send] Send status: %s\n", status); + client.write(status); + + } + return 0; +} + + + + + +void setup() { + + /* + * things to do once at boot time + */ + init_serial(); + Serial.print("[Init] Free Heap ( after serial init): "); + Serial.println(ESP.getFreeHeap()); + init_pins(); + Serial.print("[Init] Free Heap (after pins init): "); + Serial.println(ESP.getFreeHeap()); + init_wifi(); + Serial.print("[Init] Free Heap (after wifi init): "); + Serial.println(ESP.getFreeHeap()); + delay(500); + set_clock(); + Serial.print("[Init] Free Heap (after setting clock): "); + Serial.println(ESP.getFreeHeap()); + delay(500); +} + +void loop() { + + /* + * things are running in a endless loop + */ + new_door_state = read_door_state(); + if (new_door_state != current_door_state) { + Serial.printf("[Loop] Status has changed to %i\n", new_door_state); + toggle_led(new_door_state); + send_status(new_door_state); + current_door_state = new_door_state; + } + Serial.print("[Loop] Free Heap: "); + Serial.println(ESP.getFreeHeap()); + delay(FREQUENCY); +}