#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "StringSplitter.h" #include "ESP32TimerInterrupt.h" #include "Scroller.h" #include "calendar.h" #include "TimeZone.h" #include "Ascifii.h" #ifndef PSTR #define PSTR // Make Arduino Due happy #endif Adafruit_BME280 bme; // I2C #define COMMAND_PARAMETER_LENGTH 30 #define MAX_TIMES_SCROLLED 5 #define PIN 13 WiFiClient espClient; PubSubClient client(espClient); unsigned long lastMqttConnectionAttempt=0; void handleRoot(); void processCommand(); // -- Initial name of the Thing. Used e.g. as SSID of the own Access Point. const char thingName[] = "BADThing"; // -- Initial password to connect to the Thing, when it creates an own Access Point. const char wifiInitialApPassword[] = "BADesp32"; #define STRING_LEN 128 char mqttServerValue[STRING_LEN]; DNSServer dnsServer; WebServer server(80); IotWebConf iotWebConf(thingName, &dnsServer, &server, wifiInitialApPassword); IotWebConfParameter mqttServerParam = IotWebConfParameter("MQTT server", "mqttServer", mqttServerValue, STRING_LEN,"text","BADnet-gw.lan","BADnet-gw.lan",NULL); #define lcdw 32 #define lcdh 8 #define NUMMATRIX (lcdw*lcdh) CRGB matrixleds[NUMMATRIX]; FastLED_NeoMatrix *matrix; WiFiUDP ntpUDP; // You can specify the time server pool and the offset (in seconds, can be // changed later with setTimeOffset() ). Additionaly you can specify the // update interval (in milliseconds, can be changed using setUpdateInterval() ). bool initialized = false; NTP ntp(ntpUDP); TimeZone DateTime; Scroller scroller(MAX_TIMES_SCROLLED); unsigned long last_millis; bool showTextMqtt = false; int scrolledTicker = 0; bool updateNtpTime = false; bool needMqttConnect = false; ESP32Timer ITimer0(0); ESP32Timer ITimer1(1); ESP32Timer ITimer2(2); ulong tick; void IRAM_ATTR TimerScrollTime1(void); #define TIMER0_INTERVAL_MS 1000 #define TIMER2_INTERVAL_MS 60000 void IRAM_ATTR TimerScrollTime1(void) { tick++; } void IRAM_ATTR TimerUpdateNTP2(void) { updateNtpTime = true; } void setup_matrix() { matrix = new FastLED_NeoMatrix(matrixleds, lcdw, lcdh, 1, 1, NEO_MATRIX_BOTTOM + NEO_MATRIX_RIGHT + NEO_MATRIX_COLUMNS + NEO_MATRIX_ZIGZAG ); FastLED.addLeds(matrixleds, NUMMATRIX); matrix->begin(); matrix->setTextWrap(false); matrix->setBrightness(20); matrix->setTextColor(Framebuffer_GFX::Color24to16(CRGB::Green)); matrix->print("Start"); matrix->show(); delay(1000); matrix->fillScreen(0); matrix->print(""); matrix->show(); } void returnOK() { server.send(200, "text/plain", ""); } void wifiConnected() { needMqttConnect = true; } #define SEALEVELPRESSURE_HPA (1027.3) void setup() { Serial.begin(115200); DateTime.ruleDST("CEST", Last, Sun, Mar, 2, 120); // last sunday in march 2:00, timetone +120min (+1 GMT + 1h summertime offset) DateTime.ruleSTD("CET", Last, Sun, Oct, 3, 60); // last sunday in october 3:00, timezone +60min (+1 GMT) //iotWebConf.setStatusPin(PIN); iotWebConf.addParameter(&mqttServerParam); iotWebConf.setWifiConnectionCallback(&wifiConnected); iotWebConf.init(); if (ITimer1.attachInterruptInterval(SCROLLER_TICK_TIME * 1000, TimerScrollTime1)) Serial.println("Starting ITimer1 OK, millis() = " + String(millis())); else Serial.println("Can't set ITimer1. Select another freq. or timer"); if (ITimer2.attachInterruptInterval(TIMER2_INTERVAL_MS * 1000, TimerUpdateNTP2)) Serial.println("Starting ITimer2 OK, millis() = " + String(millis())); else Serial.println("Can't set ITimer2. Select another freq. or timer"); // -- Set up required URL handlers on the web server. server.on("/", handleRoot); server.on("/config", [] { iotWebConf.handleConfig(); }); server.onNotFound([]() { iotWebConf.handleNotFound(); }); setup_matrix(); scroller.init(); scroller.SetMatrix(matrix); Serial.println(F("BME280 test")); if (! bme.begin(0x76, &Wire)) { Serial.println("Could not find a valid BME280 sensor, check wiring!"); } Serial.println("-- Default Test --"); Serial.println("normal mode, 16x oversampling for all, filter off,"); bme.takeForcedMeasurement(); // has no effect in normal mode Serial.print("Temperature = "); Serial.print(bme.readTemperature()); Serial.println(" *C"); Serial.print("Pressure = "); Serial.print(bme.readPressure() / 100.0F); Serial.println(" hPa"); Serial.print("Approx. Altitude = "); Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA)); Serial.println(" m"); Serial.print("Humidity = "); Serial.print(bme.readHumidity()); Serial.println(" %"); Serial.println(); } void handleRoot() { // -- Let IotWebConf test and handle captive portal requests. if (iotWebConf.handleCaptivePortal()) { // -- Captive portal request were already served. return; } server.send(200, "text/html", "OK"); } boolean reconnect() { unsigned long now = millis(); if (1000 > now - lastMqttConnectionAttempt) { // Do not repeat within 1 sec. return false; } // Loop until we're reconnected Serial.print("Attempting MQTT connection..."); // Create a random client ID String clientId = "ESP32Client-SCROLLER"; // Attempt to connect if (client.connect(clientId.c_str())) { Serial.println("connected"); // Once connected, publish an announcement... client.subscribe("home/scroller"); client.subscribe("get/home/sensor/decka/bme280"); return true; } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 1 seconds"); // Wait 5 seconds before retrying lastMqttConnectionAttempt = now; return false; } } void callback(char* topic, byte* payload, unsigned int length) { char msg[256]; Serial.print("Message arrived ["); Serial.print(topic); Serial.print("] "); if (String("home/scroller") == String(topic)) { for (int i = 0; i < length; i++) { Serial.print((char)payload[i]); } Serial.println(); strncpy(msg,(char *)payload,length>255 ? 255 : length); msg[length>255 ? 255 : length] = '\0'; // Switch on the LED if an 1 was received as first character //scroller.TurnOff(); //scroller.DeleteLines(); scroller.AddLine(msg); showTextMqtt = true; } else if (String("get/home/sensor/decka/bme280") == String(topic)) { client.publish("home/sensor/decka/bme280/temperature",(String("N:") + String(bme.readTemperature())).c_str()); client.publish("home/sensor/decka/bme280/humidity",(String("N:") + String(bme.readHumidity())).c_str()); client.publish("home/sensor/decka/bme280/pressure",(String("N:") + String(bme.readPressure() / 100.0F)).c_str()); } } void loop() { iotWebConf.doLoop(); if (needMqttConnect) { Serial.println("---INIT---"); ntp.ruleDST("CEST", Last, Sun, Mar, 2, 120); // last sunday in march 2:00, timetone +120min (+1 GMT + 1h summertime offset) ntp.ruleSTD("CET", Last, Sun, Oct, 3, 60); // last sunday in october 3:00, timezone +60min (+1 GMT) ntp.begin(); unsigned long sec = ntp.epoch(); DateTime.setUTCTime(sec); client.setServer(mqttServerValue, 1883); client.setCallback(callback); if (reconnect()) { needMqttConnect = false; } } else if ((iotWebConf.getState() == IOTWEBCONF_STATE_ONLINE) && (!client.connected())) { Serial.println("MQTT reconnect"); client.setServer(mqttServerValue, 1883); client.setCallback(callback); reconnect(); } if (iotWebConf.getState() == IOTWEBCONF_STATE_ONLINE) { if (updateNtpTime) { Serial.println("---NTP UPDATE---"); ntp.update(); unsigned long sec = ntp.epoch(); DateTime.setUTCTime(sec); last_millis = millis(); updateNtpTime = false; } if (showTextMqtt) { scroller.TurnOn(); showTextMqtt = false; } scroller.loop(tick); client.loop(); } }