You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

297 lines
9.5 KiB

7 years ago
//Define DEBUG to get the Output from DEBUG_PRINTLN
#define DEBUG 1
#include <Arduino.h>
7 years ago
/* Wiring (Heltec OLED Lora)
* GND O O GND
* 5V O O 5V
* 3V3 O O 3V3
* GND O < 36
* RX * * 17
* TX * < 38
* RST * BUTTON < 39
* 0 * < 34
* 22 * < 35
* BME280_SDO 19 * LoRa_MISO * 32
* BME280_CS 23 * * 33
* 18 x LoRa_CS * 25 MAX98_DIN
* BME280_SCL/SCK 5 * LoRa_SCK LoRa_IRQ * 26
* 15 * OLED_SCL LoRa_MOSI * 27 BME280_SDA/SDI
* 2 * LoRa_RST * 14
* 4 * OLED_SDA * 12 MAX98_BCLK
* 17 * * 13 MAX98_LRC
* 16 * OLED_RST * 21
*/
7 years ago
//Include Basecamp in this sketch
#include <Basecamp.hpp>
#include <Configuration.hpp>
#include <U8g2lib.h>
#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif
#include <WiFiUdp.h>
#include <NTPClient.h>
7 years ago
#include "main.h"
#include "mp3.h"
7 years ago
#include "BME280.h"
#include "image.h"
7 years ago
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;
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "de.pool.ntp.org", 3600, 60000);
char timeStr[20];
7 years ago
BME280 bme280;
MP3 mp3;
uint32_t lastButtonPress = 0;
7 years ago
//Variables for the sensor and the battery
7 years ago
static const int buttonPin = 0;
static const int ResetPin = 17;
7 years ago
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 = true;
7 years ago
//Variables for the mqtt packages and topics
uint16_t statusPacketIdSub = 0;
String delaySleepTopic;
String statusTopic;
String batteryTopic;
String batteryValueTopic;
void setup() {
7 years ago
// #include "soc/rtc_io_reg.h"
// #include "soc/sens_reg.h"
//
// SET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_MUX_SEL | RTC_IO_X32P_MUX_SEL);
// CLEAR_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32P_RDE | RTC_IO_X32P_RUE | RTC_IO_X32N_RUE | RTC_IO_X32N_RDE);
// CLEAR_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_MUX_SEL | RTC_IO_X32P_MUX_SEL);
// SET_PERI_REG_BITS(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_DAC_XTAL_32K, 1, RTC_IO_DAC_XTAL_32K_S);
// SET_PERI_REG_BITS(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_DRES_XTAL_32K, 3, RTC_IO_DRES_XTAL_32K_S);
// SET_PERI_REG_BITS(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_DBIAS_XTAL_32K, 0, RTC_IO_DBIAS_XTAL_32K_S);
// SET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_XPD_XTAL_32K);
// REG_SET_BIT(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_MUX_SEL_M);
// REG_CLR_BIT(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_RDE_M | RTC_IO_PDAC1_RUE_M);
// REG_SET_FIELD(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_FUN_SEL, 1);
// REG_SET_FIELD(SENS_SAR_DAC_CTRL1_REG, SENS_DEBUG_BIT_SEL, 0);
// const uint8_t sel = 4; /* sel = 4 : 32k XTAL; sel = 5 : internal 150k RC */
// REG_SET_FIELD(RTC_IO_RTC_DEBUG_SEL_REG, RTC_IO_DEBUG_SEL0, sel);
//
7 years ago
//configuration of the battery and sensor pins
7 years ago
// pinMode(ResetPin, INPUT_PULLDOWN);
// pinMode(SensorPin, INPUT_PULLDOWN);
// pinMode(BatteryPin, INPUT);
pinMode(buttonPin, INPUT_PULLUP);
pinMode(18, OUTPUT);
digitalWrite(18, HIGH); // disable LoRa_CS
7 years ago
//read the status of the doorsensor as soon as possible to determine the state that triggered it
7 years ago
// sensorValue = digitalRead(SensorPin);
7 years ago
//Initialize Basecamp
iot.begin();
7 years ago
bme280.begin();
for (int i=0; i<5; i++) {
delay(500);
bme280.printValues();
}
u8g2.begin();
delay(50);
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font
u8g2.drawStr(2,10,"esp32-node by hendrik"); // write something to the internal memory
if (iot.configuration.get("WifiConfigured") != "True") {
u8g2.drawStr(2,30,"NOT CONFIGURED!");
u8g2.drawStr(12,40,"SSID: \"ESP32\"");
u8g2.drawStr(12,55,"http://192.168.4.1");
} else {
u8g2.drawStr(2,30,"Welcome!");
u8g2.drawStr(12,40,"connecting..");
}
u8g2.drawFrame(0,0,u8g2.getDisplayWidth(),u8g2.getDisplayHeight() );
u8g2.sendBuffer(); // transfer internal memory to the display
7 years ago
//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);
while (iot.wifi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
IPAddress localIP = iot.wifi.getIP();
char ipStr[16];
localIP.toString().toCharArray(ipStr, 16);
timeClient.begin();
timeClient.update();
timeClient.getFormattedTime().toCharArray(timeStr, 50);
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font
// u8g2.setDrawColor(2);
u8g2.drawStr(30, 30, timeStr);
u8g2.drawStr(30, 50, ipStr);
u8g2.sendBuffer();
mp3.begin();
u8g2.setContrast(127);
}
7 years ago
//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
7 years ago
// sensorValue = analogRead(BatteryPin);
7 years ago
//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();
}
}
7 years ago
void loop()
{
timeClient.update();
timeClient.getFormattedTime().toCharArray(timeStr, 50);
if (digitalRead(buttonPin) == LOW) {
if(millis() - lastButtonPress >= 1000) {
Serial.println("Button pressed");
lastButtonPress = millis();
if (mp3.playing) {
mp3.stop();
} else {
mp3.start();
}
}
}
u8g2.clearBuffer(); // clear the internal memory
if (digitalRead(buttonPin) == HIGH) {
7 years ago
u8g2.setFont(u8g2_font_inb19_mf);
u8g2.drawStr(0, 20, timeStr);
char title1[32]; char title2[32];
strncpy(title1, titleStr, 22); title1[22] = '\0';
strncpy(title2, titleStr+22, 32); title2[31] = '\0';
char weather[32];
u8g2.setFont(u8g2_font_profont12_mf); // choose a suitable font
sprintf(weather, "%.1f°C %.1f%% %.0fhPa", bme280.readTemperature(), bme280.readHumidity(), bme280.readPressure());
u8g2.drawUTF8(0, 30, weather);
u8g2.setFont(u8g2_font_prospero_bold_nbp_tf); // choose a suitable font
u8g2.drawUTF8(0, 54, title1);
u8g2.drawUTF8(0, 64, title2);
} else {
u8g2.drawXBMP(0,0, IMG_1872_width, IMG_1872_height, IMG_1872_bits);
7 years ago
}
u8g2.sendBuffer();
7 years ago
// bme280.printValues();
7 years ago
7 years ago
delay(100);
}