[UNTESTED] Patrix, log, console, wifi, mqtt
This commit is contained in:
commit
e0e80dedad
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
.pio
|
||||
.idea
|
||||
21
lib/patrix/Patrix.cpp
Normal file
21
lib/patrix/Patrix.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
#include <Arduino.h>
|
||||
#include <Patrix.h>
|
||||
#include <wifi.h>
|
||||
#include <console.h>
|
||||
#include "mqtt.h"
|
||||
#include "log.h"
|
||||
|
||||
void setup() {
|
||||
delay(500);
|
||||
Serial.begin(115200);
|
||||
info("MAIN", "\n\n\nStartup...");
|
||||
mqttSetup();
|
||||
wifiSetup();
|
||||
patrixSetup();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
consoleLoop();
|
||||
mqttLoop();
|
||||
patrixLoop();
|
||||
}
|
||||
8
lib/patrix/Patrix.h
Normal file
8
lib/patrix/Patrix.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef SENSOR3_PATRIX_H
|
||||
#define SENSOR3_PATRIX_H
|
||||
|
||||
void patrixSetup();
|
||||
|
||||
void patrixLoop();
|
||||
|
||||
#endif
|
||||
74
lib/patrix/console.cpp
Normal file
74
lib/patrix/console.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
#include <console.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include <log.h>
|
||||
#include <Esp.h>
|
||||
#include <WiFi.h>
|
||||
#include "mqtt.h"
|
||||
#include "wifi.h"
|
||||
|
||||
char consoleBuffer[64] = "";
|
||||
|
||||
char *consoleBufferW = consoleBuffer;
|
||||
|
||||
void consoleLoop() {
|
||||
uint8_t i = 0;
|
||||
while (Serial.available() > 0 && i++ < 100) {
|
||||
const char symbol = static_cast<char>(Serial.read());
|
||||
if (symbol == '\n' || symbol == '\r') {
|
||||
if (*consoleBuffer != 0) {
|
||||
Serial.print('\n');
|
||||
info("CONSOLE", "> %s", consoleBuffer);
|
||||
consoleHandle(consoleBuffer);
|
||||
consoleBufferW = consoleBuffer;
|
||||
*consoleBufferW = 0;
|
||||
}
|
||||
} else if (symbol == '\b') {
|
||||
if (consoleBufferW > consoleBuffer) {
|
||||
consoleBufferW--;
|
||||
*consoleBufferW = 0;
|
||||
Serial.print("\b \b");
|
||||
}
|
||||
} else {
|
||||
if (consoleBufferW < consoleBuffer + sizeof consoleBuffer - 1) {
|
||||
*consoleBufferW = symbol;
|
||||
consoleBufferW++;
|
||||
*consoleBufferW = 0;
|
||||
Serial.print("\r");
|
||||
Serial.print(consoleBuffer);
|
||||
} else {
|
||||
Serial.print("\nCONSOLE BUFFER OVERFLOW\n");
|
||||
Serial.print(consoleBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void consoleHandle(const char *cmd) {
|
||||
if (strcmp(cmd, "help") == 0) {
|
||||
info("CONSOLE", "help : print this help");
|
||||
info("CONSOLE", "net : print network info");
|
||||
info("CONSOLE", "reboot : reboot system");
|
||||
info("CONSOLE", "wifi : reconnect wifi");
|
||||
info("CONSOLE", "mqtt : reconnect mqtt");
|
||||
} else if (strcmp(cmd, "net") == 0) {
|
||||
info("CONSOLE", "MAC: %17s", WiFi.macAddress().c_str());
|
||||
info("CONSOLE", "IP: %17s", WiFi.localIP().toString().c_str());
|
||||
info("CONSOLE", "Gateway: %17s", WiFi.gatewayIP().toString().c_str());
|
||||
info("CONSOLE", "SSID: %17s", WiFi.SSID().c_str());
|
||||
info("CONSOLE", "BSSID: %17s", WiFi.BSSIDstr().c_str());
|
||||
info("CONSOLE", "RSSI: %17d", WiFi.RSSI());
|
||||
} else if (strcmp(cmd, "reboot") == 0) {
|
||||
info("CONSOLE", "Rebooting...");
|
||||
delay(500);
|
||||
yield();
|
||||
ESP.restart();
|
||||
} else if (strcmp(cmd, "wifi") == 0) {
|
||||
info("CONSOLE", "Reconnecting WiFi...");
|
||||
wifiConnect();
|
||||
} else if (strcmp(cmd, "mqtt") == 0) {
|
||||
info("CONSOLE", "Reconnecting MQTT...");
|
||||
mqttDisconnect();
|
||||
} else {
|
||||
info("CONSOLE", "Unknown command: %s", cmd);
|
||||
}
|
||||
}
|
||||
8
lib/patrix/console.h
Normal file
8
lib/patrix/console.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef SENSOR3_CONSOLE_H
|
||||
#define SENSOR3_CONSOLE_H
|
||||
|
||||
void consoleLoop();
|
||||
|
||||
void consoleHandle(const char *cmd);
|
||||
|
||||
#endif
|
||||
41
lib/patrix/log.cpp
Normal file
41
lib/patrix/log.cpp
Normal file
@ -0,0 +1,41 @@
|
||||
#include <HardwareSerial.h>
|
||||
#include "log.h"
|
||||
#include "mqtt.h"
|
||||
|
||||
#define SEPARATOR " | "
|
||||
|
||||
void getDateTime(char *buffer, size_t size) {
|
||||
time_t now;
|
||||
time(&now);
|
||||
tm time{};
|
||||
localtime_r(&now, &time);
|
||||
strftime(buffer, size, "%Y-%m-%d %H:%M:%S %z", &time);
|
||||
}
|
||||
|
||||
void log(const char *level, const char *module, const char *format, ...) {
|
||||
char datetime[26];
|
||||
getDateTime(datetime, sizeof datetime);
|
||||
|
||||
va_list vl;
|
||||
va_start(vl, format);
|
||||
char message[500];
|
||||
vsnprintf(message, sizeof message, format, vl);
|
||||
va_end(vl);
|
||||
|
||||
const size_t len = Serial.print(datetime) + Serial.print(SEPARATOR) + Serial.print(module) + Serial.print(SEPARATOR) + Serial.print(level) + Serial.print(SEPARATOR) + Serial.print(message) + Serial.println();
|
||||
mqttLog(len, SEPARATOR, datetime, module, level, message);
|
||||
}
|
||||
|
||||
void info(const char *module, const char *format, ...) {
|
||||
va_list vl;
|
||||
va_start(vl, format);
|
||||
log("INFO", module, format, vl);
|
||||
va_end(vl);
|
||||
}
|
||||
|
||||
void error(const char *module, const char *format, ...) {
|
||||
va_list vl;
|
||||
va_start(vl, format);
|
||||
log("ERROR", module, format, vl);
|
||||
va_end(vl);
|
||||
}
|
||||
8
lib/patrix/log.h
Normal file
8
lib/patrix/log.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef SENSOR3_LOG_H
|
||||
#define SENSOR3_LOG_H
|
||||
|
||||
void info(const char *module, const char *format, ...);
|
||||
|
||||
void error(const char *module, const char *format, ...);
|
||||
|
||||
#endif
|
||||
79
lib/patrix/mqtt.cpp
Normal file
79
lib/patrix/mqtt.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
#include "mqtt.h"
|
||||
|
||||
#include <WiFiClient.h>
|
||||
#include <WiFi.h>
|
||||
#include "log.h"
|
||||
#include "PubSubClient.h"
|
||||
#include "console.h"
|
||||
|
||||
#define CONNECT_TIMEOUT_MILLISECONDS 5000
|
||||
|
||||
unsigned long mqttLastConnectTry = 0;
|
||||
|
||||
WiFiClient espClient;
|
||||
|
||||
PubSubClient mqtt(espClient);
|
||||
|
||||
char logTopic[32] = "log/UNSET";
|
||||
|
||||
char cmdTopic[64] = "cmd/UNSET";
|
||||
|
||||
void mqttSetup() {
|
||||
snprintf(logTopic, sizeof logTopic, "%s/%s", "log", HOSTNAME);
|
||||
snprintf(cmdTopic, sizeof cmdTopic, "%s/%s", "cmd", HOSTNAME);
|
||||
}
|
||||
|
||||
void mqttLog(const size_t len, const char *separator, const char *datetime, const char *module, const char *level, const char *message) {
|
||||
if (mqtt.beginPublish(logTopic, len, false)) {
|
||||
mqtt.print(datetime);
|
||||
mqtt.print(separator);
|
||||
mqtt.print(module);
|
||||
mqtt.print(separator);
|
||||
mqtt.print(level);
|
||||
mqtt.print(separator);
|
||||
mqtt.print(message);
|
||||
mqtt.endPublish();
|
||||
}
|
||||
}
|
||||
|
||||
void mqttDisconnect() {
|
||||
mqtt.disconnect();
|
||||
}
|
||||
|
||||
void mqttLoop() {
|
||||
if (WiFi.localIP() != 0 && !mqtt.connected() && (mqttLastConnectTry == 0 || millis() - mqttLastConnectTry > CONNECT_TIMEOUT_MILLISECONDS)) {
|
||||
mqttLastConnectTry = millis();
|
||||
mqtt.setServer("10.0.0.50", 1883);
|
||||
if (!mqtt.connect(HOSTNAME, logTopic, 0, false, "disconnected")) {
|
||||
Serial.printf("failed to connect\n");
|
||||
return;
|
||||
}
|
||||
info("MQTT", "connected");
|
||||
mqtt.setBufferSize(512);
|
||||
mqtt.subscribe(cmdTopic);
|
||||
mqtt.setCallback([](const char *topic, const uint8_t *bytes, const unsigned int length) {
|
||||
char content[64];
|
||||
if (length > sizeof content - 1) {
|
||||
error("MQTT", "RECEIVE BUFFER OVERFLOW");
|
||||
return;
|
||||
}
|
||||
memcpy(content, bytes, length);
|
||||
content[length] = 0;
|
||||
|
||||
if (strcmp(topic, cmdTopic) == 0) {
|
||||
info("MQTT", "CMD > %s", content);
|
||||
consoleHandle(content);
|
||||
}
|
||||
});
|
||||
}
|
||||
mqtt.loop();
|
||||
}
|
||||
|
||||
bool mqttPublish(const char *topic, const JsonDocument &doc) {
|
||||
if (!mqtt.connected()) {
|
||||
return false;
|
||||
}
|
||||
char buffer[512];
|
||||
const size_t size = serializeJson(doc, buffer);
|
||||
return mqtt.publish(topic, buffer, size);
|
||||
}
|
||||
16
lib/patrix/mqtt.h
Normal file
16
lib/patrix/mqtt.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef SENSOR3_MQTT_H
|
||||
#define SENSOR3_MQTT_H
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
void mqttSetup();
|
||||
|
||||
void mqttLoop();
|
||||
|
||||
void mqttDisconnect();
|
||||
|
||||
void mqttLog(size_t len, const char *separator, const char *datetime, const char *module, const char *level, const char *message);
|
||||
|
||||
bool mqttPublish(const char *topic, const JsonDocument &doc);
|
||||
|
||||
#endif
|
||||
159
lib/patrix/wifi.cpp
Normal file
159
lib/patrix/wifi.cpp
Normal file
@ -0,0 +1,159 @@
|
||||
#include "wifi.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <ArduinoOTA.h>
|
||||
|
||||
#define NTP_SERVER "pool.ntp.org"
|
||||
|
||||
#define TIMEZONE_OFFSET 3600
|
||||
|
||||
#define DST_OFFSET 3600
|
||||
|
||||
#define MIN_EPOCH_SECONDS 1712675973
|
||||
|
||||
uint8_t otaLastLogStep = 0;
|
||||
|
||||
bool wifiConnected = false;
|
||||
|
||||
bool timeSet = false;
|
||||
|
||||
time_t preTimeOffset = 0;
|
||||
|
||||
unsigned long wifiLastConnectTry = 0;
|
||||
|
||||
void otaSetup();
|
||||
|
||||
void bootDelay();
|
||||
|
||||
void wifiSetup() {
|
||||
WiFi.softAPdisconnect();
|
||||
WiFi.setAutoReconnect(false);
|
||||
wifiConnect();
|
||||
otaSetup();
|
||||
configTime(TIMEZONE_OFFSET, DST_OFFSET, NTP_SERVER, WiFi.gatewayIP().toString().c_str());
|
||||
bootDelay();
|
||||
}
|
||||
|
||||
void wifiConnect() {
|
||||
WiFi.disconnect();
|
||||
yield();
|
||||
wifiLastConnectTry = millis();
|
||||
info("WIFI", "Connecting: %s", WIFI_SSID);
|
||||
WiFi.begin(WIFI_SSID, WIFI_PKEY);
|
||||
yield();
|
||||
}
|
||||
|
||||
void otaSetup() {
|
||||
ArduinoOTA.onStart([] {
|
||||
info("OTA", "Start!");
|
||||
otaLastLogStep = 0;
|
||||
});
|
||||
ArduinoOTA.onProgress([](unsigned int received, unsigned int total) {
|
||||
uint8_t currentStep = 20 * received / total;
|
||||
if (otaLastLogStep != currentStep) {
|
||||
info("OTA", "Progress: %3d%%", currentStep * 5);
|
||||
otaLastLogStep = currentStep;
|
||||
}
|
||||
});
|
||||
ArduinoOTA.onEnd([] {
|
||||
info("OTA", "Complete!");
|
||||
});
|
||||
ArduinoOTA.onError([](ota_error_t e) {
|
||||
const char *name;
|
||||
switch (e) {
|
||||
case OTA_AUTH_ERROR:
|
||||
name = "AUTH";
|
||||
break;
|
||||
case OTA_BEGIN_ERROR:
|
||||
name = "BEGIN";
|
||||
break;
|
||||
case OTA_CONNECT_ERROR:
|
||||
name = "CONNECT";
|
||||
break;
|
||||
case OTA_RECEIVE_ERROR:
|
||||
name = "RECEIVE";
|
||||
break;
|
||||
case OTA_END_ERROR:
|
||||
name = "END";
|
||||
break;
|
||||
default:
|
||||
name = "[???]";
|
||||
break;
|
||||
}
|
||||
error("OTA", name);
|
||||
});
|
||||
ArduinoOTA.begin();
|
||||
}
|
||||
|
||||
void bootDelay() {
|
||||
#ifdef BOOT_DELAY
|
||||
info("BOOT DELAY", "Waiting for WiFi...");
|
||||
while ((uint32_t) WiFi.localIP() == 0) {
|
||||
delay(100);
|
||||
yield();
|
||||
wifiLoop();
|
||||
}
|
||||
info("BOOT DELAY", "WiFi connected!");
|
||||
unsigned long begin = millis();
|
||||
while (millis() - begin < 10000) {
|
||||
delay(100);
|
||||
yield();
|
||||
wifiLoop();
|
||||
}
|
||||
info("BOOT DELAY", "Completed.");
|
||||
#endif
|
||||
}
|
||||
|
||||
void wifiLoop() {
|
||||
const time_t epochSeconds = getTime();
|
||||
if (!timeSet) {
|
||||
timeSet = epochSeconds >= MIN_EPOCH_SECONDS;
|
||||
if (!timeSet) {
|
||||
preTimeOffset = epochSeconds;
|
||||
} else {
|
||||
info("NTP", "Time set!");
|
||||
}
|
||||
}
|
||||
|
||||
const bool hasIp = static_cast<uint32_t>(WiFi.localIP()) != 0;
|
||||
if (wifiConnected) {
|
||||
if (!hasIp) {
|
||||
wifiConnected = false;
|
||||
info("WIFI", "Disconnected!");
|
||||
wifiConnect();
|
||||
}
|
||||
} else {
|
||||
if (hasIp) {
|
||||
wifiConnected = true;
|
||||
info("WIFI", "Connected as: %s", WiFi.localIP().toString().c_str());
|
||||
} else if (millis() - wifiLastConnectTry > 10000) {
|
||||
info("WIFI", "Timeout!");
|
||||
wifiConnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool isTimeSet() {
|
||||
return timeSet;
|
||||
}
|
||||
|
||||
time_t getTime() {
|
||||
time_t epochSeconds;
|
||||
time(&epochSeconds);
|
||||
return epochSeconds;
|
||||
}
|
||||
|
||||
time_t correctTime(const time_t value) {
|
||||
if (!timeSet) {
|
||||
return value;
|
||||
}
|
||||
if (value < MIN_EPOCH_SECONDS) {
|
||||
return getTime() - preTimeOffset + value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
bool isOlderThan(time_t time, time_t seconds) {
|
||||
return getTime() > correctTime(time) + seconds;
|
||||
}
|
||||
20
lib/patrix/wifi.h
Normal file
20
lib/patrix/wifi.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef GAERBOX_WIFI_H
|
||||
#define GAERBOX_WIFI_H
|
||||
|
||||
#include <ctime>
|
||||
|
||||
void wifiSetup();
|
||||
|
||||
void wifiLoop();
|
||||
|
||||
void wifiConnect();
|
||||
|
||||
bool isTimeSet();
|
||||
|
||||
time_t getTime();
|
||||
|
||||
time_t correctTime(time_t value);
|
||||
|
||||
bool isOlderThan(time_t time, time_t seconds);
|
||||
|
||||
#endif
|
||||
15
platformio.ini
Normal file
15
platformio.ini
Normal file
@ -0,0 +1,15 @@
|
||||
[env:Fermenter]
|
||||
platform = espressif32
|
||||
board = esp32dev
|
||||
framework = arduino
|
||||
upload_port = /dev/ttyUSB0
|
||||
upload_speed = 921600
|
||||
;upload_protocol = espota
|
||||
;upload_port =
|
||||
;upload_flags = --auth=OtaAuthPatrixFermenter
|
||||
monitor_port = /dev/ttyUSB0
|
||||
monitor_speed = 115200
|
||||
monitor_filters = esp32_exception_decoder
|
||||
build_flags = -D HOSTNAME=\"Fermenter\" -D WIFI_SSID=\"HappyNet\" -D WIFI_PKEY=\"1Grausame!Sackratte7\" -D OTA_PASSWORD=\"OtaAuthPatrixFermenter\" -D BOOT_DELAY=true
|
||||
lib_deps = knolleary/PubSubClient
|
||||
bblanchon/ArduinoJson
|
||||
9
src/Fermenter.cpp
Normal file
9
src/Fermenter.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
#include <Patrix.h>
|
||||
|
||||
void patrixSetup() {
|
||||
|
||||
}
|
||||
|
||||
void patrixLoop() {
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user