[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