Add ESP32 dashboard UART JSON protocol
This commit is contained in:
@@ -13,7 +13,8 @@
|
|||||||
#define IGNITION_PIN 34
|
#define IGNITION_PIN 34
|
||||||
|
|
||||||
// UART over CAT5 to Pico dashboard
|
// UART over CAT5 to Pico dashboard
|
||||||
#define UART_TX_PIN 21
|
#define DASHBOARD_UART_TX_PIN 21
|
||||||
#define UART_RX_PIN 22
|
#define DASHBOARD_UART_RX_PIN 22
|
||||||
|
#define DASHBOARD_UART_BAUD 115200
|
||||||
|
|
||||||
// RS-485/MAX3485 fallback only; not currently planned
|
// RS-485/MAX3485 is fallback only and not currently planned.
|
||||||
|
|||||||
@@ -4,3 +4,4 @@
|
|||||||
#define MSG_STATUS_RESPONSE "status_response"
|
#define MSG_STATUS_RESPONSE "status_response"
|
||||||
#define MSG_SET_RELAY "set_relay"
|
#define MSG_SET_RELAY "set_relay"
|
||||||
#define MSG_RELAY_RESPONSE "relay_response"
|
#define MSG_RELAY_RESPONSE "relay_response"
|
||||||
|
#define MSG_ERROR "error"
|
||||||
|
|||||||
@@ -3,10 +3,14 @@
|
|||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "protocol.h"
|
||||||
#include "relays.h"
|
#include "relays.h"
|
||||||
#include "sensors.h"
|
#include "sensors.h"
|
||||||
|
|
||||||
WebServer server(80);
|
WebServer server(80);
|
||||||
|
HardwareSerial DashboardSerial(2);
|
||||||
|
|
||||||
|
String uartLineBuffer;
|
||||||
|
|
||||||
float batterySOC = 82.0;
|
float batterySOC = 82.0;
|
||||||
float batteryVoltage = 13.2;
|
float batteryVoltage = 13.2;
|
||||||
@@ -15,10 +19,8 @@ float batteryRemainingAh = 82.0;
|
|||||||
float batteryRuntimeHours = 12.0;
|
float batteryRuntimeHours = 12.0;
|
||||||
float batteryTemp = 76.0;
|
float batteryTemp = 76.0;
|
||||||
|
|
||||||
void handleStatus() {
|
void buildStatusDocument(JsonDocument& doc) {
|
||||||
|
doc["type"] = MSG_STATUS_RESPONSE;
|
||||||
DynamicJsonDocument doc(2048);
|
|
||||||
|
|
||||||
doc["timestamp"] = millis();
|
doc["timestamp"] = millis();
|
||||||
|
|
||||||
JsonObject battery = doc.createNestedObject("battery");
|
JsonObject battery = doc.createNestedObject("battery");
|
||||||
@@ -51,41 +53,157 @@ void handleStatus() {
|
|||||||
JsonObject network = doc.createNestedObject("network");
|
JsonObject network = doc.createNestedObject("network");
|
||||||
network["wifi_enabled"] = true;
|
network["wifi_enabled"] = true;
|
||||||
network["uart_connected"] = true;
|
network["uart_connected"] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendStatus(Stream& output, bool pretty = false) {
|
||||||
|
DynamicJsonDocument doc(2048);
|
||||||
|
buildStatusDocument(doc);
|
||||||
|
|
||||||
|
if (pretty) {
|
||||||
|
serializeJsonPretty(doc, output);
|
||||||
|
} else {
|
||||||
|
serializeJson(doc, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
output.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendError(Stream& output, const char* message) {
|
||||||
|
DynamicJsonDocument doc(256);
|
||||||
|
doc["type"] = MSG_ERROR;
|
||||||
|
doc["message"] = message;
|
||||||
|
serializeJson(doc, output);
|
||||||
|
output.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool setRelayByName(const char* relayName, bool enabled) {
|
||||||
|
if (strcmp(relayName, "starlink") == 0) {
|
||||||
|
relays.starlink = enabled;
|
||||||
|
} else if (strcmp(relayName, "fridge") == 0) {
|
||||||
|
relays.fridge = enabled;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateRelayOutputs();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendRelayResponse(Stream& output, const char* relayName, bool enabled) {
|
||||||
|
DynamicJsonDocument doc(256);
|
||||||
|
doc["type"] = MSG_RELAY_RESPONSE;
|
||||||
|
doc["relay"] = relayName;
|
||||||
|
doc["enabled"] = enabled;
|
||||||
|
doc["ok"] = true;
|
||||||
|
serializeJson(doc, output);
|
||||||
|
output.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleUartMessage(const String& line) {
|
||||||
|
DynamicJsonDocument doc(512);
|
||||||
|
DeserializationError error = deserializeJson(doc, line);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
sendError(DashboardSerial, "invalid_json");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* type = doc["type"] | "";
|
||||||
|
|
||||||
|
if (strcmp(type, MSG_STATUS_REQUEST) == 0) {
|
||||||
|
sendStatus(DashboardSerial);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(type, MSG_SET_RELAY) == 0) {
|
||||||
|
const char* relayName = doc["relay"] | "";
|
||||||
|
bool enabled = doc["enabled"] | false;
|
||||||
|
|
||||||
|
if (!setRelayByName(relayName, enabled)) {
|
||||||
|
sendError(DashboardSerial, "unknown_relay");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sendRelayResponse(DashboardSerial, relayName, enabled);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sendError(DashboardSerial, "unknown_message_type");
|
||||||
|
}
|
||||||
|
|
||||||
|
void pollDashboardUart() {
|
||||||
|
while (DashboardSerial.available()) {
|
||||||
|
char c = DashboardSerial.read();
|
||||||
|
|
||||||
|
if (c == '\n') {
|
||||||
|
uartLineBuffer.trim();
|
||||||
|
|
||||||
|
if (uartLineBuffer.length() > 0) {
|
||||||
|
handleUartMessage(uartLineBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
uartLineBuffer = "";
|
||||||
|
} else if (c != '\r') {
|
||||||
|
uartLineBuffer += c;
|
||||||
|
|
||||||
|
if (uartLineBuffer.length() > 512) {
|
||||||
|
uartLineBuffer = "";
|
||||||
|
sendError(DashboardSerial, "message_too_long");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleStatus() {
|
||||||
|
server.setContentLength(CONTENT_LENGTH_UNKNOWN);
|
||||||
|
server.send(200, "application/json", "");
|
||||||
|
sendStatus(server.client(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleRelayHttp(const char* relayName, bool enabled) {
|
||||||
|
if (!setRelayByName(relayName, enabled)) {
|
||||||
|
server.send(404, "application/json", "{\"ok\":false,\"error\":\"unknown_relay\"}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicJsonDocument doc(256);
|
||||||
|
doc["type"] = MSG_RELAY_RESPONSE;
|
||||||
|
doc["relay"] = relayName;
|
||||||
|
doc["enabled"] = enabled;
|
||||||
|
doc["ok"] = true;
|
||||||
|
|
||||||
String output;
|
String output;
|
||||||
serializeJsonPretty(doc, output);
|
serializeJson(doc, output);
|
||||||
|
|
||||||
server.send(200, "application/json", output);
|
server.send(200, "application/json", output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleStarlinkOn() {
|
void handleStarlinkOn() {
|
||||||
relays.starlink = true;
|
handleRelayHttp("starlink", true);
|
||||||
updateRelayOutputs();
|
|
||||||
server.send(200, "text/plain", "OK");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleStarlinkOff() {
|
void handleStarlinkOff() {
|
||||||
relays.starlink = false;
|
handleRelayHttp("starlink", false);
|
||||||
updateRelayOutputs();
|
|
||||||
server.send(200, "text/plain", "OK");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleFridgeOn() {
|
void handleFridgeOn() {
|
||||||
relays.fridge = true;
|
handleRelayHttp("fridge", true);
|
||||||
updateRelayOutputs();
|
|
||||||
server.send(200, "text/plain", "OK");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleFridgeOff() {
|
void handleFridgeOff() {
|
||||||
relays.fridge = false;
|
handleRelayHttp("fridge", false);
|
||||||
updateRelayOutputs();
|
|
||||||
server.send(200, "text/plain", "OK");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
|
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
DashboardSerial.begin(
|
||||||
|
DASHBOARD_UART_BAUD,
|
||||||
|
SERIAL_8N1,
|
||||||
|
DASHBOARD_UART_RX_PIN,
|
||||||
|
DASHBOARD_UART_TX_PIN
|
||||||
|
);
|
||||||
|
|
||||||
Serial.println();
|
Serial.println();
|
||||||
Serial.println("==================================");
|
Serial.println("==================================");
|
||||||
Serial.println("Xterra Controller Booting");
|
Serial.println("Xterra Controller Booting");
|
||||||
@@ -117,20 +235,18 @@ void setup() {
|
|||||||
server.begin();
|
server.begin();
|
||||||
|
|
||||||
Serial.println("Web Server Started");
|
Serial.println("Web Server Started");
|
||||||
|
Serial.println("Dashboard UART Started");
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
|
|
||||||
server.handleClient();
|
server.handleClient();
|
||||||
|
pollDashboardUart();
|
||||||
|
|
||||||
static unsigned long lastSensorUpdate = 0;
|
static unsigned long lastSensorUpdate = 0;
|
||||||
|
|
||||||
if (millis() - lastSensorUpdate > 5000) {
|
if (millis() - lastSensorUpdate > 5000) {
|
||||||
|
|
||||||
updateSensors();
|
updateSensors();
|
||||||
|
|
||||||
lastSensorUpdate = millis();
|
lastSensorUpdate = millis();
|
||||||
|
|
||||||
Serial.println("Sensor Update");
|
Serial.println("Sensor Update");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user