From 335ebf546d6f1f15c0bf4dbce08dd8a65d1ceb2c Mon Sep 17 00:00:00 2001 From: Hacuchino-hash <246103064+Hacuchino-hash@users.noreply.github.com> Date: Wed, 5 Aug 2026 09:34:02 -0500 Subject: [PATCH] Add SPA06 barometer telemetry and charge status LED for MeshTracker X1 --- examples/companion_radio/ui-orig/UITask.cpp | 30 +++++++++++++++++++++ variants/meshtracker_x1/platformio.ini | 2 ++ variants/meshtracker_x1/target.cpp | 16 +++++++++++ variants/meshtracker_x1/target.h | 3 +++ variants/meshtracker_x1/variant.cpp | 3 ++- variants/meshtracker_x1/variant.h | 1 + 6 files changed, 54 insertions(+), 1 deletion(-) diff --git a/examples/companion_radio/ui-orig/UITask.cpp b/examples/companion_radio/ui-orig/UITask.cpp index 08fc9b7ab..1e9613165 100644 --- a/examples/companion_radio/ui-orig/UITask.cpp +++ b/examples/companion_radio/ui-orig/UITask.cpp @@ -337,6 +337,36 @@ void UITask::userLedHandler() { next_batt_check = cur_time + 60000; } +#ifdef EXT_CHRG_DETECT + // charge status display while docked (skipped when messages are waiting, + // so the unread indication is never masked) + static unsigned long next_pwr_check = 0; + static bool ext_powered = false, ext_charging = false; + if (cur_time > next_pwr_check) { + ext_powered = _board->isExternalPowered(); + bool chrg = digitalRead(EXT_CHRG_DETECT) == LOW; + #ifdef EXT_CHRG_DONE + if (digitalRead(EXT_CHRG_DONE) == LOW) chrg = false; // charge-done wins + #endif + ext_charging = ext_powered && chrg; + next_pwr_check = cur_time + 1000; + } + if (ext_powered && _msgcount == 0) { + if (ext_charging) { + // amber breathing while charging + int ph = cur_time % 2000; + int v = ph < 1000 ? ph : 2000 - ph; + uint8_t lvl = (uint8_t)(v * 255 / 1000); + statusLedWrite(lvl, (uint8_t)(lvl * 35 / 100), 0); + } else { + statusLedWrite(0, 40, 0); // dim solid green: charge complete + } + state = 0; + next_change = cur_time; + return; + } +#endif + if (cur_time > next_change) { if (state == 0) { state = 1; diff --git a/variants/meshtracker_x1/platformio.ini b/variants/meshtracker_x1/platformio.ini index 185069168..6a46a79f9 100644 --- a/variants/meshtracker_x1/platformio.ini +++ b/variants/meshtracker_x1/platformio.ini @@ -32,6 +32,8 @@ build_flags = ${nrf52_base.build_flags} build_src_filter = ${nrf52_base.build_src_filter} + +<../variants/meshtracker_x1> +lib_deps = ${nrf52_base.lib_deps} + https://github.com/adafruit/Adafruit_SPA06_003/archive/refs/tags/1.0.2.zip debug_tool = jlink upload_protocol = nrfutil diff --git a/variants/meshtracker_x1/target.cpp b/variants/meshtracker_x1/target.cpp index 1139b8b71..d6d548b51 100644 --- a/variants/meshtracker_x1/target.cpp +++ b/variants/meshtracker_x1/target.cpp @@ -67,6 +67,17 @@ void MeshTrackerX1SensorManager::stop_gps() { bool MeshTrackerX1SensorManager::begin() { // init GPS Serial1.begin(GPS_BAUD_RATE); + + // init SPA06-003 barometer + baro_ok = spa06.begin(SPA06_003_DEFAULT_ADDR, &Wire) || spa06.begin(0x76, &Wire); + if (baro_ok) { + spa06.setPressureOversampling(SPA06_003_OVERSAMPLE_8); + spa06.setTemperatureOversampling(SPA06_003_OVERSAMPLE_8); + // 1 Hz continuous keeps reads non-blocking at minimal power cost + spa06.setPressureMeasureRate(SPA06_003_RATE_1); + spa06.setTemperatureMeasureRate(SPA06_003_RATE_1); + spa06.setMeasurementMode(SPA06_003_MEAS_CONTINUOUS_BOTH); + } return true; } @@ -74,12 +85,17 @@ bool MeshTrackerX1SensorManager::querySensors(uint8_t requester_permissions, Cay if (requester_permissions & TELEM_PERM_LOCATION) { // does requester have permission? telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, node_altitude); } + if (requester_permissions & TELEM_PERM_ENVIRONMENT && baro_ok) { + telemetry.addTemperature(TELEM_CHANNEL_SELF, spa06.readTemperature()); + telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, spa06.readPressure()); + } return true; } void MeshTrackerX1SensorManager::loop() { static long next_gps_update = 0; + _nmea->loop(); if (millis() > next_gps_update) { diff --git a/variants/meshtracker_x1/target.h b/variants/meshtracker_x1/target.h index 665f43281..9741efb6a 100644 --- a/variants/meshtracker_x1/target.h +++ b/variants/meshtracker_x1/target.h @@ -8,12 +8,15 @@ #include #include #include +#include #ifdef DISPLAY_CLASS #include "NullDisplayDriver.h" #endif class MeshTrackerX1SensorManager: public SensorManager { bool gps_active = false; + bool baro_ok = false; + Adafruit_SPA06_003 spa06; LocationProvider * _nmea; void start_gps(); diff --git a/variants/meshtracker_x1/variant.cpp b/variants/meshtracker_x1/variant.cpp index a0e643801..5a685a8ef 100644 --- a/variants/meshtracker_x1/variant.cpp +++ b/variants/meshtracker_x1/variant.cpp @@ -62,7 +62,8 @@ const uint32_t g_ADigitalPinMap[PINS_COUNT + 1] = void initVariant() { pinMode(BATTERY_PIN, INPUT); - pinMode(EXT_CHRG_DETECT, INPUT); + pinMode(EXT_CHRG_DETECT, INPUT_PULLUP); + pinMode(EXT_CHRG_DONE, INPUT_PULLUP); pinMode(EXT_PWR_DETECT, INPUT); pinMode(PIN_BUTTON1, INPUT_PULLDOWN); diff --git a/variants/meshtracker_x1/variant.h b/variants/meshtracker_x1/variant.h index 8e9bae8fa..c3dbd274f 100644 --- a/variants/meshtracker_x1/variant.h +++ b/variants/meshtracker_x1/variant.h @@ -25,6 +25,7 @@ #define ADC_MULTIPLIER (2.0F) #define EXT_CHRG_DETECT (35) // P1.3, LOW while charging +#define EXT_CHRG_DONE (36) // P1.4, LOW when charge complete #define EXT_PWR_DETECT (5) // P0.5 #define ADC_RESOLUTION (14)