generated from CubeCraft-Creations/Tracehound
Dev #26
@@ -65,7 +65,9 @@ platform = https://github.com/pioarduino/platform-espressif32/releases/download/
|
||||
board = seeed_xiao_esp32c6
|
||||
framework = arduino
|
||||
monitor_speed = 115200
|
||||
lib_deps = ${common.lib_deps}
|
||||
lib_deps =
|
||||
${common.lib_deps}
|
||||
olikraus/U8g2 @ ^2.35
|
||||
build_flags = ${common.build_flags}
|
||||
-D CONFIG_ARDUINO_LOOP_STACK_SIZE=8192
|
||||
-D ARDUINO_USB_MODE=1
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
#include <PubSubClient.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <SPIFFS.h>
|
||||
#include <Wire.h>
|
||||
#include <U8g2lib.h>
|
||||
|
||||
// ────────────────────────────────────────────
|
||||
// Configuration (SPIFFS)
|
||||
@@ -91,9 +93,58 @@ bool saveConfig() {
|
||||
#define UART_TX_PIN D6
|
||||
|
||||
// Camera-online indicator → green channel of the RGB STAT LED.
|
||||
// (Full RGB/OLED status-panel bring-up is not implemented yet.)
|
||||
#define STAT_LED_PIN D1
|
||||
|
||||
// ────────────────────────────────────────────
|
||||
// Status OLED — 1.3" I2C panel on D4(SDA)/D5(SCL)
|
||||
// ────────────────────────────────────────────
|
||||
// 1.3" 128x64 modules are SH1106. If the image is shifted ~2px or
|
||||
// wrapped, the panel is an SSD1306 — swap the constructor below to
|
||||
// U8G2_SSD1306_128X64_NONAME_F_HW_I2C.
|
||||
#define OLED_SDA_PIN D4
|
||||
#define OLED_SCL_PIN D5
|
||||
#define OLED_I2C_ADDR 0x3C
|
||||
|
||||
U8G2_SH1106_128X64_NONAME_F_HW_I2C oled(U8G2_R0, U8X8_PIN_NONE);
|
||||
bool oledReady = false;
|
||||
|
||||
// Last-known camera status, mirrored for the display.
|
||||
int dispBatteryRaw = 0;
|
||||
bool dispRecording = false;
|
||||
int dispVideoRemain = 0; // seconds
|
||||
unsigned long recStartMs = 0; // 0 = not recording
|
||||
|
||||
// Walk the bus and log every responder — confirms the OLED address
|
||||
// (and wiring) independent of the display driver.
|
||||
void i2cScan() {
|
||||
Serial.println("[I2C] Scanning...");
|
||||
byte found = 0;
|
||||
for (byte a = 1; a < 127; a++) {
|
||||
Wire.beginTransmission(a);
|
||||
if (Wire.endTransmission() == 0) {
|
||||
Serial.printf("[I2C] device @ 0x%02X\n", a);
|
||||
found++;
|
||||
}
|
||||
}
|
||||
if (!found) Serial.println("[I2C] none found — check wiring/power");
|
||||
}
|
||||
|
||||
void displayInit() {
|
||||
Wire.begin(OLED_SDA_PIN, OLED_SCL_PIN);
|
||||
i2cScan();
|
||||
oled.setI2CAddress(OLED_I2C_ADDR << 1);
|
||||
oledReady = oled.begin();
|
||||
Serial.printf("[OLED] begin %s\n", oledReady ? "ok" : "FAILED");
|
||||
if (!oledReady) return;
|
||||
oled.clearBuffer();
|
||||
oled.setFont(u8g2_font_7x14B_tr);
|
||||
oled.drawStr(0, 14, "RemoteRig");
|
||||
oled.setFont(u8g2_font_6x10_tr);
|
||||
oled.drawStr(0, 32, "Camera node");
|
||||
oled.drawStr(0, 46, "booting...");
|
||||
oled.sendBuffer();
|
||||
}
|
||||
|
||||
void sendCmdToESP8266(const String& command) {
|
||||
JsonDocument doc;
|
||||
doc["type"] = "cmd";
|
||||
@@ -201,6 +252,48 @@ bool connectMQTT() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// ────────────────────────────────────────────
|
||||
// Status screen
|
||||
// ────────────────────────────────────────────
|
||||
|
||||
void renderStatus() {
|
||||
if (!oledReady) return;
|
||||
oled.clearBuffer();
|
||||
|
||||
// Camera id (top, bold)
|
||||
oled.setFont(u8g2_font_7x14B_tr);
|
||||
String id = cfg.camera_id.length() ? cfg.camera_id : clientID();
|
||||
oled.drawStr(0, 13, id.c_str());
|
||||
|
||||
oled.setFont(u8g2_font_6x10_tr);
|
||||
char line[24];
|
||||
|
||||
// REC state + session timer
|
||||
if (dispRecording) {
|
||||
unsigned long s = recStartMs ? (millis() - recStartMs) / 1000 : 0;
|
||||
oled.drawBox(0, 19, 6, 6); // filled square = REC
|
||||
snprintf(line, sizeof(line), "REC %02lu:%02lu", s / 60, s % 60);
|
||||
oled.drawStr(10, 26, line);
|
||||
} else {
|
||||
oled.drawStr(0, 26, "IDLE");
|
||||
}
|
||||
|
||||
// Battery (raw until calibrated) + video remaining (minutes)
|
||||
snprintf(line, sizeof(line), "BAT %d VID %dm", dispBatteryRaw, dispVideoRemain / 60);
|
||||
oled.drawStr(0, 38, line);
|
||||
|
||||
// Uplink to the hub
|
||||
const char* link = mqtt.connected() ? "LINK: MQTT ok"
|
||||
: WiFi.status() == WL_CONNECTED ? "LINK: wifi only"
|
||||
: "LINK: offline";
|
||||
oled.drawStr(0, 50, link);
|
||||
|
||||
// Camera reachability
|
||||
oled.drawStr(0, 62, cameraOnline ? "CAM: online" : "CAM: --");
|
||||
|
||||
oled.sendBuffer();
|
||||
}
|
||||
|
||||
// ────────────────────────────────────────────
|
||||
// Setup
|
||||
// ────────────────────────────────────────────
|
||||
@@ -214,6 +307,8 @@ void setup() {
|
||||
pinMode(STAT_LED_PIN, OUTPUT); // RGB STAT LED — green = camera online
|
||||
digitalWrite(STAT_LED_PIN, LOW);
|
||||
|
||||
displayInit(); // I2C scan + OLED splash
|
||||
|
||||
loadConfig();
|
||||
|
||||
// UART to ESP-01S
|
||||
@@ -251,6 +346,10 @@ void loop() {
|
||||
static unsigned long lastBeat = 0, lastRecon = 0;
|
||||
static int reconDelay = 1;
|
||||
|
||||
// ── OLED refresh (always — keep the panel live even when offline) ──
|
||||
static unsigned long lastDisp = 0;
|
||||
if (now - lastDisp > 500) { lastDisp = now; renderStatus(); }
|
||||
|
||||
// ── Wi-Fi watchdog ──
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
if (now - lastRecon > 5000) { lastRecon = now; WiFi.reconnect(); }
|
||||
@@ -288,6 +387,14 @@ void loop() {
|
||||
digitalWrite(STAT_LED_PIN, online ? HIGH : LOW);
|
||||
}
|
||||
|
||||
// Mirror status onto the OLED fields
|
||||
dispBatteryRaw = doc["battery_raw"] | 0;
|
||||
dispVideoRemain = doc["video_remaining_sec"] | 0;
|
||||
bool rec = doc["recording"] | false;
|
||||
if (rec && !dispRecording) recStartMs = millis();
|
||||
if (!rec) recStartMs = 0;
|
||||
dispRecording = rec;
|
||||
|
||||
if (cfg.camera_id.length() > 0) {
|
||||
// Build the MQTT status payload per contract
|
||||
JsonDocument mqttDoc;
|
||||
|
||||
Reference in New Issue
Block a user