/* * 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 "certs.h" #include "config.h" #include "credentials.h" // cpp23 utility namespace cpp23 { template constexpr std::underlying_type_t to_underlying(Enum e) noexcept { return static_cast>(e);} } // defining some constants enum : uint8_t { LED_PIN = 16, // D0 - GPIO 16 REED_PIN = 2 // D4 - GPIO 2 }; enum class door_state { closed = 0, open = 1 }; // defining some globals static inline door_state current_door_state = door_state::closed; constexpr static inline std::array state_str {{"0", "1"}}; // initializing static inline BearSSL::X509List const ca_certs { CA_CERTS }; static inline BearSSL::X509List const client_cert { CLIENT_CERT }; static inline BearSSL::PrivateKey const client_key { CLIENT_KEY }; void blink_led(uint8_t blink_count, uint8_t delay_time) { /* * zur ausgabe von meldungen blinkt die interne led. * erfolgreichesmeldungen werden durch kurze blinkzeichen angezeigt, * fehlermeldungen sind durch eine lange sequenz gekennzeichnet. * Signale: * status der tür hat sich geändert: 2x kurz * änderung erfolgreich gesendet: 5x kurz * es konnte keine wifi aufgebaut werden: 3x lang * senden des status fehlgeschlagen: 5x lang * * param 1: integer * param 2: integer */ for (; blink_count; --blink_count) { digitalWrite(LED_PIN, LOW); delay(delay_time); digitalWrite(LED_PIN, HIGH); delay(delay_time); } } void init_serial() { /* * set baudrate and debug modus */ Serial.begin(BAUD_RATE); Serial.setDebugOutput(DEBUG); Serial.println("\n[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, HIGH); Serial.println("[Pin] LED and REED sensor initialized"); } void init_wifi() { WiFi.begin(SSID, PSK); Serial.println("[WiFi] Wifi initialized"); while (WiFi.status() != WL_CONNECTED) { Serial.println("[WiFi] Error: Failed to connect"); blink_led(3, 500); } Serial.printf("[WiFi] Connected to %s\n", WiFi.SSID()); Serial.print("[WiFi] IP: "); Serial.println(WiFi.localIP()); set_clock(); } door_state read_door_state() { /* * die initialisierung des reed-switch-pins mit pullup bewirkt, dass am pin * 3,3 volt anliegen. die verbindung des pins mit GND sorgt dafür, * dass 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 */ return (digitalRead(REED_PIN) == HIGH) ? door_state::open : door_state::closed; } void set_clock() { /* * We need time for certificate authorization */ configTime(TZ_STRING, NTP_URL); Serial.print("[Clock] Waiting for NTP time sync"); time_t now = time(nullptr); for (; now < 16 * 3600; now = time(nullptr)) { // 16 hours delay(500); Serial.print("."); } Serial.println(""); struct tm timeinfo; gmtime_r(&now, &timeinfo); Serial.printf("[Clock] Current time: %s\n", asctime(&timeinfo)); } bool send_status(door_state state) { /* * Inits wifi (if needed) and send the status */ char const* const status = state_str[cpp23::to_underlying(state)]; BearSSL::WiFiClientSecure client; client.setTrustAnchors(&ca_certs); client.setClientRSACert(&client_cert, &client_key); Serial.println("[Ctx] SSL Context initialized"); Serial.printf("[Send] Connect to %s:%i\n", SERVER_URL, SERVER_PORT); if (!client.connect(SERVER_URL, SERVER_PORT)) { Serial.println("[Send] Can't connect to server"); Serial.printf("[Send] SSL Error: %d\n", client.getLastSSLError()); client.stop(); return false; } Serial.println("[Send] Connection successful established"); Serial.printf("[Send] Send status: %s\n", status); client.write(status); client.stop(); return true; } void setup() { /* * things to do once at boot time */ init_serial(); init_pins(); init_wifi(); } void loop() { /* * things are running in a endless loop */ door_state 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); blink_led(2, 100); if (send_status(new_door_state)) { current_door_state = new_door_state; blink_led(5, 100); } else { blink_led(5, 500); } } delay(FREQUENCY); }