318 lines
8.1 KiB
C++
318 lines
8.1 KiB
C++
#include <Wire.h>
|
|
#include <Adafruit_Sensor.h>
|
|
#include <Adafruit_BME280.h>
|
|
|
|
#include <WiFi.h>
|
|
#include <SPI.h>
|
|
#include <FastLED.h>
|
|
#include <FastLED_NeoMatrix.h>
|
|
#include <PubSubClient.h>
|
|
|
|
#include <WiFiMulti.h>
|
|
|
|
#include <HTTPClient.h>
|
|
#include <ArduinoJson.h>
|
|
#include <IotWebConf.h>
|
|
#include <NTP.h>
|
|
#include <SPIFFS.h>
|
|
#include <time.h>
|
|
|
|
#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<NEOPIXEL,PIN>(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();
|
|
}
|
|
}
|
|
|