Merge PowerSaving v16 updates

This commit is contained in:
mikecarper committed 2026-07-17 16:32:06 -07:00
commit 129e687c02
12 files changed
+172 -22

No files matched your search

+1
View File
@@ -522,6 +522,7 @@ protected:
#if ENV_INCLUDE_GPS == 1
void applyGpsPrefs() {
sensors.setPowerSavingEnabled(_prefs.powersaving_enabled != 0);
sensors.setSettingValue("gps", _prefs.gps_enabled?"1":"0");
}
#endif
+46 -10
View File
@@ -1958,7 +1958,12 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, char* command, char* re
if (_sensors->setSettingValue("gps", "1")) {
_prefs->gps_enabled = 1;
savePrefs();
strcpy(reply, "ok");
if (_prefs->powersaving_enabled) { // Power Saving
strcpy(reply, "on (powersaving)");
} else { // Normal mode
strcpy(reply, "ok");
}
} else {
strcpy(reply, "gps toggle not found");
}
@@ -1974,7 +1979,7 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, char* command, char* re
LocationProvider * l = _sensors->getLocationProvider();
if (l != NULL) {
l->syncTime();
strcpy(reply, "ok");
strcpy(reply, "scheduled");
} else {
strcpy(reply, "gps provider not found");
}
@@ -2019,14 +2024,42 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, char* command, char* re
bool enabled = l->isEnabled(); // is EN pin on ?
bool fix = l->isValid(); // has fix ?
int sats = l->satellitesCount();
bool active = !strcmp(_sensors->getSettingByKey("gps"), "1");
if (enabled) {
sprintf(reply, "on, %s, %s, %d sats",
active?"active":"deactivated",
fix?"fix":"no fix",
sats);
} else {
strcpy(reply, "off");
const char* gps_setting = _sensors->getSettingByKey("gps");
bool active = gps_setting != NULL && strcmp(gps_setting, "1") == 0;
if (_prefs->powersaving_enabled && l->getGPSPowerSaving()) { // GPS Power Saving
unsigned long now = millis();
unsigned long next_off = l->getNextGPSOff();
unsigned long deadline = next_off != 0 ? next_off : l->getNextGPSOn();
long remaining_ms = deadline == 0 ? 0 : (long)(deadline - now);
unsigned long mins = remaining_ms > 0 ? (unsigned long)remaining_ms / 60000UL : 0;
if (next_off != 0) {
snprintf(reply, 160, "on (powersaving, sleep in %luh %lum), %s, %s, %d sats",
mins / 60UL, mins % 60UL, active ? "active" : "deactivated",
fix ? "fix" : "no fix", sats);
} else {
snprintf(reply, 160, "off (powersaving, wake in %luh %lum)", mins / 60UL, mins % 60UL);
}
// "last sync" from GPS
unsigned long last_sync = l->getLastValidTimeSync();
size_t used = strlen(reply);
if (last_sync == 0) {
snprintf(reply + used, 160 - used, ", last sync: none");
} else {
DateTime dt = DateTime(last_sync);
snprintf(reply + used, 160 - used, ", last sync: %02d:%02d - %d/%d/%d UTC",
dt.hour(), dt.minute(), dt.day(), dt.month(), dt.year());
}
} else { // Normal mode
if (enabled) {
sprintf(reply, "on, %s, %s, %d sats",
active?"active":"deactivated",
fix?"fix":"no fix",
sats);
} else {
strcpy(reply, "off");
}
}
} else {
strcpy(reply, "Can't find GPS");
@@ -2038,6 +2071,7 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, char* command, char* re
strcpy(reply, "Error: USB serial connected");
} else {
_prefs->powersaving_enabled = 1;
_sensors->setPowerSavingEnabled(true);
savePrefs();
strcpy(reply, "on - Immediate effect");
}
@@ -2046,6 +2080,7 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, char* command, char* re
strcpy(reply, "Error: USB serial connected");
} else {
_prefs->powersaving_enabled = 1;
_sensors->setPowerSavingEnabled(true);
savePrefs();
strcpy(reply, "on - After 2 minutes");
}
@@ -2056,6 +2091,7 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, char* command, char* re
#endif
} else if (memcmp(command, "powersaving off", 15) == 0) {
_prefs->powersaving_enabled = 0;
_sensors->setPowerSavingEnabled(false);
savePrefs();
strcpy(reply, "off");
} else if (memcmp(command, "powersaving", 11) == 0) {
+3 -1
View File
@@ -55,8 +55,9 @@ protected:
public:
double node_lat, node_lon; // modify these, if you want to affect Advert location
double node_altitude; // altitude in meters
bool powersaving_enabled; // powersaving mode
SensorManager() { node_lat = 0; node_lon = 0; node_altitude = 0; }
SensorManager() { node_lat = 0; node_lon = 0; node_altitude = 0; powersaving_enabled = false; }
virtual bool i2c_probe(TwoWire& wire, uint8_t addr) { return false; }
virtual bool begin() { return false; }
virtual bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { return false; }
@@ -67,6 +68,7 @@ public:
virtual const char* getSettingValue(int i) const { return NULL; }
virtual bool setSettingValue(const char* name, const char* value) { return false; }
virtual LocationProvider* getLocationProvider() { return NULL; }
virtual void setPowerSavingEnabled(bool enabled) { powersaving_enabled = enabled; }
// Helper functions to manage setting by keys (useful in many places ...)
const char* getSettingByKey(const char* key) {
+15 -1
View File
@@ -1,3 +1,5 @@
#ifdef ETHERNET_ENABLED
#include "SerialEthernetInterface.h"
#include "EthernetMac.h"
#include <SPI.h>
@@ -116,7 +118,17 @@ size_t SerialEthernetInterface::writeFrame(const uint8_t src[], size_t len) {
}
bool SerialEthernetInterface::isWriteBusy() const {
return false;
return send_queue_len >= (FRAME_QUEUE_SIZE * 2 / 3);
}
bool SerialEthernetInterface::isReadBusy() const {
return _state != RECV_STATE_IDLE;
}
bool SerialEthernetInterface::hasPendingIO() const {
// The W5100S path is polled and has no wake interrupt. Keep servicing it
// while a client is connected or either direction has queued frame state.
return deviceConnected || send_queue_len > 0 || _state != RECV_STATE_IDLE;
}
size_t SerialEthernetInterface::checkRecvFrame(uint8_t dest[]) {
@@ -262,3 +274,5 @@ bool SerialEthernetInterface::isConnected() const {
void SerialEthernetInterface::loop() {
Ethernet.maintain();
}
#endif // ETHERNET_ENABLED
@@ -1,5 +1,7 @@
#pragma once
#ifdef ETHERNET_ENABLED
#include "helpers/BaseSerialInterface.h"
#include <SPI.h>
#include <RAK13800_W5100S.h>
@@ -7,6 +9,7 @@
#ifndef ETHERNET_TCP_PORT
#define ETHERNET_TCP_PORT 5000
#endif
// define ETHERNET_RAW_LINE=1 to use raw line-based CLI instead of framed packets
class SerialEthernetInterface : public BaseSerialInterface {
@@ -57,7 +60,9 @@ class SerialEthernetInterface : public BaseSerialInterface {
bool isEnabled() const override { return _isEnabled; }
bool isConnected() const override;
bool isReadBusy() const override;
bool isWriteBusy() const override;
bool hasPendingIO() const override;
size_t writeFrame(const uint8_t src[], size_t len) override;
size_t checkRecvFrame(uint8_t dest[]) override;
@@ -76,3 +81,5 @@ class SerialEthernetInterface : public BaseSerialInterface {
#define ETHERNET_DEBUG_PRINTLN(...) {}
#define ETHERNET_DEBUG_PRINT_IP(...) {}
#endif
#endif // ETHERNET_ENABLED
@@ -627,6 +627,18 @@ static const SensorDef SENSOR_TABLE[] = {
static const size_t SENSOR_TABLE_SIZE = (sizeof(SENSOR_TABLE) / sizeof(SENSOR_TABLE[0])) - 1;
// ============================================================
// Power Saving GPS
// ============================================================
#if ENV_INCLUDE_GPS
#ifndef GPS_POWERSAVING_ON_DURATION_SECS
#define GPS_POWERSAVING_ON_DURATION_SECS (10UL * 60UL)
#endif
#ifndef GPS_POWERSAVING_OFF_DURATION_SECS
#define GPS_POWERSAVING_OFF_DURATION_SECS (24UL * 60UL * 60UL)
#endif
#endif
// ============================================================
// begin() — scan the I2C bus, then initialize only what was
// found. A sensor whose address does not ACK during the scan
@@ -735,7 +747,13 @@ const char* EnvironmentSensorManager::getSettingValue(int i) const {
bool EnvironmentSensorManager::setSettingValue(const char* name, const char* value) {
#if ENV_INCLUDE_GPS
if (gps_detected && strcmp(name, "gps") == 0) {
setGpsTelemetryUserEnabled(strcmp(value, "0") != 0);
bool enabled = strcmp(value, "0") != 0;
bool was_active = gps_active;
_location->setGPSPowerSaving(enabled && powersaving_enabled);
setGpsTelemetryUserEnabled(enabled);
if (enabled && powersaving_enabled && was_active) {
armGpsPowerSavingCycle();
}
return true;
}
if (strcmp(name, "gps_interval") == 0) {
@@ -747,6 +765,29 @@ bool EnvironmentSensorManager::setSettingValue(const char* name, const char* val
return false; // not supported
}
void EnvironmentSensorManager::setPowerSavingEnabled(bool enabled) {
if (powersaving_enabled == enabled) return;
powersaving_enabled = enabled;
#if ENV_INCLUDE_GPS
if (!gps_detected) return;
bool gps_user_enabled = isGpsTelemetryUserEnabled();
_location->setGPSPowerSaving(enabled && gps_user_enabled);
if (!gps_user_enabled) return;
if (enabled) {
if (gps_active) {
armGpsPowerSavingCycle();
} else {
start_gps();
}
} else if (!gps_active) {
// Manual GPS-on means continuous operation when node power saving is off.
start_gps();
}
#endif
}
#if ENV_INCLUDE_GPS
void EnvironmentSensorManager::initBasicGPS() {
@@ -879,26 +920,42 @@ bool EnvironmentSensorManager::gpsIsAwake(uint8_t ioPin){
}
#endif
void EnvironmentSensorManager::armGpsPowerSavingCycle() {
if (!powersaving_enabled || !_location->getGPSPowerSaving()) return;
_location->syncTime();
_location->setNextGPSOn(0);
_location->setNextGPSOff(millis() + GPS_POWERSAVING_ON_DURATION_SECS * 1000UL);
}
void EnvironmentSensorManager::start_gps() {
if (gps_active) return;
gps_active = true;
#ifdef RAK_WISBLOCK_GPS
pinMode(gpsResetPin, OUTPUT);
digitalWrite(gpsResetPin, HIGH);
return;
#endif
pinMode(gpsResetPin, OUTPUT);
digitalWrite(gpsResetPin, HIGH);
#else
_location->begin();
_location->reset();
#ifndef PIN_GPS_EN
MESH_DEBUG_PRINTLN("Start GPS is N/A on this board. Actual GPS state unchanged");
#endif
#endif
armGpsPowerSavingCycle();
}
void EnvironmentSensorManager::stop_gps() {
if (!gps_active) return;
gps_active = false;
#ifdef RAK_WISBLOCK_GPS
if (powersaving_enabled && _location->getGPSPowerSaving()) {
_location->stopTimeSync();
_location->setNextGPSOff(0);
_location->setNextGPSOn(millis() + GPS_POWERSAVING_OFF_DURATION_SECS * 1000UL);
}
#ifdef RAK_WISBLOCK_GPS
pinMode(gpsResetPin, OUTPUT);
digitalWrite(gpsResetPin, LOW);
return;
@@ -920,11 +977,22 @@ void EnvironmentSensorManager::loop() {
unsigned long now = millis();
loopGpsTelemetry(now);
if (powersaving_enabled && gps_detected && _location->getGPSPowerSaving()) {
unsigned long next_off = _location->getNextGPSOff();
unsigned long next_on = _location->getNextGPSOn();
if (gps_active && ((next_off != 0 && (long)(now - next_off) >= 0)
|| !_location->waitingTimeSync())) {
stop_gps();
} else if (!gps_active && ((next_on != 0 && (long)(now - next_on) >= 0)
|| _location->waitingTimeSync())) {
start_gps();
}
}
if (gps_active) {
_location->loop();
}
if ((long)(now - next_gps_update) >= 0) {
if(gps_active){
#ifdef RAK_WISBLOCK_GPS
if ((i2cGPSFlag || serialGPSFlag) && _location->isValid()) {
@@ -951,6 +1019,7 @@ void EnvironmentSensorManager::loop() {
processGpsTelemetryFix(gps_lat, gps_lon, gps_altitude, now);
}
#endif
}
next_gps_update = now + (gps_update_interval_sec * 1000);
}
@@ -25,6 +25,7 @@ protected:
#if ENV_INCLUDE_GPS
LocationProvider* _location;
void armGpsPowerSavingCycle();
void start_gps();
void stop_gps();
bool telemetryGpsDetected() const override { return gps_detected; }
@@ -55,4 +56,5 @@ public:
const char* getSettingName(int i) const override;
const char* getSettingValue(int i) const override;
bool setSettingValue(const char* name, const char* value) override;
void setPowerSavingEnabled(bool enabled) override;
};
+12
View File
@@ -7,6 +7,10 @@ class LocationProvider {
protected:
bool _time_sync_needed = true;
bool _time_sync_applied = false;
bool _gps_powersaving_enabled = false;
unsigned long _next_gps_off = 0;
unsigned long _next_gps_on = 0;
unsigned long _last_valid_time_sync = 0;
void markTimeSyncApplied() { _time_sync_applied = true; }
@@ -20,6 +24,14 @@ public:
_time_sync_applied = false;
return applied;
}
virtual void stopTimeSync() { _time_sync_needed = false; }
virtual void setGPSPowerSaving(bool enabled) { _gps_powersaving_enabled = enabled; _next_gps_off = 0; _next_gps_on = 0; }
virtual bool getGPSPowerSaving() { return _gps_powersaving_enabled; }
virtual void setNextGPSOff(unsigned long _millis) { _next_gps_off = _millis; }
virtual unsigned long getNextGPSOff() { return _next_gps_off; }
virtual void setNextGPSOn(unsigned long _millis) { _next_gps_on = _millis; }
virtual unsigned long getNextGPSOn() { return _next_gps_on; }
virtual unsigned long getLastValidTimeSync() { return _last_valid_time_sync; }
virtual long getLatitude() = 0;
virtual long getLongitude() = 0;
virtual long getAltitude() = 0;
@@ -153,9 +153,10 @@ public :
markTimeSyncApplied();
_time_sync_needed = false;
_last_time_sync = millis();
_last_valid_time_sync = _clock->getCurrentTime();
}
}
if (isValid()) {
if (isValid() && satellitesCount() >= 5) {
time_valid ++;
}
}
+1
View File
@@ -1,4 +1,5 @@
#include "ST7735Display.h"
#include <TFT_eSPI.h>
//#include <Fonts/GFXFF/FreeSans9pt7b.h>
-1
View File
@@ -3,7 +3,6 @@
#include "DisplayDriver.h"
#include <Wire.h>
#include <SPI.h>
#include "TFT_eSPI.h"
#include <helpers/RefCountedDigitalPin.h>
class ST7735Display : public DisplayDriver {
+6
View File
@@ -36,6 +36,8 @@ build_flags =
-D ADMIN_PASSWORD='"password"'
-D MAX_NEIGHBOURS=50
-D DISPLAY_CLASS=SH1106Display
-D ENV_PIN_SDA=PIN_WIRE1_SDA
-D ENV_PIN_SCL=PIN_WIRE1_SCL
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
lib_deps = ${WioTrackerL1.lib_deps}
@@ -50,6 +52,8 @@ build_flags = ${WioTrackerL1.build_flags}
-D ADMIN_PASSWORD='"password"'
-D ROOM_PASSWORD='"hello"'
-D DISPLAY_CLASS=SH1106Display
-D ENV_PIN_SDA=PIN_WIRE1_SDA
-D ENV_PIN_SCL=PIN_WIRE1_SCL
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
lib_deps = ${WioTrackerL1.lib_deps}
@@ -68,6 +72,8 @@ build_flags = ${WioTrackerL1.build_flags}
-D OFFLINE_QUEUE_SIZE=256
-D PIN_BUZZER=12
-D QSPIFLASH=1
-D ENV_PIN_SDA=PIN_WIRE1_SDA
-D ENV_PIN_SCL=PIN_WIRE1_SCL
; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1
; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1
build_src_filter = ${WioTrackerL1.build_src_filter}