diff --git a/.gitignore b/.gitignore index 5dac9f5..b4c4d22 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,10 @@ .piolibdeps .clang_complete .gcc-flags.json + +# virtualenv +bin/ +include/ +lib/ +local/ +share/ diff --git a/platformio.ini b/platformio.ini index 777d273..7f78e32 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,6 +9,16 @@ ; http://docs.platformio.org/page/projectconf.html [env:esp32thing] -platform = espressif32 +platform = https://github.com/platformio/platform-espressif32.git#feature/stage +;platform = espressif32 board = esp32thing +board_f_cpu = 240000000L +board_f_flash = 80000000L framework = arduino +build_flags = -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG + +lib_deps = +; Basecamp + https://github.com/merlinschumacher/Basecamp.git + u8g2 +lib_ignore = ESPAsyncTCP diff --git a/src/main.cpp b/src/main.cpp index b87a9e5..5772f51 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,34 +1,176 @@ -/** - * Blink - * - * Turns on an LED on for one second, - * then off for one second, repeatedly. - * - * https://github.com/platformio/platformio-examples/tree/develop/espressif - */ -#include "Arduino.h" - -#ifndef LED_BUILTIN -#define LED_BUILTIN 13 +//Define DEBUG to get the Output from DEBUG_PRINTLN +#define DEBUG 1 + +//Include Basecamp in this sketch +#include +#include + +#include +#ifdef U8X8_HAVE_HW_SPI +#include +#endif +#ifdef U8X8_HAVE_HW_I2C +#include #endif -void setup() +#include "main.h" + +U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ 15, /* data=*/ 4, /* reset=*/ 16); + +//Create a new Basecamp instance called iot +Basecamp iot; + +//Variables for the sensor and the battery +static const int ResetPin = 35; +static const int SensorPin = 32; +static const int BatteryPin = 34; +int sensorValue = 0; +//The batteryLimit defines the point at which the battery is considered empty. +int batteryLimit = 3300; + +//This is used to control if the ESP should enter sleep mode or not +bool delaySleep = false; + +//Variables for the mqtt packages and topics +uint16_t statusPacketIdSub = 0; +String delaySleepTopic; +String statusTopic; +String batteryTopic; +String batteryValueTopic; + +// Reset the configuration to factory defaults (all empty) +void resetToFactoryDefaults() { - // initialize LED digital pin as an output. - pinMode(LED_BUILTIN, OUTPUT); + DEBUG_PRINTLN("Resetting to factory defaults"); + Configuration config(String{"/basecamp.json"}); + config.load(); + config.reset(); + config.save(); } -void loop() -{ - // turn the LED on (HIGH is the voltage level) - digitalWrite(LED_BUILTIN, HIGH); +void setup() { + //configuration of the battery and sensor pins + pinMode(ResetPin, INPUT_PULLDOWN); + pinMode(SensorPin, INPUT_PULLDOWN); + pinMode(BatteryPin, INPUT); + + //read the status of the doorsensor as soon as possible to determine the state that triggered it + sensorValue = digitalRead(SensorPin); + + bool resetPressed = (digitalRead(ResetPin) == HIGH); + if (resetPressed) + { + resetToFactoryDefaults(); + } - // wait for a second - delay(1000); + u8g2.begin(); + delay(50); + u8g2.clearBuffer(); // clear the internal memory + u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font + u8g2.drawStr(0,10,"Hello World!"); // write something to the internal memory + u8g2.sendBuffer(); // transfer internal memory to the display - // turn the LED off by making the voltage LOW - digitalWrite(LED_BUILTIN, LOW); + //Initialize Basecamp + iot.begin(); - // wait for a second - delay(1000); + if (resetPressed) { + DEBUG_PRINTLN("**** CONFIG HAS BEEN MANUALLY RESET ****"); + } + + //Configure the MQTT topics + delaySleepTopic = "esp32-node/cmd/" + iot.hostname + "/delaysleep"; + statusTopic = "esp32-node/stat/" + iot.hostname + "/status"; + batteryTopic = "esp32-node/stat/" + iot.hostname + "/battery"; + batteryValueTopic = "esp32-node/stat/" + iot.hostname + "/batteryvalue"; + + //Set up the Callbacks for the MQTT instance. Refer to the Async MQTT Client documentation + // TODO: We should do this actually _before_ connecting the mqtt client... + iot.mqtt.onConnect(onMqttConnect); + iot.mqtt.onPublish(suspendESP); + iot.mqtt.onMessage(onMqttMessage); } + + +//This function is called when the MQTT-Server is connected +void onMqttConnect(bool sessionPresent) { + DEBUG_PRINTLN(__func__); + + //Subscribe to the delay topic + iot.mqtt.subscribe(delaySleepTopic.c_str(), 0); + //Trigger the transmission of the current state. + transmitStatus(); +} + + +//This function transfers the state of the sensor. That includes the door status, battery status and level +void transmitStatus() { + DEBUG_PRINTLN(__func__); + + if (sensorValue == 0) { + DEBUG_PRINTLN("Door open"); + //Transfer the current state of the sensor to the MQTT broker + statusPacketIdSub = iot.mqtt.publish(statusTopic.c_str(), 1, true, "open" ); + //Configure the wakeup pin to wake if the door is closed + esp_sleep_enable_ext0_wakeup((gpio_num_t)SensorPin, 1); + } else { + DEBUG_PRINTLN("Door closed"); + //Transfer the current state of the sensor to the MQTT broker + statusPacketIdSub = iot.mqtt.publish(statusTopic.c_str(), 1, true, "closed" ); + //Configure the wakeup pin to wake if the door is closed + esp_sleep_enable_ext0_wakeup((gpio_num_t)SensorPin, 0); + } + + //Read the current analog battery value + sensorValue = analogRead(BatteryPin); + //sensorC stores the battery value as a char + char sensorC[6]; + //convert the sensor value to a string + sprintf(sensorC, "%04i", sensorValue); + //Send the sensor value to the MQTT broker + iot.mqtt.publish(batteryValueTopic.c_str(), 1, true, sensorC); + //Check the battery level and publish the state + if (sensorValue < batteryLimit) { + DEBUG_PRINTLN("Battery empty"); + iot.mqtt.publish(batteryTopic.c_str(), 1, true, "empty" ); + } else { + DEBUG_PRINTLN("Battery full"); + iot.mqtt.publish(batteryTopic.c_str(), 1, true, "full" ); + } + DEBUG_PRINTLN("Data published"); +} + +//This topic is called if an MQTT message is received +void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) { + DEBUG_PRINTLN(__func__); + + //Check if the payload eqals "true" and set delaySleep correspondigly + //Since we only subscribed to one topic, we only have to compare the payload + if (strcmp(payload, "true") == 0) { + delaySleep = true; + } else { + delaySleep = false; + } +} + +void suspendESP(uint16_t packetId) { + DEBUG_PRINTLN(__func__); + + //Check if the published package is the one of the door sensor + if (packetId == statusPacketIdSub) { + + if (delaySleep == true) { + DEBUG_PRINTLN("Delaying Sleep"); + return; + } + DEBUG_PRINTLN("Entering deep sleep"); + //properly disconnect from the MQTT broker + iot.mqtt.disconnect(); + //send the ESP into deep sleep + esp_deep_sleep_start(); + } +} + +void loop() +{ +} + diff --git a/src/main.h b/src/main.h new file mode 100644 index 0000000..a412623 --- /dev/null +++ b/src/main.h @@ -0,0 +1,7 @@ +void resetToFactoryDefaults(); +void setup(); +void onMqttConnect(bool sessionPresent); +void transmitStatus(); +void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total); +void suspendESP(uint16_t packetId); +void loop();