Files
ESPScroller/src/main.cpp
2021-11-30 16:03:06 +01:00

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();
}
}