/* * 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; BearSSL::WiFiClientSecure client; 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, HIGH); Serial.println("[Pin] LED and REED initialized"); } void init_wifi() { /* * Creates the ssl context. Turns wifi off and than into * access point mode. * TODO: is 'turn of' needed! */ ESP8266WiFiMulti wifi; WiFi.mode(WIFI_OFF); WiFi.mode(WIFI_STA); wifi.addAP(SSID_1, PSK_1); wifi.addAP(SSID_2, NULL); 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()); set_clock(); } else { Serial.println("[Wifi] Error: Failed to connect"); signal_wifi_failed(); } } 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 signal_door_changed() { /* * LED signal, if door is opened */ uint8_t count = 2; for(uint8_t i=0; i!= count; ++i) { digitalWrite(LED_PIN, LOW); delay(100); digitalWrite(LED_PIN, HIGH); delay(100); } } void signal_send_successful() { /* * LED signal, if new status was send successful */ uint8_t count = 5; for(uint8_t i=0; i!= count; ++i) { digitalWrite(LED_PIN, LOW); delay(100); digitalWrite(LED_PIN, HIGH); delay(100); } } void signal_clock_failed() { /* * LED signal, if time setting failed */ uint8_t count = 2; for(uint8_t i=0; i!= count; ++i) { digitalWrite(LED_PIN, LOW); delay(500); digitalWrite(LED_PIN, HIGH); delay(500); } delay(2000); } void signal_wifi_failed() { /* * LED signal, if wifi initialication was failed */ uint8_t count = 3; for(uint8_t i=0; i!= count; ++i) { digitalWrite(LED_PIN, LOW); delay(500); digitalWrite(LED_PIN, HIGH); delay(500); } delay(2000); } void signal_connect_failed() { /* * LED signal, if door is opened */ uint8_t count = 4; for(uint8_t i=0; i!= count; ++i) { digitalWrite(LED_PIN, LOW); delay(500); digitalWrite(LED_PIN, HIGH); delay(500); } delay(2000); } void signal_send_failed() { /* * LED signal, if door is opened */ uint8_t count = 5; for(uint8_t i=0; i!= count; ++i) { digitalWrite(LED_PIN, LOW); delay(500); digitalWrite(LED_PIN, HIGH); delay(500); } delay(2000); } 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); while (now < 8 * 3600 * 2) { delay(500); Serial.print("."); now = time(nullptr); } Serial.println(""); struct tm timeinfo; gmtime_r(&now, &timeinfo); Serial.print("[Clock] Current time: "); Serial.println(asctime(&timeinfo)); } int send_status(door_state state) { /* * Inits wifi (if needed) and send the status */ char status[2] = ""; if (state == DOOR_CLOSED) { strncpy(status, "0", 1); } else if (state == DOOR_OPEN) { strncpy(status, "1", 1); } else { return 1; } 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); Serial.println("[Ctx] SSL Context initialized"); 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()); signal_send_failed(); 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); signal_send_successful(); client.stop(); } return 0; } void setup() { /* * things to do once at boot time */ init_serial(); init_pins(); init_wifi(); } void loop() { /* * things are running in a endless loop */ if (WiFi.status() != WL_CONNECTED) { init_wifi(); } 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); signal_door_changed(); if (send_status(new_door_state) == 0) { current_door_state = new_door_state; } } delay(FREQUENCY); }