From faf043327d40e508a6f35fc1100bdb764dde5d66 Mon Sep 17 00:00:00 2001 From: Adam Mealings Date: Wed, 14 May 2025 21:46:39 +0100 Subject: [PATCH 01/41] RAK4631 analogue user button on input 31 --- examples/companion_radio/UITask.cpp | 68 +++++++++++++++++------------ src/helpers/nrf52/RAK4631Board.cpp | 3 ++ variants/rak4631/platformio.ini | 1 + 3 files changed, 43 insertions(+), 29 deletions(-) diff --git a/examples/companion_radio/UITask.cpp b/examples/companion_radio/UITask.cpp index e0c2ec51..6eae88c9 100644 --- a/examples/companion_radio/UITask.cpp +++ b/examples/companion_radio/UITask.cpp @@ -209,40 +209,50 @@ void UITask::userLedHandler() { } void UITask::buttonHandler() { -#ifdef PIN_USER_BTN - static int prev_btn_state = !USER_BTN_PRESSED; - static unsigned long btn_state_change_time = 0; - static unsigned long next_read = 0; - int cur_time = millis(); - if (cur_time >= next_read) { - int btn_state = digitalRead(PIN_USER_BTN); - if (btn_state != prev_btn_state) { - if (btn_state == USER_BTN_PRESSED) { // pressed? - if (_display != NULL) { - if (_display->isOn()) { - clearMsgPreview(); - } else { - _display->turnOn(); - _need_refresh = true; + #ifdef PIN_USER_BTN || PIN_USER_BTN_ANA + static int prev_btn_state = !USER_BTN_PRESSED; + static int prev_btn_state_ana = !USER_BTN_PRESSED; + static unsigned long btn_state_change_time = 0; + static unsigned long next_read = 0; + int cur_time = millis(); + if (cur_time >= next_read) { + int btn_state = 0; + int btn_state_ana = 0; + #ifdef PIN_USER_BTN + btn_state = digitalRead(PIN_USER_BTN); + #endif + #ifdef PIN_USER_BTN_ANA + btn_state_ana = (analogRead(PIN_USER_BTN_ANA) < 20); // analogRead returns a value hopefully below 20 when button is pressed. + #endif + //Serial.println(analogRead(PIN_USER_BTN_ANA)); + if (btn_state != prev_btn_state || btn_state_ana != prev_btn_state_ana) { // check for either digital or analogue button change of state + if (btn_state == USER_BTN_PRESSED || btn_state_ana == USER_BTN_PRESSED) { // pressed? + if (_display != NULL) { + if (_display->isOn()) { + clearMsgPreview(); + } else { + _display->turnOn(); + _need_refresh = true; + } + _auto_off = cur_time + AUTO_OFF_MILLIS; // extend auto-off timer + } + } else { // unpressed ? check pressed time ... + if ((cur_time - btn_state_change_time) > 5000) { + #ifdef PIN_STATUS_LED + digitalWrite(PIN_STATUS_LED, LOW); + delay(10); + #endif + _board->powerOff(); } - _auto_off = cur_time + AUTO_OFF_MILLIS; // extend auto-off timer - } - } else { // unpressed ? check pressed time ... - if ((cur_time - btn_state_change_time) > 5000) { - #ifdef PIN_STATUS_LED - digitalWrite(PIN_STATUS_LED, LOW); - delay(10); - #endif - _board->powerOff(); } + btn_state_change_time = millis(); + prev_btn_state = btn_state; + prev_btn_state_ana = btn_state_ana; } - btn_state_change_time = millis(); - prev_btn_state = btn_state; + next_read = millis() + 100; // 10 reads per second } - next_read = millis() + 100; // 10 reads per second + #endif } -#endif -} void UITask::loop() { buttonHandler(); diff --git a/src/helpers/nrf52/RAK4631Board.cpp b/src/helpers/nrf52/RAK4631Board.cpp index 8b368734..6deed5b4 100644 --- a/src/helpers/nrf52/RAK4631Board.cpp +++ b/src/helpers/nrf52/RAK4631Board.cpp @@ -25,6 +25,9 @@ void RAK4631Board::begin() { #ifdef PIN_USER_BTN pinMode(PIN_USER_BTN, INPUT_PULLUP); #endif +#ifdef PIN_USER_BTN_ANA + pinMode(PIN_USER_BTN_ANA, INPUT_PULLUP); +#endif #if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL) Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL); diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini index 85f59bfa..af1eb3d4 100644 --- a/variants/rak4631/platformio.ini +++ b/variants/rak4631/platformio.ini @@ -7,6 +7,7 @@ build_flags = ${nrf52840_base.build_flags} -I variants/rak4631 -D RAK_4631 -D PIN_USER_BTN=9 + -D PIN_USER_BTN_ANA=31 -D PIN_BOARD_SCL=14 -D PIN_BOARD_SDA=13 -D PIN_OLED_RESET=-1 From f1df9f7c3b5ad3d118e5001bc4bafab72a408be9 Mon Sep 17 00:00:00 2001 From: adam2872 <53094349+adam2872@users.noreply.github.com> Date: Wed, 14 May 2025 22:04:28 +0100 Subject: [PATCH 02/41] Revert "RAK4631 analogue user button on input 31" --- examples/companion_radio/UITask.cpp | 68 ++++++++++++----------------- src/helpers/nrf52/RAK4631Board.cpp | 3 -- variants/rak4631/platformio.ini | 1 - 3 files changed, 29 insertions(+), 43 deletions(-) diff --git a/examples/companion_radio/UITask.cpp b/examples/companion_radio/UITask.cpp index 6eae88c9..e0c2ec51 100644 --- a/examples/companion_radio/UITask.cpp +++ b/examples/companion_radio/UITask.cpp @@ -209,50 +209,40 @@ void UITask::userLedHandler() { } void UITask::buttonHandler() { - #ifdef PIN_USER_BTN || PIN_USER_BTN_ANA - static int prev_btn_state = !USER_BTN_PRESSED; - static int prev_btn_state_ana = !USER_BTN_PRESSED; - static unsigned long btn_state_change_time = 0; - static unsigned long next_read = 0; - int cur_time = millis(); - if (cur_time >= next_read) { - int btn_state = 0; - int btn_state_ana = 0; - #ifdef PIN_USER_BTN - btn_state = digitalRead(PIN_USER_BTN); - #endif - #ifdef PIN_USER_BTN_ANA - btn_state_ana = (analogRead(PIN_USER_BTN_ANA) < 20); // analogRead returns a value hopefully below 20 when button is pressed. - #endif - //Serial.println(analogRead(PIN_USER_BTN_ANA)); - if (btn_state != prev_btn_state || btn_state_ana != prev_btn_state_ana) { // check for either digital or analogue button change of state - if (btn_state == USER_BTN_PRESSED || btn_state_ana == USER_BTN_PRESSED) { // pressed? - if (_display != NULL) { - if (_display->isOn()) { - clearMsgPreview(); - } else { - _display->turnOn(); - _need_refresh = true; - } - _auto_off = cur_time + AUTO_OFF_MILLIS; // extend auto-off timer - } - } else { // unpressed ? check pressed time ... - if ((cur_time - btn_state_change_time) > 5000) { - #ifdef PIN_STATUS_LED - digitalWrite(PIN_STATUS_LED, LOW); - delay(10); - #endif - _board->powerOff(); +#ifdef PIN_USER_BTN + static int prev_btn_state = !USER_BTN_PRESSED; + static unsigned long btn_state_change_time = 0; + static unsigned long next_read = 0; + int cur_time = millis(); + if (cur_time >= next_read) { + int btn_state = digitalRead(PIN_USER_BTN); + if (btn_state != prev_btn_state) { + if (btn_state == USER_BTN_PRESSED) { // pressed? + if (_display != NULL) { + if (_display->isOn()) { + clearMsgPreview(); + } else { + _display->turnOn(); + _need_refresh = true; } + _auto_off = cur_time + AUTO_OFF_MILLIS; // extend auto-off timer + } + } else { // unpressed ? check pressed time ... + if ((cur_time - btn_state_change_time) > 5000) { + #ifdef PIN_STATUS_LED + digitalWrite(PIN_STATUS_LED, LOW); + delay(10); + #endif + _board->powerOff(); } - btn_state_change_time = millis(); - prev_btn_state = btn_state; - prev_btn_state_ana = btn_state_ana; } - next_read = millis() + 100; // 10 reads per second + btn_state_change_time = millis(); + prev_btn_state = btn_state; } - #endif + next_read = millis() + 100; // 10 reads per second } +#endif +} void UITask::loop() { buttonHandler(); diff --git a/src/helpers/nrf52/RAK4631Board.cpp b/src/helpers/nrf52/RAK4631Board.cpp index 6deed5b4..8b368734 100644 --- a/src/helpers/nrf52/RAK4631Board.cpp +++ b/src/helpers/nrf52/RAK4631Board.cpp @@ -25,9 +25,6 @@ void RAK4631Board::begin() { #ifdef PIN_USER_BTN pinMode(PIN_USER_BTN, INPUT_PULLUP); #endif -#ifdef PIN_USER_BTN_ANA - pinMode(PIN_USER_BTN_ANA, INPUT_PULLUP); -#endif #if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL) Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL); diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini index af1eb3d4..85f59bfa 100644 --- a/variants/rak4631/platformio.ini +++ b/variants/rak4631/platformio.ini @@ -7,7 +7,6 @@ build_flags = ${nrf52840_base.build_flags} -I variants/rak4631 -D RAK_4631 -D PIN_USER_BTN=9 - -D PIN_USER_BTN_ANA=31 -D PIN_BOARD_SCL=14 -D PIN_BOARD_SDA=13 -D PIN_OLED_RESET=-1 From 8a27743e43ba40eb13d2fd6ed9b5f91598d09402 Mon Sep 17 00:00:00 2001 From: Normunds Gavars Date: Mon, 19 May 2025 17:24:54 +0300 Subject: [PATCH 03/41] Create sensor classes that can be shared across variants --- src/helpers/sensors/AHTX0Sensor.h | 39 ++++++ .../sensors/EnvironmentSensorManager.cpp | 67 ++++++++++ .../sensors/EnvironmentSensorManager.h | 30 +++++ src/helpers/sensors/INA219Sensor.h | 48 +++++++ src/helpers/sensors/INA3221Sensor.h | 71 +++++++++++ variants/promicro/platformio.ini | 1 + variants/promicro/target.cpp | 119 +----------------- variants/promicro/target.h | 41 +----- 8 files changed, 259 insertions(+), 157 deletions(-) create mode 100644 src/helpers/sensors/AHTX0Sensor.h create mode 100644 src/helpers/sensors/EnvironmentSensorManager.cpp create mode 100644 src/helpers/sensors/EnvironmentSensorManager.h create mode 100644 src/helpers/sensors/INA219Sensor.h create mode 100644 src/helpers/sensors/INA3221Sensor.h diff --git a/src/helpers/sensors/AHTX0Sensor.h b/src/helpers/sensors/AHTX0Sensor.h new file mode 100644 index 00000000..04af3057 --- /dev/null +++ b/src/helpers/sensors/AHTX0Sensor.h @@ -0,0 +1,39 @@ +#pragma once +#include +#include + +#define TELEM_AHTX_ADDRESS 0x38 // AHT10, AHT20 temperature and humidity sensor I2C address + +static Adafruit_AHTX0 AHTX0; + +class AHTX0Sensor { + bool initialized = false; +public: + void begin() { + if (AHTX0.begin(&Wire, 0, TELEM_AHTX_ADDRESS)) { + MESH_DEBUG_PRINTLN("Found AHT10/AHT20 at address: %02X", TELEM_AHTX_ADDRESS); + initialized = true; + } else { + initialized = false; + MESH_DEBUG_PRINTLN("AHT10/AHT20 was not found at I2C address %02X", TELEM_AHTX_ADDRESS); + } + } + + bool isInitialized() const { return initialized; }; + + float getRelativeHumidity() const { + if (initialized) { + sensors_event_t humidity, temp; + AHTX0.getEvent(&humidity, &temp); + return humidity.relative_humidity; + } + } + + float getTemperature() const { + if (initialized) { + sensors_event_t humidity, temp; + AHTX0.getEvent(&humidity, &temp); + return temp.temperature; + } + } +}; diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp new file mode 100644 index 00000000..b0497471 --- /dev/null +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -0,0 +1,67 @@ +#include "EnvironmentSensorManager.h" + +bool EnvironmentSensorManager::begin() { + INA3221_sensor.begin(); + INA219_sensor.begin(); + AHTX0_sensor.begin(); + + return true; +} + +bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { + next_available_channel = TELEM_CHANNEL_SELF + 1; + if (requester_permissions & TELEM_PERM_ENVIRONMENT) { + if (INA3221_sensor.isInitialized()) { + for(int i = 0; i < 3; i++) { + // add only enabled INA3221 channels to telemetry + if (INA3221_sensor.getChannelEnabled(i)) { + telemetry.addVoltage(next_available_channel, INA3221_sensor.getVoltage(i)); + telemetry.addCurrent(next_available_channel, INA3221_sensor.getCurrent(i)); + telemetry.addPower(next_available_channel, INA3221_sensor.getPower(i)); + next_available_channel++; + } + } + } + if (INA219_sensor.isInitialized()) { + telemetry.addVoltage(next_available_channel, INA219_sensor.getVoltage()); + telemetry.addCurrent(next_available_channel, INA219_sensor.getCurrent()); + telemetry.addPower(next_available_channel, INA219_sensor.getPower()); + next_available_channel++; + } + if (AHTX0_sensor.isInitialized()) { + telemetry.addTemperature(TELEM_CHANNEL_SELF, AHTX0_sensor.getTemperature()); + telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, AHTX0_sensor.getRelativeHumidity()); + } + } + + return true; +} + +int EnvironmentSensorManager::getNumSettings() const { + return NUM_SENSOR_SETTINGS; +} + +const char* EnvironmentSensorManager::getSettingName(int i) const { + if (i >= 0 && i < NUM_SENSOR_SETTINGS) { + return INA3221_CHANNEL_NAMES[i]; + } + return NULL; +} + +const char* EnvironmentSensorManager::getSettingValue(int i) const { + if (i >= 0 && i < NUM_SENSOR_SETTINGS) { + return INA3221_sensor.getChannelEnabled(i) == true ? "1" : "0"; + } + return NULL; +} + +bool EnvironmentSensorManager::setSettingValue(const char* name, const char* value) { + for (int i = 0; i < NUM_SENSOR_SETTINGS; i++) { + if (strcmp(name, INA3221_CHANNEL_NAMES[i]) == 0) { + bool channel_enabled = strcmp(value, "1") == 0 ? true : false; + INA3221_sensor.setChannelEnabled(i, channel_enabled); + return true; + } + } + return false; +} \ No newline at end of file diff --git a/src/helpers/sensors/EnvironmentSensorManager.h b/src/helpers/sensors/EnvironmentSensorManager.h new file mode 100644 index 00000000..95a7476b --- /dev/null +++ b/src/helpers/sensors/EnvironmentSensorManager.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include "INA3221Sensor.h" +#include "INA219Sensor.h" +#include "AHTX0Sensor.h" + +#define NUM_SENSOR_SETTINGS 3 +#define TELEM_INA3221_SETTING_CH1 "INA3221-1" +#define TELEM_INA3221_SETTING_CH2 "INA3221-2" +#define TELEM_INA3221_SETTING_CH3 "INA3221-3" + +class EnvironmentSensorManager : public SensorManager { +// INA3221 channels in telemetry +const char * INA3221_CHANNEL_NAMES[NUM_SENSOR_SETTINGS] = { TELEM_INA3221_SETTING_CH1, TELEM_INA3221_SETTING_CH2, TELEM_INA3221_SETTING_CH3}; + +protected: + int next_available_channel = TELEM_CHANNEL_SELF + 1; + INA3221Sensor INA3221_sensor; + AHTX0Sensor AHTX0_sensor; + INA219Sensor INA219_sensor; +public: + EnvironmentSensorManager(){}; + bool begin() override; + bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override; + int getNumSettings() const override; + const char* getSettingName(int i) const override; + const char* getSettingValue(int i) const override; + bool setSettingValue(const char* name, const char* value) override; +}; diff --git a/src/helpers/sensors/INA219Sensor.h b/src/helpers/sensors/INA219Sensor.h new file mode 100644 index 00000000..1f641ab2 --- /dev/null +++ b/src/helpers/sensors/INA219Sensor.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include + +#define TELEM_INA219_ADDRESS 0x40 // INA219 single channel current sensor I2C address +#define TELEM_INA219_SHUNT_VALUE 0.100 // shunt value in ohms (may differ between manufacturers) +#define TELEM_INA219_MAX_CURRENT 5 + +static INA219 INA_219(TELEM_INA219_ADDRESS, &Wire); + +class INA219Sensor { + bool initialized = false; +public: + void begin() { + if (INA_219.begin()) { + MESH_DEBUG_PRINTLN("Found INA219 at address: %02X", INA_219.getAddress()); + INA_219.setMaxCurrentShunt(TELEM_INA219_MAX_CURRENT, TELEM_INA219_SHUNT_VALUE); + initialized = true; + } else { + initialized = false; + MESH_DEBUG_PRINTLN("INA219 was not found at I2C address %02X", TELEM_INA219_ADDRESS); + } + } + + bool isInitialized() const { return initialized; } + + float getVoltage() const { + if (initialized) { + return INA_219.getBusVoltage(); + } + return 0; + } + + float getCurrent() const { + if (initialized) { + return INA_219.getCurrent(); + } + return 0; + } + + float getPower() const { + if (initialized) { + return INA_219.getPower(); + } + return 0; + } +}; diff --git a/src/helpers/sensors/INA3221Sensor.h b/src/helpers/sensors/INA3221Sensor.h new file mode 100644 index 00000000..f3618a9f --- /dev/null +++ b/src/helpers/sensors/INA3221Sensor.h @@ -0,0 +1,71 @@ +#pragma once + +#include +#include + +#define TELEM_INA3221_ADDRESS 0x42 // INA3221 3 channel current sensor I2C address +#define TELEM_INA3221_SHUNT_VALUE 0.100 // most variants will have a 0.1 ohm shunts + +#define NUM_CHANNELS 3 + +static INA3221 INA_3221(TELEM_INA3221_ADDRESS, &Wire); + +class INA3221Sensor { + bool initialized = false; + +public: + void begin() { + if (INA_3221.begin()) { + MESH_DEBUG_PRINTLN("Found INA3221 at address: %02X", INA_3221.getAddress()); + MESH_DEBUG_PRINTLN("%04X %04X %04X", INA_3221.getDieID(), INA_3221.getManufacturerID(), INA_3221.getConfiguration()); + + for(int i = 0; i < 3; i++) { + INA_3221.setShuntR(i, TELEM_INA3221_SHUNT_VALUE); + } + initialized = true; + } else { + initialized = false; + MESH_DEBUG_PRINTLN("INA3221 was not found at I2C address %02X", TELEM_INA3221_ADDRESS); + } + } + + bool isInitialized() const { return initialized; } + + int numChannels() const { return NUM_CHANNELS; } + + float getVoltage(int channel) const { + if (initialized && channel >=0 && channel < NUM_CHANNELS) { + return INA_3221.getBusVoltage(channel); + } + return 0; + } + + float getCurrent(int channel) const { + if (initialized && channel >=0 && channel < NUM_CHANNELS) { + return INA_3221.getCurrent(channel); + } + return 0; + } + + float getPower (int channel) const { + if (initialized && channel >=0 && channel < NUM_CHANNELS) { + return INA_3221.getPower(channel); + } + return 0; + } + + bool setChannelEnabled(int channel, bool enabled) { + if (initialized && channel >=0 && channel < NUM_CHANNELS) { + INA_3221.enableChannel(channel); + return true; + } + return false; + } + + bool getChannelEnabled(int channel) const { + if (initialized && channel >=0 && channel < NUM_CHANNELS) { + return INA_3221.getEnableChannel(channel); + } + return false; + } +}; diff --git a/variants/promicro/platformio.ini b/variants/promicro/platformio.ini index 51fbc92f..8cabf6e6 100644 --- a/variants/promicro/platformio.ini +++ b/variants/promicro/platformio.ini @@ -15,6 +15,7 @@ build_flags = ${nrf52840_base.build_flags} -D PIN_USER_BTN=6 build_src_filter = ${nrf52840_base.build_src_filter} + + + +<../variants/promicro> lib_deps= ${nrf52840_base.lib_deps} adafruit/Adafruit SSD1306 @ ^2.5.13 diff --git a/variants/promicro/target.cpp b/variants/promicro/target.cpp index 6e3dc938..841bd1dc 100644 --- a/variants/promicro/target.cpp +++ b/variants/promicro/target.cpp @@ -10,7 +10,7 @@ WRAPPER_CLASS radio_driver(radio, board); VolatileRTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); -PromicroSensorManager sensors; +EnvironmentSensorManager sensors; #ifdef DISPLAY_CLASS DISPLAY_CLASS display; @@ -79,120 +79,3 @@ mesh::LocalIdentity radio_new_identity() { return mesh::LocalIdentity(&rng); // create new random identity } -static INA3221 INA_3221(TELEM_INA3221_ADDRESS, &Wire); -static INA219 INA_219(TELEM_INA219_ADDRESS, &Wire); -static Adafruit_AHTX0 AHTX; - -bool PromicroSensorManager::begin() { - initINA3221(); - initINA219(); - initAHTX(); - - return true; -} - -bool PromicroSensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { - int nextAvalableChannel = TELEM_CHANNEL_SELF + 1; - if (requester_permissions & TELEM_PERM_ENVIRONMENT) { - if (INA3221initialized) { - for(int i = 0; i < 3; i++) { - // add only enabled INA3221 channels to telemetry - if (INA3221_CHANNEL_ENABLED[i]) { - telemetry.addVoltage(nextAvalableChannel, INA_3221.getBusVoltage(i)); - telemetry.addCurrent(nextAvalableChannel, INA_3221.getCurrent(i)); - telemetry.addPower(nextAvalableChannel, INA_3221.getPower(i)); - nextAvalableChannel++; - } - } - } - if (INA219initialized) { - telemetry.addVoltage(nextAvalableChannel, INA_219.getBusVoltage()); - telemetry.addCurrent(nextAvalableChannel, INA_219.getCurrent()); - telemetry.addPower(nextAvalableChannel, INA_219.getPower()); - nextAvalableChannel++; - } - if (AHTXinitialized) { - sensors_event_t humidity, temp; - AHTX.getEvent(&humidity, &temp); - telemetry.addTemperature(TELEM_CHANNEL_SELF, temp.temperature); - telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, humidity.relative_humidity); - } - } - - return true; -} - -int PromicroSensorManager::getNumSettings() const { - return NUM_SENSOR_SETTINGS; -} - -const char* PromicroSensorManager::getSettingName(int i) const { - if (i >= 0 && i < NUM_SENSOR_SETTINGS) { - return INA3221_CHANNEL_NAMES[i]; - } - return NULL; -} - -const char* PromicroSensorManager::getSettingValue(int i) const { - if (i >= 0 && i < NUM_SENSOR_SETTINGS) { - return INA3221_CHANNEL_ENABLED[i] ? "1" : "0"; - } - return NULL; -} - -bool PromicroSensorManager::setSettingValue(const char* name, const char* value) { - for (int i = 0; i < NUM_SENSOR_SETTINGS; i++) { - if (strcmp(name, INA3221_CHANNEL_NAMES[i]) == 0) { - int channelEnabled = INA_3221.getEnableChannel(i); - if (strcmp(value, "1") == 0) { - INA3221_CHANNEL_ENABLED[i] = true; - if (!channelEnabled) { - INA_3221.enableChannel(i); - } - } else { - INA3221_CHANNEL_ENABLED[i] = false; - if (channelEnabled) { - INA_3221.disableChannel(i); - } - } - return true; - } - } - return false; -} - -void PromicroSensorManager::initINA3221() { - if (INA_3221.begin()) { - MESH_DEBUG_PRINTLN("Found INA3221 at address: %02X", INA_3221.getAddress()); - MESH_DEBUG_PRINTLN("%04X %04X %04X", INA_3221.getDieID(), INA_3221.getManufacturerID(), INA_3221.getConfiguration()); - - for(int i = 0; i < 3; i++) { - INA_3221.setShuntR(i, TELEM_INA3221_SHUNT_VALUE); - } - INA3221initialized = true; - } else { - INA3221initialized = false; - MESH_DEBUG_PRINTLN("INA3221 was not found at I2C address %02X", TELEM_INA3221_ADDRESS); - } -} - -void PromicroSensorManager::initINA219() { - if (INA_219.begin()) { - MESH_DEBUG_PRINTLN("Found INA219 at address: %02X", INA_219.getAddress()); - INA_219.setMaxCurrentShunt(TELEM_INA219_MAX_CURRENT, TELEM_INA219_SHUNT_VALUE); - INA219initialized = true; - } else { - INA219initialized = false; - MESH_DEBUG_PRINTLN("INA219 was not found at I2C address %02X", TELEM_INA219_ADDRESS); - } -} - -void PromicroSensorManager::initAHTX() { - if (AHTX.begin(&Wire, 0, TELEM_AHTX_ADDRESS)) { - MESH_DEBUG_PRINTLN("Found AHT10/AHT20 at address: %02X", TELEM_AHTX_ADDRESS); - AHTXinitialized = true; - } else { - AHTXinitialized = false; - MESH_DEBUG_PRINTLN("AHT10/AHT20 was not found at I2C address %02X", TELEM_AHTX_ADDRESS); - } -} diff --git a/variants/promicro/target.h b/variants/promicro/target.h index b7475b4a..c289d744 100644 --- a/variants/promicro/target.h +++ b/variants/promicro/target.h @@ -8,14 +8,12 @@ #include #include #include -#include -#include -#include #ifdef DISPLAY_CLASS #include #endif #define NUM_SENSOR_SETTINGS 3 +#include extern PromicroBoard board; extern WRAPPER_CLASS radio_driver; @@ -31,39 +29,4 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); void radio_set_tx_power(uint8_t dbm); mesh::LocalIdentity radio_new_identity(); -#define TELEM_INA3221_ADDRESS 0x42 // INA3221 3 channel current sensor I2C address -#define TELEM_INA219_ADDRESS 0x40 // INA219 single channel current sensor I2C address -#define TELEM_AHTX_ADDRESS 0x38 // AHT10, AHT20 temperature and humidity sensor I2C address - -#define TELEM_INA3221_SHUNT_VALUE 0.100 // most variants will have a 0.1 ohm shunts -#define TELEM_INA3221_SETTING_CH1 "INA3221-1" -#define TELEM_INA3221_SETTING_CH2 "INA3221-2" -#define TELEM_INA3221_SETTING_CH3 "INA3221-3" - -#define TELEM_INA219_SHUNT_VALUE 0.100 // shunt value in ohms (may differ between manufacturers) -#define TELEM_INA219_MAX_CURRENT 5 - -class PromicroSensorManager: public SensorManager { - bool INA3221initialized = false; - bool INA219initialized = false; - bool AHTXinitialized = false; - - // INA3221 channels in telemetry - const char * INA3221_CHANNEL_NAMES[NUM_SENSOR_SETTINGS] = { TELEM_INA3221_SETTING_CH1, TELEM_INA3221_SETTING_CH2, TELEM_INA3221_SETTING_CH3}; - bool INA3221_CHANNEL_ENABLED[NUM_SENSOR_SETTINGS] = {true, true, true}; - - void initINA3221(); - void initINA219(); - void initAHTX(); -public: - PromicroSensorManager(){}; - bool begin() override; - bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override; - int getNumSettings() const override; - const char* getSettingName(int i) const override; - const char* getSettingValue(int i) const override; - bool setSettingValue(const char* name, const char* value) override; -}; - - -extern PromicroSensorManager sensors; \ No newline at end of file +extern EnvironmentSensorManager sensors; \ No newline at end of file From 3cf78a952ba9e23bbfb05706bb17f318879c7c1c Mon Sep 17 00:00:00 2001 From: Normunds Gavars Date: Mon, 19 May 2025 19:37:30 +0300 Subject: [PATCH 04/41] Telemetry: Create BME280 sensor that can bu used across variants. Add to promicro. --- src/helpers/sensors/BME280Sensor.h | 55 +++++++++++++++++++ .../sensors/EnvironmentSensorManager.cpp | 7 +++ .../sensors/EnvironmentSensorManager.h | 2 + variants/promicro/platformio.ini | 1 + 4 files changed, 65 insertions(+) create mode 100644 src/helpers/sensors/BME280Sensor.h diff --git a/src/helpers/sensors/BME280Sensor.h b/src/helpers/sensors/BME280Sensor.h new file mode 100644 index 00000000..1226fce5 --- /dev/null +++ b/src/helpers/sensors/BME280Sensor.h @@ -0,0 +1,55 @@ +#pragma once +#include +#include + +#define TELEM_BME280_ADDRESS 0x76 // BME280 environmental sensor I2C address +#define SEALEVELPRESSURE_HPA (1013.25) // Athmospheric pressure at sea level + +static Adafruit_BME280 BME280; + +class BME280Sensor { + bool initialized = false; +public: + void begin() { + if (BME280.begin(TELEM_BME280_ADDRESS, &Wire)) { + MESH_DEBUG_PRINTLN("Found BME280 at address: %02X", TELEM_BME280_ADDRESS); + MESH_DEBUG_PRINTLN("BME sensor ID: %02X", BME280.sensorID); + initialized = true; + } else { + initialized = false; + MESH_DEBUG_PRINTLN("BME280 was not found at I2C address %02X", TELEM_BME280_ADDRESS); + } + } + + bool isInitialized() const { return initialized; }; + + float getRelativeHumidity() const { + if (initialized) { + return BME280.readHumidity();; + } + } + + float getTemperature() const { + if (initialized) { + return BME280.readTemperature();; + } + } + + float getBarometricPressure() const { + if (initialized) { + return BME280.readPressure(); + } + } + + float getAltitude() const { + if (initialized) { + return BME280.readAltitude(SEALEVELPRESSURE_HPA); + } + } + + void setTemperatureCompensation(float delta) { + if (initialized) { + BME280.setTemperatureCompensation(delta); + } + } +}; diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp index b0497471..cf931470 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.cpp +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -4,6 +4,7 @@ bool EnvironmentSensorManager::begin() { INA3221_sensor.begin(); INA219_sensor.begin(); AHTX0_sensor.begin(); + BME280_sensor.begin(); return true; } @@ -32,6 +33,12 @@ bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, Cayen telemetry.addTemperature(TELEM_CHANNEL_SELF, AHTX0_sensor.getTemperature()); telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, AHTX0_sensor.getRelativeHumidity()); } + if (BME280_sensor.isInitialized()) { + telemetry.addTemperature(TELEM_CHANNEL_SELF, BME280_sensor.getTemperature()); + telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, BME280_sensor.getRelativeHumidity()); + telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, BME280_sensor.getBarometricPressure()); + telemetry.addAltitude(TELEM_CHANNEL_SELF, BME280_sensor.getAltitude()); + } } return true; diff --git a/src/helpers/sensors/EnvironmentSensorManager.h b/src/helpers/sensors/EnvironmentSensorManager.h index 95a7476b..6d02f9fc 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.h +++ b/src/helpers/sensors/EnvironmentSensorManager.h @@ -4,6 +4,7 @@ #include "INA3221Sensor.h" #include "INA219Sensor.h" #include "AHTX0Sensor.h" +#include "BME280Sensor.h" #define NUM_SENSOR_SETTINGS 3 #define TELEM_INA3221_SETTING_CH1 "INA3221-1" @@ -19,6 +20,7 @@ protected: INA3221Sensor INA3221_sensor; AHTX0Sensor AHTX0_sensor; INA219Sensor INA219_sensor; + BME280Sensor BME280_sensor; public: EnvironmentSensorManager(){}; bool begin() override; diff --git a/variants/promicro/platformio.ini b/variants/promicro/platformio.ini index 8cabf6e6..7b6771e0 100644 --- a/variants/promicro/platformio.ini +++ b/variants/promicro/platformio.ini @@ -22,6 +22,7 @@ lib_deps= ${nrf52840_base.lib_deps} robtillaart/INA3221 @ ^0.4.1 robtillaart/INA219 @ ^0.4.1 adafruit/Adafruit AHTX0@^2.0.5 + adafruit/Adafruit BME280 Library@^2.3.0 [env:Faketec_Repeater] extends = Faketec From 5d9e7b4567b216f9a6f4c0926ce5c1b000d5b20e Mon Sep 17 00:00:00 2001 From: Normunds Gavars Date: Mon, 19 May 2025 20:30:58 +0300 Subject: [PATCH 05/41] Remove unnecessary include --- src/helpers/sensors/EnvironmentSensorManager.h | 1 + variants/promicro/target.h | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/helpers/sensors/EnvironmentSensorManager.h b/src/helpers/sensors/EnvironmentSensorManager.h index 6d02f9fc..318de001 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.h +++ b/src/helpers/sensors/EnvironmentSensorManager.h @@ -7,6 +7,7 @@ #include "BME280Sensor.h" #define NUM_SENSOR_SETTINGS 3 + #define TELEM_INA3221_SETTING_CH1 "INA3221-1" #define TELEM_INA3221_SETTING_CH2 "INA3221-2" #define TELEM_INA3221_SETTING_CH3 "INA3221-3" diff --git a/variants/promicro/target.h b/variants/promicro/target.h index c289d744..c634d18a 100644 --- a/variants/promicro/target.h +++ b/variants/promicro/target.h @@ -7,17 +7,16 @@ #include #include #include -#include #ifdef DISPLAY_CLASS #include #endif -#define NUM_SENSOR_SETTINGS 3 #include extern PromicroBoard board; extern WRAPPER_CLASS radio_driver; extern AutoDiscoverRTCClock rtc_clock; +extern EnvironmentSensorManager sensors; #ifdef DISPLAY_CLASS extern DISPLAY_CLASS display; @@ -29,4 +28,3 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); void radio_set_tx_power(uint8_t dbm); mesh::LocalIdentity radio_new_identity(); -extern EnvironmentSensorManager sensors; \ No newline at end of file From fd3781002251aa1ef9cd99a4f0883aa160059474 Mon Sep 17 00:00:00 2001 From: cod3doomy Date: Mon, 19 May 2025 12:55:56 -0700 Subject: [PATCH 06/41] t-beam supreme: display fix, BME add, user btn fix -Fixed build issues after display refactor -Added BME280 support and updated SensorManager to include this data -Fixed user button and verified it turns the display on --- .gitignore | 1 + src/helpers/SensorManager.h | 4 +- src/helpers/TBeamS3SupremeBoard.h | 4 +- .../platformio.ini | 7 +- .../lilygo_tbeam_supreme_SX1262/target.cpp | 78 +++++++++++++++++-- variants/lilygo_tbeam_supreme_SX1262/target.h | 5 ++ 6 files changed, 89 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 51449c2d..7ca9335a 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ out/ .direnv/ .DS_Store .vscode/settings.json +.vscode/extensions.json diff --git a/src/helpers/SensorManager.h b/src/helpers/SensorManager.h index 0e4bc27d..f48c2a7b 100644 --- a/src/helpers/SensorManager.h +++ b/src/helpers/SensorManager.h @@ -10,10 +10,10 @@ class SensorManager { public: - double node_lat, node_lon; // modify these, if you want to affect Advert location + double node_lat, node_lon, node_temp, node_hum, node_pres; // modify these, if you want to affect Advert location double node_altitude; // altitude in meters - SensorManager() { node_lat = 0; node_lon = 0; node_altitude = 0; } + SensorManager() { node_lat = 0; node_lon = 0; node_altitude = 0; node_temp = 0; node_hum = 0; node_pres = 0;} virtual bool begin() { return false; } virtual bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { return false; } virtual void loop() { } diff --git a/src/helpers/TBeamS3SupremeBoard.h b/src/helpers/TBeamS3SupremeBoard.h index 74d9ca2e..9bc9a83d 100644 --- a/src/helpers/TBeamS3SupremeBoard.h +++ b/src/helpers/TBeamS3SupremeBoard.h @@ -22,7 +22,7 @@ #define PIN_BOARD_SCL1 41 //SCL for PMU and PFC8563 (RTC) #define PIN_PMU_IRQ 40 //IRQ pin for PMU -#define PIN_USER_BTN 0 +//#define PIN_USER_BTN 0 #define P_BOARD_SPI_MOSI 35 //SPI for SD Card and QMI8653 (IMU) #define P_BOARD_SPI_MISO 37 //SPI for SD Card and QMI8653 (IMU) @@ -55,7 +55,9 @@ class TBeamS3SupremeBoard : public ESP32Board { XPowersAXP2101 PMU; public: #ifdef MESH_DEBUG + void scanDevices(TwoWire *w); void printPMU(); + void printBMEValues(); #endif bool power_init(); diff --git a/variants/lilygo_tbeam_supreme_SX1262/platformio.ini b/variants/lilygo_tbeam_supreme_SX1262/platformio.ini index d3447673..5ab9fedc 100644 --- a/variants/lilygo_tbeam_supreme_SX1262/platformio.ini +++ b/variants/lilygo_tbeam_supreme_SX1262/platformio.ini @@ -8,18 +8,21 @@ build_flags = -D P_LORA_TX_LED=6 -D PIN_BOARD_SDA=17 -D PIN_BOARD_SCL=18 + -D PIN_USER_BTN=0 -D RADIO_CLASS=CustomSX1262 -D WRAPPER_CLASS=CustomSX1262Wrapper - ;-D DISPLAY_CLASS=SSD1306Display ;Needs to be modified for SH1106 + -D DISPLAY_CLASS=SH1106Display -D SX126X_RX_BOOSTED_GAIN=1 build_src_filter = ${esp32_base.build_src_filter} +<../variants/lilygo_tbeam_supreme_SX1262> + + board_build.partitions = min_spiffs.csv ; get around 4mb flash limit lib_deps = ${esp32_base.lib_deps} lewisxhe/XPowersLib @ ^0.2.7 - ;adafruit/Adafruit SSD1306 @ ^2.5.13 + adafruit/Adafruit SH110X @ ^2.1.13 stevemarple/MicroNMEA @ ^2.0.6 + adafruit/Adafruit BME280 Library @ ^2.3.0 ; === LILYGO T-Beam S3 Supreme with SX1262 environments === [env:T_Beam_S3_Supreme_SX1262_repeater] diff --git a/variants/lilygo_tbeam_supreme_SX1262/target.cpp b/variants/lilygo_tbeam_supreme_SX1262/target.cpp index f5b7080b..97fd8c76 100644 --- a/variants/lilygo_tbeam_supreme_SX1262/target.cpp +++ b/variants/lilygo_tbeam_supreme_SX1262/target.cpp @@ -1,10 +1,16 @@ #include #include "target.h" #include +#include TBeamS3SupremeBoard board; +#ifdef DISPLAY_CLASS + DISPLAY_CLASS display; +#endif + bool pmuIntFlag; +//#define SEALEVELPRESSURE_HPA (1013.25) #ifndef LORA_CR #define LORA_CR 5 @@ -23,6 +29,7 @@ ESP32RTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); TbeamSupSensorManager sensors = TbeamSupSensorManager(nmea); +Adafruit_BME280 bme; static void setPMUIntFlag(){ pmuIntFlag = true; @@ -46,7 +53,7 @@ void scanDevices(TwoWire *w) switch (addr) { case 0x77: case 0x76: - Serial.println("\tFound BMX280 Sensor"); + Serial.println("\tFound BME280 Sensor"); deviceOnline |= BME280_ONLINE; break; case 0x34: @@ -107,6 +114,26 @@ void TBeamS3SupremeBoard::printPMU() Serial.println(); } +void printBMEValues() { + Serial.print("Temperature = "); + Serial.print(bme.readTemperature()); + Serial.println(" *C"); + + Serial.print("Pressure = "); + + Serial.print(bme.readPressure() / 100.0F); + Serial.println(" hPa"); + + Serial.print("Approx. Altitude = "); + Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA)); + Serial.println(" m"); + + Serial.print("Humidity = "); + Serial.print(bme.readHumidity()); + Serial.println(" %"); + + Serial.println(); +} #endif bool TBeamS3SupremeBoard::power_init() @@ -289,6 +316,10 @@ bool radio_init() { fallback_clock.begin(); rtc_clock.begin(Wire1); + + // #ifdef MESH_DEBUG + // printBMEValues(); + // #endif #ifdef SX126X_DIO3_TCXO_VOLTAGE float tcxo = SX126X_DIO3_TCXO_VOLTAGE; @@ -340,8 +371,14 @@ void TbeamSupSensorManager::sleep_gps() { } bool TbeamSupSensorManager::begin() { + //init BME280 + if (! bme.begin(0x77, &Wire)) { + MESH_DEBUG_PRINTLN("Could not find a valid BME280 sensor, check wiring!"); + } + else + MESH_DEBUG_PRINTLN("BME280 found and init!"); + // init GPS port - Serial1.begin(GPS_BAUD_RATE, SERIAL_8N1, P_GPS_RX, P_GPS_TX); bool result = false; @@ -359,22 +396,53 @@ bool TbeamSupSensorManager::querySensors(uint8_t requester_permissions, CayenneL 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) { // does requester have permission? + telemetry.addTemperature(TELEM_CHANNEL_SELF, node_temp); + telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, node_hum); + telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, node_pres); + //telemetry.addAltitude(TELEM_CHANNEL_SELF, node_alt); + } return true; } void TbeamSupSensorManager::loop() { - static long next_gps_update = 0; + static long next_update = 0; _nmea->loop(); - if (millis() > next_gps_update) { + if (millis() > next_update) { if (_nmea->isValid()) { node_lat = ((double)_nmea->getLatitude())/1000000.; node_lon = ((double)_nmea->getLongitude())/1000000.; node_altitude = ((double)_nmea->getAltitude()) / 1000.0; //Serial.printf("lat %f lon %f\r\n", _lat, _lon); } - next_gps_update = millis() + 1000; + + //read BME280 values + //node_alt = bme.readAltitude(SEALEVELPRESSURE_HPA); + node_temp = bme.readTemperature(); + node_hum = bme.readHumidity(); + node_pres = (bme.readPressure() / 100.0F); + + #ifdef MESH_DEBUG + Serial.print("Temperature = "); + Serial.print(node_temp); + Serial.println(" *C"); + + Serial.print("Humidity = "); + Serial.print(node_hum); + Serial.println(" %"); + + Serial.print("Pressure = "); + Serial.print(node_pres); + Serial.println(" hPa"); + + // Serial.print("Approx. Altitude = "); + // Serial.print(node_alt); + // Serial.println(" m"); + #endif + + next_update = millis() + 1000; } } diff --git a/variants/lilygo_tbeam_supreme_SX1262/target.h b/variants/lilygo_tbeam_supreme_SX1262/target.h index 107e2950..99ffa1c5 100644 --- a/variants/lilygo_tbeam_supreme_SX1262/target.h +++ b/variants/lilygo_tbeam_supreme_SX1262/target.h @@ -31,6 +31,11 @@ extern WRAPPER_CLASS radio_driver; extern AutoDiscoverRTCClock rtc_clock; extern TbeamSupSensorManager sensors; +#ifdef DISPLAY_CLASS + #include + extern DISPLAY_CLASS display; +#endif + enum { POWERMANAGE_ONLINE = _BV(0), DISPLAY_ONLINE = _BV(1), From 4990fe40e7d6a86553cc0da0c03aaebd7b69062d Mon Sep 17 00:00:00 2001 From: cod3doomy Date: Mon, 19 May 2025 13:15:01 -0700 Subject: [PATCH 07/41] t-beam supreme: current limit increase Added the current limit increase define --- variants/lilygo_tbeam_supreme_SX1262/platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/variants/lilygo_tbeam_supreme_SX1262/platformio.ini b/variants/lilygo_tbeam_supreme_SX1262/platformio.ini index 5ab9fedc..0316bef2 100644 --- a/variants/lilygo_tbeam_supreme_SX1262/platformio.ini +++ b/variants/lilygo_tbeam_supreme_SX1262/platformio.ini @@ -12,6 +12,7 @@ build_flags = -D RADIO_CLASS=CustomSX1262 -D WRAPPER_CLASS=CustomSX1262Wrapper -D DISPLAY_CLASS=SH1106Display + -D SX126X_CURRENT_LIMIT=140 -D SX126X_RX_BOOSTED_GAIN=1 build_src_filter = ${esp32_base.build_src_filter} +<../variants/lilygo_tbeam_supreme_SX1262> From 9a0b6e532629354550bc6a5636e7e12bf8f489f5 Mon Sep 17 00:00:00 2001 From: Adam Mealings Date: Tue, 20 May 2025 13:54:31 +0100 Subject: [PATCH 08/41] Updated to use #if defined... instead of #ifdef --- examples/companion_radio/UITask.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/companion_radio/UITask.cpp b/examples/companion_radio/UITask.cpp index 6eae88c9..3bbf87f2 100644 --- a/examples/companion_radio/UITask.cpp +++ b/examples/companion_radio/UITask.cpp @@ -209,7 +209,7 @@ void UITask::userLedHandler() { } void UITask::buttonHandler() { - #ifdef PIN_USER_BTN || PIN_USER_BTN_ANA + #if defined(PIN_USER_BTN) || defined(PIN_USER_BTN_ANA) static int prev_btn_state = !USER_BTN_PRESSED; static int prev_btn_state_ana = !USER_BTN_PRESSED; static unsigned long btn_state_change_time = 0; @@ -224,7 +224,6 @@ void UITask::buttonHandler() { #ifdef PIN_USER_BTN_ANA btn_state_ana = (analogRead(PIN_USER_BTN_ANA) < 20); // analogRead returns a value hopefully below 20 when button is pressed. #endif - //Serial.println(analogRead(PIN_USER_BTN_ANA)); if (btn_state != prev_btn_state || btn_state_ana != prev_btn_state_ana) { // check for either digital or analogue button change of state if (btn_state == USER_BTN_PRESSED || btn_state_ana == USER_BTN_PRESSED) { // pressed? if (_display != NULL) { From 009173ab9ecfcafb724a30ba9d5fb16a9c5172d4 Mon Sep 17 00:00:00 2001 From: Adam Mealings Date: Tue, 20 May 2025 15:16:56 +0100 Subject: [PATCH 09/41] added missing variable defs and pinmode --- src/helpers/nrf52/RAK4631Board.cpp | 4 ++++ variants/rak4631/platformio.ini | 1 + 2 files changed, 5 insertions(+) diff --git a/src/helpers/nrf52/RAK4631Board.cpp b/src/helpers/nrf52/RAK4631Board.cpp index 8b368734..eb1a42c5 100644 --- a/src/helpers/nrf52/RAK4631Board.cpp +++ b/src/helpers/nrf52/RAK4631Board.cpp @@ -26,6 +26,10 @@ void RAK4631Board::begin() { pinMode(PIN_USER_BTN, INPUT_PULLUP); #endif +#ifdef PIN_USER_BTN_ANA + pinMode(PIN_USER_BTN_ANA, INPUT_PULLUP); +#endif + #if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL) Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL); #endif diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini index d7584456..c2845fd4 100644 --- a/variants/rak4631/platformio.ini +++ b/variants/rak4631/platformio.ini @@ -7,6 +7,7 @@ build_flags = ${nrf52840_base.build_flags} -I variants/rak4631 -D RAK_4631 -D PIN_USER_BTN=9 + -D PIN_USER_BTN_ANA=31 -D PIN_BOARD_SCL=14 -D PIN_BOARD_SDA=13 -D PIN_OLED_RESET=-1 From 1c8aaebb90445d0190f4f415619d20ff012fe2c5 Mon Sep 17 00:00:00 2001 From: webmonkey Date: Tue, 20 May 2025 19:24:20 +0100 Subject: [PATCH 10/41] Proof-reading fixes to the FAQ Fixed spelling and grammar issues. Also changed the number of stored Room server messages from 16 to 32 --- docs/faq.md | 68 ++++++++++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/docs/faq.md b/docs/faq.md index 1bb4a0e5..3ac8894d 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -16,7 +16,7 @@ author: https://github.com/LitBomb - [1.2.4. Repeater](#124-repeater) - [1.2.5. Room Server](#125-room-server) - [2. Initial Setup](#2-initial-setup) - - [2.1. Q: How many devices do I need to start using meshcore?](#21-q-how-many-devices-do-i-need-to-start-using-meshcore) + - [2.1. Q: How many devices do I need to start using MeshCore?](#21-q-how-many-devices-do-i-need-to-start-using-meshcore) - [2.2. Q: Does MeshCore cost any money?](#22-q-does-meshcore-cost-any-money) - [2.3. Q: What frequencies are supported by MeshCore?](#23-q-what-frequencies-are-supported-by-meshcore) - [2.4. Q: What is an "advert" in MeshCore?](#24-q-what-is-an-advert-in-meshcore) @@ -40,7 +40,7 @@ author: https://github.com/LitBomb - [4.11. Q: What is the 'Import from Clipboard' feature on the t-deck and is there a way to manually add nodes without having to receive adverts?](#411-q-what-is-the-import-from-clipboard-feature-on-the-t-deck-and-is-there-a-way-to-manually-add-nodes-without-having-to-receive-adverts) - [5. General](#5-general) - [5.1. Q: What are BW, SF, and CR?](#51-q-what-are-bw-sf-and-cr) - - [5.2. Q: Do MeshCore clients repeat?](#52-q-do-meshcore-clients-repeat) + - [5.2. Q: Do MeshCore clients repeat?](#52-q-do--clients-repeat) - [5.3. Q: What happens when a node learns a route via a mobile repeater, and that repeater is gone?](#53-q-what-happens-when-a-node-learns-a-route-via-a-mobile-repeater-and-that-repeater-is-gone) - [5.4. Q: How does a node discovery a path to its destination and then use it to send messages in the future, instead of flooding every message it sends like Meshtastic?](#54-q-how-does-a-node-discovery-a-path-to-its-destination-and-then-use-it-to-send-messages-in-the-future-instead-of-flooding-every-message-it-sends-like-meshtastic) - [5.5. Q: Do public channels always flood? Do private channels always flood?](#55-q-do-public-channels-always-flood-do-private-channels-always-flood) @@ -61,8 +61,8 @@ author: https://github.com/LitBomb - [6. Troubleshooting](#6-troubleshooting) - [6.1. Q: My client says another client or a repeater or a room server was last seen many, many days ago.](#61-q-my-client-says-another-client-or-a-repeater-or-a-room-server-was-last-seen-many-many-days-ago) - [6.2. Q: A repeater or a client or a room server I expect to see on my discover list (on T-Deck) or contact list (on a smart device client) are not listed.](#62-q-a-repeater-or-a-client-or-a-room-server-i-expect-to-see-on-my-discover-list-on-t-deck-or-contact-list-on-a-smart-device-client-are-not-listed) - - [6.3. Q: How to connect to a repeater via BLE (bluetooth)?](#63-q-how-to-connect-to-a-repeater-via-ble-bluetooth) - - [6.4. Q: I can't connect via bluetooth, what is the bluetooth pairing code?](#64-q-i-cant-connect-via-bluetooth-what-is-the-bluetooth-pairing-code) + - [6.3. Q: How to connect to a repeater via BLE (Bluetooth)?](#63-q-how-to-connect-to-a-repeater-via-ble-bluetooth) + - [6.4. Q: I can't connect via Bluetooth, what is the Bluetooth pairing code?](#64-q-i-cant-connect-via-bluetooth-what-is-the-bluetooth-pairing-code) - [6.5. Q: My Heltec V3 keeps disconnecting from my smartphone. It can't hold a solid Bluetooth connection.](#65-q-my-heltec-v3-keeps-disconnecting-from-my-smartphone--it-cant-hold-a-solid-bluetooth-connection) - [7. Other Questions:](#7-other-questions) - [7.1. Q: How to Update repeater and room server firmware over the air?](#71-q-how-to--update-repeater-and-room-server-firmware-over-the-air) @@ -89,7 +89,7 @@ Anyone is able to build anything they like on top of MeshCore without paying any Main web site: [https://meshcore.co.uk/](https://meshcore.co.uk/) Firmware Flasher: https://flasher.meshcore.co.uk/ Phone Client Applications: https://meshcore.co.uk/apps.html - MeshCore Fimrware Github: https://github.com/ripplebiz/MeshCore + MeshCore Fimrware GitHub: https://github.com/ripplebiz/MeshCore NOTE: Andy Kirby has a very useful [intro video](https://www.youtube.com/watch?v=t1qne8uJBAc) for beginners. @@ -119,16 +119,16 @@ Companion radios are for connecting to the Android app or web app as a messenger #### 1.2.4. Repeater Repeaters are used to extend the range of a MeshCore network. Repeater firmware runs on the same devices that run client firmware. A repeater's job is to forward MeshCore packets to the destination device. It does **not** forward or retransmit every packet it receives, unlike other LoRa mesh systems. -A repeater can be remotely administered using a T-Deck running the MeshCore firwmware with remote admistration features unlocked, or from a BLE Companion client connected to a smartphone running the MeshCore app. +A repeater can be remotely administered using a T-Deck running the MeshCore firmware with remote administration features unlocked, or from a BLE Companion client connected to a smartphone running the MeshCore app. #### 1.2.5. Room Server A room server is a simple BBS server for sharing posts. T-Deck devices running MeshCore firmware or a BLE Companion client connected to a smartphone running the MeshCore app can connect to a room server. -room servers store message history on them, and push the stored messages to users. Room servers allow roaming users to come back later and retrieve message history. Contrast to channels, messages are either received when it's sent, or not received and missed if the a room user is out of range. You can think of room servers like email servers where you can come back later and get your emails from your mail server +Room servers store message history on them and push the stored messages to users. Room servers allow roaming users to come back later and retrieve message history. With channels, messages are either received when it's sent, or not received and missed if the channel user is out of range. Room servers are different and more like email servers where you can come back later and get your emails from your mail server. -A room server can be remotely administered using a T-Deck running the MeshCore firwmware with remote admistration features unlocked, or from a BLE Companion client connected to a smartphone running the MeshCore app. +A room server can be remotely administered using a T-Deck running the MeshCore firmware with remote administration features unlocked, or from a BLE Companion client connected to a smartphone running the MeshCore app. -When a client logs into a room server, the client will receive the previously 16 unseen messages. +When a client logs into a room server, the client will receive the previously 32 unseen messages. A room server can also take on the repeater role. To enable repeater role on a room server, use this command: @@ -138,26 +138,26 @@ A room server can also take on the repeater role. To enable repeater role on a ## 2. Initial Setup -### 2.1. Q: How many devices do I need to start using meshcore? -**A:** If you have one supported device, flash the BLE Companion firmware and use your device as a client. You can connect to the device using the Android client via bluetooth (iOS client will be available later). You can start communiating with other MeshCore users near you. +### 2.1. Q: How many devices do I need to start using MeshCore? +**A:** If you have one supported device, flash the BLE Companion firmware and use your device as a client. You can connect to the device using the Android client via Bluetooth (iOS client will be available later). You can start communicating with other MeshCore users near you. -If you have two supported devices, and there are not many MeshCore users near you, flash both of them to BLE Companion firmware so you can use your devices to communiate with your near-by friends and family. +If you have two supported devices, and there are not many MeshCore users near you, flash both to BLE Companion firmware so you can use your devices to communicate with your near-by friends and family. -If you have two supported devices, and there are other MeshcCore users near by, you can flash one of your devices with BLE Companion firmware, and flash another supported device to repeater firmware. Place the repeater high above ground o extend your MeshCore network's reach. +If you have two supported devices, and there are other MeshcCore users nearby, you can flash one of your devices with BLE Companion firmware and flash another supported device to repeater firmware. Place the repeater high above ground to extend your MeshCore network's reach. -After you flashed the latest firmware onto your repeater device, keep the device connected to your computer via USB serial, use the console feature on the web flasher and set the frequency for your region or country, so your client can remote administer the rpeater or room server over RF: +After you flashed the latest firmware onto your repeater device, keep the device connected to your computer via USB serial, use the console feature on the web flasher and set the frequency for your region or country, so your client can remote administer the repeater or room server over RF: `set freq {frequency}` The repeater and room server CLI reference is here: https://github.com/ripplebiz/MeshCore/wiki/Repeater-&-Room-Server-CLI-Reference -If you have more supported devices, you can use your additional deivces with the room server firmware. +If you have more supported devices, you can use your additional devices with the room server firmware. ### 2.2. Q: Does MeshCore cost any money? **A:** All radio firmware versions (e.g. for Heltec V3, RAK, T-1000E, etc) are free and open source developed by Scott at Ripple Radios. -The native Android and iOS client uses the freemium model and is developed by Liam Cottle, developer of meshtastic map at [meshtastic.liamcottle.net](https://meshtastic.liamcottle.net) on [github ](https://github.com/liamcottle/meshtastic-map)and [reticulum-meshchat on github](https://github.com/liamcottle/reticulum-meshchat). +The native Android and iOS client uses the freemium model and is developed by Liam Cottle, developer of meshtastic map at [meshtastic.liamcottle.net](https://meshtastic.liamcottle.net) on [GitHub](https://github.com/liamcottle/meshtastic-map) and [reticulum-meshchat on github](https://github.com/liamcottle/reticulum-meshchat). The T-Deck firmware is free to download and most features are available without cost. To support the firmware developer, you can pay for a registration key to unlock your T-Deck for deeper map zoom and remote server administration over RF using the T-Deck. You do not need to pay for the registration to use your T-Deck for direct messaging and connecting to repeaters and room servers. @@ -178,16 +178,16 @@ the rest of the radio settings are the same for all frequencies: - Coding Rate (CR): 5 - Bandwidth (BW): 250.00 -(originally MeshCore started with SF 10. recently (as of late April 2025) the community has avocated SF 11 also a viable option for longer range but a little slower transmissions. Currently there are MeshCore meshes with SF 10 and SF 11. Liam Cottle's smartphone app's presets now recommend SF 10 for Australia and SF 11 for all other regions and countries. EU and UK has SF 10 and SF 11 presets. Work with your local meshers on diciding with SF number is best for your use cases. In the future, there may be bridge nodes that can bridge SF 10 and SF 11 (or even different frequencies) traffic.) +(Originally MeshCore started with SF 10. recently (as of late April 2025) the community has advocated SF 11 also a viable option for longer range but a little slower transmission. Currently there are MeshCore meshes with SF 10 and SF 11. Liam Cottle's smartphone app's presets now recommend SF 10 for Australia and SF 11 for all other regions and countries. EU and UK has SF 10 and SF 11 presets. Work with your local meshers on deciding with SF number is best for your use cases. In the future, there may be bridge nodes that can bridge SF 10 and SF 11 (or even different frequencies) traffic.) ### 2.4. Q: What is an "advert" in MeshCore? **A:** -Advert means to advertise yourself on the network. In Reticulum terms it would be to announce. In Meshtastic terms it would be the node sending it's node info. +Advert means to advertise yourself on the network. In Reticulum terms it would be to announce. In Meshtastic terms it would be the node sending its node info. MeshCore allows you to manually broadcast your name, position and public encryption key, which is also signed to prevent spoofing. When you click the advert button, it broadcasts that data over LoRa. MeshCore calls that an Advert. There's two ways to advert, "zero hop" and "flood". * Zero hop means your advert is broadcasted out to anyone that can hear it, and that's it. -* Flooded means it's broadcasted out, and then repeated by all the repeaters that hear it. +* Flooded means it's broadcasted out and then repeated by all the repeaters that hear it. MeshCore clients only advertise themselves when the user initiates it. A repeater (and room server?) advertises its presence once every 240 minutes. This interval can be configured using the following command: @@ -259,9 +259,9 @@ You can get the latitude and longitude from Google Maps by right-clicking the lo 8. At this point you can begin flashing using ### 4.2. Q: Why is my T-Deck Plus not getting any satellite lock? -**A:** For T-Deck Plus, the GPS baud rate should be set to **38400**. Also, a number of T-Deck Plus devices were found to have the GPS module installed upside down, with the GPS antenna facing down instead of up. If your T-Deck Plus still doesn't get any satellite lock after setting the baud rate to 38400, you might need to open up the device to check the GPS orientation. +**A:** For T-Deck Plus, the GPS baud rate should be set to **38400**. Also, some T-Deck Plus devices were found to have the GPS module installed upside down, with the GPS antenna facing down instead of up. If your T-Deck Plus still doesn't get any satellite lock after setting the baud rate to 38400, you might need to open the device to check the GPS orientation. -GPS on T-Deck is always enabled. You can skip the "GPS clock sync" and the T-Deck will continue to try to get a GPS lock. You can go to the `GPS Info` screen, you should see the `Sentences:` coutner increasing if the baud rate is correct. +GPS on T-Deck is always enabled. You can skip the "GPS clock sync" and the T-Deck will continue to try to get a GPS lock. You can go to the `GPS Info` screen; you should see the `Sentences:` counter increasing if the baud rate is correct. [Source]([https://](https://discord.com/channels/826570251612323860/1330643963501351004/1356609240302616689)) @@ -294,7 +294,7 @@ Unlock page: ### 4.8. Q: How to decipher the diagnostics screen on T-Deck? -**A: ** Space is tight on T-Deck's screen so the information is a bit cryptic. Format is : +**A: ** Space is tight on T-Deck's screen, so the information is a bit cryptic. The format is : `{hops} l:{packet-length}({payload-len}) t:{packet-type} snr:{n} rssi:{n}` See here for packet-type: [https://github.com/ripplebiz/MeshCore/blob/main/src/Packet.h#L19](https://github.com/ripplebiz/MeshCore/blob/main/src/Packet.h#L19 "https://github.com/ripplebiz/MeshCore/blob/main/src/Packet.h#L19") @@ -337,11 +337,11 @@ Making the bandwidth 2x wider (from BW125 to BW250) allows you to send 2x more b Lowering the spreading factor makes it more difficult for the gateway to receive a transmission, as it will be more sensitive to noise. You could compare this to two people taking in a noisy place (a bar for example). If you’re far from each other, you have to talk slow (SF10), but if you’re close, you can talk faster (SF7) -So it's balancing act between speed of the transmission and resistance to noise. +So, it's balancing act between speed of the transmission and resistance to noise. things network is mainly focused on LoRaWAN, but the LoRa low-level stuff still checks out for any LoRa project ### 5.2. Q: Do MeshCore clients repeat? -**A:** No, MeshCore clients do not repeat. This is the core of MeshCore's messaging-first design. This is to avoid devices flooding the air ware and create endless collisions so messages sent aren't received. +**A:** No, MeshCore clients do not repeat. This is the core of MeshCore's messaging-first design. This is to avoid devices flooding the air ware and create endless collisions, so messages sent aren't received. In MeshCore, only repeaters and room server with '`set repeat on` repeat. ### 5.3. Q: What happens when a node learns a route via a mobile repeater, and that repeater is gone? @@ -352,13 +352,13 @@ In the case if users are moving around frequently, and the paths are breaking, t ### 5.4. Q: How does a node discovery a path to its destination and then use it to send messages in the future, instead of flooding every message it sends like Meshtastic? -Routes are stored in sender's contact list. When you send a message the first time, the message first gets to your destination by flood routing, When your destination node gets the message, it sends back to the sender a delivery report with all repeaters that the original message went through. This delivery report is flood-routed back to you the sender and is a basis for future direct path. when you send the next message, the path will get embedded into the packet and be evaluated by repeaters. if the hop and address of the repeater matches, it will retransmit the message, otherwise it will not retransmit, hence minimizing utilization. +Routes are stored in sender's contact list. When you send a message the first time, the message first gets to your destination by flood routing, when your destination node gets the message, it sends back to the sender a delivery report with all repeaters that the original message went through. This delivery report is flood-routed back to you the sender and is a basis for future direct path. when you send the next message, the path will get embedded into the packet and be evaluated by repeaters. if the hop and address of the repeater matches, it will retransmit the message, otherwise it will not retransmit, hence minimizing utilization. [Source](https://discord.com/channels/826570251612323860/1330643963501351004/1351279141630119996) ### 5.5. Q: Do public channels always flood? Do private channels always flood? -**A:** Yes, group channels are A to B, so there is no defined path. They have to flood. Repeaters can however deny flood traffic up to some hop limit, with the `set flood.max` CLI command. Admistrators of repeaters get to set the rules of their repeaters. +**A:** Yes, group channels are A to B, so there is no defined path. They have to flood. Repeaters can however deny flood traffic up to some hop limit, with the `set flood.max` CLI command. Administrators of repeaters get to set the rules of their repeaters. [Source](https://discord.com/channels/1343693475589263471/1343693475589263474/1350023009527664672) @@ -490,7 +490,7 @@ adafruit-nrfutil --verbose dfu serial --package t1000_e_bootloader-0.9.1-5-g4887 **A:** Yes. See the following: #### 5.14.1. meshcoremqtt -A python based script to send meshore debug and packet capture data to MQTT for analysis +A Python script to send meshore debug and packet capture data to MQTT for analysis https://github.com/Andrew-a-g/meshcoretomqtt #### 5.14.2. MeshCore for Home Assistant @@ -506,7 +506,7 @@ CLI interface to MeshCore companion radio over BLE, TCP, or serial. Uses Pyton https://github.com/fdlamotte/meshcore-cli #### 5.14.5. meshcore.js -A Javascript library for interacting with a MeshCore device running the companion radio firmware +A JavaScript library for interacting with a MeshCore device running the companion radio firmware https://github.com/liamcottle/meshcore.js --- @@ -521,23 +521,23 @@ https://github.com/liamcottle/meshcore.js You can get the epoch time on and use it to set your T-Deck clock. For a repeater and room server, the admin can use a T-Deck to remotely set their clock (clock sync), or use the `time` command in the USB serial console with the server device connected. -### 6.3. Q: How to connect to a repeater via BLE (bluetooth)? -**A:** You can't connect to a device running repeater firmware via bluetooth. Devices running the BLE companion firmware you can connect to it via bluetooth using the android app +### 6.3. Q: How to connect to a repeater via BLE (Bluetooth)? +**A:** You can't connect to a device running repeater firmware via Bluetooth. Devices running the BLE companion firmware you can connect to it via Bluetooth using the android app -### 6.4. Q: I can't connect via bluetooth, what is the bluetooth pairing code? +### 6.4. Q: I can't connect via Bluetooth, what is the Bluetooth pairing code? -**A:** the default bluetooth pairing code is `123456` +**A:** the default Bluetooth pairing code is `123456` ### 6.5. Q: My Heltec V3 keeps disconnecting from my smartphone. It can't hold a solid Bluetooth connection. -**A:** Heltec V3 has a very small coil antenna on its PCB for WiFi and Bluetooth connectivty. It has a very short range, only a few feet. It is possible to remove the coil antenna and replace it with a 31mm wire. The BT range is much improved with the modification. +**A:** Heltec V3 has a very small coil antenna on its PCB for Wi-Fi and Bluetooth connectivity. It has a very short range, only a few feet. It is possible to remove the coil antenna and replace it with a 31mm wire. The BT range is much improved with the modification. --- ## 7. Other Questions: ### 7.1. Q: How to Update repeater and room server firmware over the air? **A:** Only nRF-based RAK4631 and Heltec T114 OTA firmware update are verified using nRF smartphone app. Lilygo T-Echo doesn't work currently. -You can update repeater and room server firmware with a bluetooth connection between your smartphone and your LoRa radio using the nRF app. +You can update repeater and room server firmware with a Bluetooth connection between your smartphone and your LoRa radio using the nRF app. 1. Download the ZIP file for the specific node from the web flasher to your smartphone 2. On the phone client, log on to the repeater as administrator (default password is `password`) to issue the `start ota`command to the repeater or room server to get the device into OTA DFU mode From 4f503de7431cfa446e0bb3fb9113389ba6e35880 Mon Sep 17 00:00:00 2001 From: cod3doomy Date: Tue, 20 May 2025 11:37:41 -0700 Subject: [PATCH 11/41] t-beam supreme: fixes and cleanup Reverted the SensorManager changes Moved BME into TbeamSupSensorManager Moved printBMEValues into TbeamSupSensorManager Moved scanDevices out of TBeamS3SupremeBoard --- src/helpers/SensorManager.h | 4 ++-- src/helpers/TBeamS3SupremeBoard.h | 2 -- variants/lilygo_tbeam_supreme_SX1262/target.cpp | 5 +---- variants/lilygo_tbeam_supreme_SX1262/target.h | 17 ++++++++++++++--- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/helpers/SensorManager.h b/src/helpers/SensorManager.h index f48c2a7b..41c34e55 100644 --- a/src/helpers/SensorManager.h +++ b/src/helpers/SensorManager.h @@ -10,10 +10,10 @@ class SensorManager { public: - double node_lat, node_lon, node_temp, node_hum, node_pres; // modify these, if you want to affect Advert location + double node_lat, node_lon; // modify these, if you want to affect Advert location double node_altitude; // altitude in meters - SensorManager() { node_lat = 0; node_lon = 0; node_altitude = 0; node_temp = 0; node_hum = 0; node_pres = 0;} + SensorManager() { node_lat = 0; node_lon = 0; node_altitude = 0;} virtual bool begin() { return false; } virtual bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { return false; } virtual void loop() { } diff --git a/src/helpers/TBeamS3SupremeBoard.h b/src/helpers/TBeamS3SupremeBoard.h index 9bc9a83d..1ae6a230 100644 --- a/src/helpers/TBeamS3SupremeBoard.h +++ b/src/helpers/TBeamS3SupremeBoard.h @@ -55,9 +55,7 @@ class TBeamS3SupremeBoard : public ESP32Board { XPowersAXP2101 PMU; public: #ifdef MESH_DEBUG - void scanDevices(TwoWire *w); void printPMU(); - void printBMEValues(); #endif bool power_init(); diff --git a/variants/lilygo_tbeam_supreme_SX1262/target.cpp b/variants/lilygo_tbeam_supreme_SX1262/target.cpp index 97fd8c76..4dbfd625 100644 --- a/variants/lilygo_tbeam_supreme_SX1262/target.cpp +++ b/variants/lilygo_tbeam_supreme_SX1262/target.cpp @@ -1,7 +1,6 @@ #include #include "target.h" #include -#include TBeamS3SupremeBoard board; @@ -10,7 +9,6 @@ TBeamS3SupremeBoard board; #endif bool pmuIntFlag; -//#define SEALEVELPRESSURE_HPA (1013.25) #ifndef LORA_CR #define LORA_CR 5 @@ -29,7 +27,6 @@ ESP32RTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); TbeamSupSensorManager sensors = TbeamSupSensorManager(nmea); -Adafruit_BME280 bme; static void setPMUIntFlag(){ pmuIntFlag = true; @@ -114,7 +111,7 @@ void TBeamS3SupremeBoard::printPMU() Serial.println(); } -void printBMEValues() { +void TbeamSupSensorManager::printBMEValues() { Serial.print("Temperature = "); Serial.print(bme.readTemperature()); Serial.println(" *C"); diff --git a/variants/lilygo_tbeam_supreme_SX1262/target.h b/variants/lilygo_tbeam_supreme_SX1262/target.h index 99ffa1c5..dbb24a8e 100644 --- a/variants/lilygo_tbeam_supreme_SX1262/target.h +++ b/variants/lilygo_tbeam_supreme_SX1262/target.h @@ -8,15 +8,20 @@ #include #include #include +#include class TbeamSupSensorManager: public SensorManager { bool gps_active = false; LocationProvider * _nmea; - + Adafruit_BME280 bme; + double node_temp, node_hum, node_pres; + + #define SEALEVELPRESSURE_HPA (1013.25) + void start_gps(); void sleep_gps(); public: - TbeamSupSensorManager(LocationProvider &nmea): _nmea(&nmea) { } + TbeamSupSensorManager(LocationProvider &nmea): _nmea(&nmea) {node_temp = 0; node_hum = 0; node_pres = 0;} bool begin() override; bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override; void loop() override; @@ -24,6 +29,11 @@ class TbeamSupSensorManager: public SensorManager { const char* getSettingName(int i) const override; const char* getSettingValue(int i) const override; bool setSettingValue(const char* name, const char* value) override; + + #ifdef MESH_DEBUG + void printBMEValues(); + #endif + }; extern TBeamS3SupremeBoard board; @@ -53,7 +63,8 @@ enum { OSC32768_ONLINE = _BV(13), }; -bool power_init(); +void scanDevices(TwoWire *w); +static bool l76kProbe(); bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); From 7839cb29a16bc083901d1de4091d11690a6120dc Mon Sep 17 00:00:00 2001 From: webmonkey Date: Tue, 20 May 2025 21:42:36 +0100 Subject: [PATCH 12/41] Small fixes --- docs/faq.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/faq.md b/docs/faq.md index 3ac8894d..030c5531 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -40,7 +40,7 @@ author: https://github.com/LitBomb - [4.11. Q: What is the 'Import from Clipboard' feature on the t-deck and is there a way to manually add nodes without having to receive adverts?](#411-q-what-is-the-import-from-clipboard-feature-on-the-t-deck-and-is-there-a-way-to-manually-add-nodes-without-having-to-receive-adverts) - [5. General](#5-general) - [5.1. Q: What are BW, SF, and CR?](#51-q-what-are-bw-sf-and-cr) - - [5.2. Q: Do MeshCore clients repeat?](#52-q-do--clients-repeat) + - [5.2. Q: Do MeshCore clients repeat?](#52-q-do-meshcore-clients-repeat) - [5.3. Q: What happens when a node learns a route via a mobile repeater, and that repeater is gone?](#53-q-what-happens-when-a-node-learns-a-route-via-a-mobile-repeater-and-that-repeater-is-gone) - [5.4. Q: How does a node discovery a path to its destination and then use it to send messages in the future, instead of flooding every message it sends like Meshtastic?](#54-q-how-does-a-node-discovery-a-path-to-its-destination-and-then-use-it-to-send-messages-in-the-future-instead-of-flooding-every-message-it-sends-like-meshtastic) - [5.5. Q: Do public channels always flood? Do private channels always flood?](#55-q-do-public-channels-always-flood-do-private-channels-always-flood) @@ -342,7 +342,7 @@ things network is mainly focused on LoRaWAN, but the LoRa low-level stuff still ### 5.2. Q: Do MeshCore clients repeat? **A:** No, MeshCore clients do not repeat. This is the core of MeshCore's messaging-first design. This is to avoid devices flooding the air ware and create endless collisions, so messages sent aren't received. -In MeshCore, only repeaters and room server with '`set repeat on` repeat. +In MeshCore, only repeaters and room server with `set repeat on` repeat. ### 5.3. Q: What happens when a node learns a route via a mobile repeater, and that repeater is gone? @@ -352,7 +352,7 @@ In the case if users are moving around frequently, and the paths are breaking, t ### 5.4. Q: How does a node discovery a path to its destination and then use it to send messages in the future, instead of flooding every message it sends like Meshtastic? -Routes are stored in sender's contact list. When you send a message the first time, the message first gets to your destination by flood routing, when your destination node gets the message, it sends back to the sender a delivery report with all repeaters that the original message went through. This delivery report is flood-routed back to you the sender and is a basis for future direct path. when you send the next message, the path will get embedded into the packet and be evaluated by repeaters. if the hop and address of the repeater matches, it will retransmit the message, otherwise it will not retransmit, hence minimizing utilization. +Routes are stored in sender's contact list. When you send a message the first time, the message first gets to your destination by flood routing. When your destination node gets the message, it will send back a delivery report to the sender with all repeaters that the original message went through. This delivery report is flood-routed back to you the sender and is a basis for future direct path. When you send the next message, the path will get embedded into the packet and be evaluated by repeaters. If the hop and address of the repeater matches, it will retransmit the message, otherwise it will not retransmit, hence minimizing utilization. [Source](https://discord.com/channels/826570251612323860/1330643963501351004/1351279141630119996) From 98d94d9423066518c9f61aff7a0564b1651ef842 Mon Sep 17 00:00:00 2001 From: Normunds Gavars Date: Thu, 22 May 2025 00:19:00 +0300 Subject: [PATCH 13/41] Remove sensor wrapper classes and simplify. Switch to Adafruit libs for sensors. --- src/helpers/sensors/AHTX0Sensor.h | 39 ------ src/helpers/sensors/BME280Sensor.h | 55 -------- .../sensors/EnvironmentSensorManager.cpp | 118 ++++++++++-------- .../sensors/EnvironmentSensorManager.h | 40 +++--- src/helpers/sensors/INA3221Sensor.h | 71 ----------- variants/promicro/platformio.ini | 15 +-- 6 files changed, 97 insertions(+), 241 deletions(-) delete mode 100644 src/helpers/sensors/AHTX0Sensor.h delete mode 100644 src/helpers/sensors/BME280Sensor.h delete mode 100644 src/helpers/sensors/INA3221Sensor.h diff --git a/src/helpers/sensors/AHTX0Sensor.h b/src/helpers/sensors/AHTX0Sensor.h deleted file mode 100644 index 04af3057..00000000 --- a/src/helpers/sensors/AHTX0Sensor.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once -#include -#include - -#define TELEM_AHTX_ADDRESS 0x38 // AHT10, AHT20 temperature and humidity sensor I2C address - -static Adafruit_AHTX0 AHTX0; - -class AHTX0Sensor { - bool initialized = false; -public: - void begin() { - if (AHTX0.begin(&Wire, 0, TELEM_AHTX_ADDRESS)) { - MESH_DEBUG_PRINTLN("Found AHT10/AHT20 at address: %02X", TELEM_AHTX_ADDRESS); - initialized = true; - } else { - initialized = false; - MESH_DEBUG_PRINTLN("AHT10/AHT20 was not found at I2C address %02X", TELEM_AHTX_ADDRESS); - } - } - - bool isInitialized() const { return initialized; }; - - float getRelativeHumidity() const { - if (initialized) { - sensors_event_t humidity, temp; - AHTX0.getEvent(&humidity, &temp); - return humidity.relative_humidity; - } - } - - float getTemperature() const { - if (initialized) { - sensors_event_t humidity, temp; - AHTX0.getEvent(&humidity, &temp); - return temp.temperature; - } - } -}; diff --git a/src/helpers/sensors/BME280Sensor.h b/src/helpers/sensors/BME280Sensor.h deleted file mode 100644 index 1226fce5..00000000 --- a/src/helpers/sensors/BME280Sensor.h +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once -#include -#include - -#define TELEM_BME280_ADDRESS 0x76 // BME280 environmental sensor I2C address -#define SEALEVELPRESSURE_HPA (1013.25) // Athmospheric pressure at sea level - -static Adafruit_BME280 BME280; - -class BME280Sensor { - bool initialized = false; -public: - void begin() { - if (BME280.begin(TELEM_BME280_ADDRESS, &Wire)) { - MESH_DEBUG_PRINTLN("Found BME280 at address: %02X", TELEM_BME280_ADDRESS); - MESH_DEBUG_PRINTLN("BME sensor ID: %02X", BME280.sensorID); - initialized = true; - } else { - initialized = false; - MESH_DEBUG_PRINTLN("BME280 was not found at I2C address %02X", TELEM_BME280_ADDRESS); - } - } - - bool isInitialized() const { return initialized; }; - - float getRelativeHumidity() const { - if (initialized) { - return BME280.readHumidity();; - } - } - - float getTemperature() const { - if (initialized) { - return BME280.readTemperature();; - } - } - - float getBarometricPressure() const { - if (initialized) { - return BME280.readPressure(); - } - } - - float getAltitude() const { - if (initialized) { - return BME280.readAltitude(SEALEVELPRESSURE_HPA); - } - } - - void setTemperatureCompensation(float delta) { - if (initialized) { - BME280.setTemperatureCompensation(delta); - } - } -}; diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp index cf931470..6d39e905 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.cpp +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -1,10 +1,49 @@ #include "EnvironmentSensorManager.h" +static Adafruit_AHTX0 AHTX0; +static Adafruit_BME280 BME280; +static Adafruit_INA3221 INA3221; +static Adafruit_INA219 INA219(TELEM_INA219_ADDRESS); + bool EnvironmentSensorManager::begin() { - INA3221_sensor.begin(); - INA219_sensor.begin(); - AHTX0_sensor.begin(); - BME280_sensor.begin(); + + if (INA3221.begin(TELEM_INA3221_ADDRESS, &Wire)) { + MESH_DEBUG_PRINTLN("Found INA3221 at address: %02X", TELEM_INA3221_ADDRESS); + MESH_DEBUG_PRINTLN("%04X %04X", INA3221.getDieID(), INA3221.getManufacturerID()); + + for(int i = 0; i < 3; i++) { + INA3221.setShuntResistance(i, TELEM_INA3221_SHUNT_VALUE); + } + INA3221_initialized = true; + } else { + INA3221_initialized = false; + MESH_DEBUG_PRINTLN("INA3221 was not found at I2C address %02X", TELEM_INA3221_ADDRESS); + } + + if (INA219.begin(&Wire)) { + MESH_DEBUG_PRINTLN("Found INA219 at address: %02X", TELEM_INA219_ADDRESS); + INA219_initialized = true; + } else { + INA219_initialized = false; + MESH_DEBUG_PRINTLN("INA219 was not found at I2C address %02X", TELEM_INA219_ADDRESS); + } + + if (AHTX0.begin(&Wire, 0, TELEM_AHTX_ADDRESS)) { + MESH_DEBUG_PRINTLN("Found AHT10/AHT20 at address: %02X", TELEM_AHTX_ADDRESS); + AHTX0_initialized = true; + } else { + AHTX0_initialized = false; + MESH_DEBUG_PRINTLN("AHT10/AHT20 was not found at I2C address %02X", TELEM_AHTX_ADDRESS); + } + + if (BME280.begin(TELEM_BME280_ADDRESS, &Wire)) { + MESH_DEBUG_PRINTLN("Found BME280 at address: %02X", TELEM_BME280_ADDRESS); + MESH_DEBUG_PRINTLN("BME sensor ID: %02X", BME280.sensorID); + BME280_initialized = true; + } else { + BME280_initialized = false; + MESH_DEBUG_PRINTLN("BME280 was not found at I2C address %02X", TELEM_BME280_ADDRESS); + } return true; } @@ -12,63 +51,40 @@ bool EnvironmentSensorManager::begin() { bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { next_available_channel = TELEM_CHANNEL_SELF + 1; if (requester_permissions & TELEM_PERM_ENVIRONMENT) { - if (INA3221_sensor.isInitialized()) { - for(int i = 0; i < 3; i++) { + if (INA3221_initialized) { + for(int i = 0; i < TELEM_INA3221_NUM_CHANNELS; i++) { // add only enabled INA3221 channels to telemetry - if (INA3221_sensor.getChannelEnabled(i)) { - telemetry.addVoltage(next_available_channel, INA3221_sensor.getVoltage(i)); - telemetry.addCurrent(next_available_channel, INA3221_sensor.getCurrent(i)); - telemetry.addPower(next_available_channel, INA3221_sensor.getPower(i)); + if (INA3221.isChannelEnabled(i)) { + float voltage = INA3221.getBusVoltage(i); + float current = INA3221.getCurrentAmps(i); + telemetry.addVoltage(next_available_channel, voltage); + telemetry.addCurrent(next_available_channel, current); + telemetry.addPower(next_available_channel, voltage * current); next_available_channel++; } } } - if (INA219_sensor.isInitialized()) { - telemetry.addVoltage(next_available_channel, INA219_sensor.getVoltage()); - telemetry.addCurrent(next_available_channel, INA219_sensor.getCurrent()); - telemetry.addPower(next_available_channel, INA219_sensor.getPower()); + if (INA219_initialized) { + telemetry.addVoltage(next_available_channel, INA219.getBusVoltage_V()); + telemetry.addCurrent(next_available_channel, INA219.getCurrent_mA() / 1000); + telemetry.addPower(next_available_channel, INA219.getPower_mW() / 1000); next_available_channel++; } - if (AHTX0_sensor.isInitialized()) { - telemetry.addTemperature(TELEM_CHANNEL_SELF, AHTX0_sensor.getTemperature()); - telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, AHTX0_sensor.getRelativeHumidity()); + if (AHTX0_initialized) { + sensors_event_t humidity, temp; + AHTX0.getEvent(&humidity, &temp); + + telemetry.addTemperature(TELEM_CHANNEL_SELF, temp.temperature); + telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, humidity.relative_humidity); } - if (BME280_sensor.isInitialized()) { - telemetry.addTemperature(TELEM_CHANNEL_SELF, BME280_sensor.getTemperature()); - telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, BME280_sensor.getRelativeHumidity()); - telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, BME280_sensor.getBarometricPressure()); - telemetry.addAltitude(TELEM_CHANNEL_SELF, BME280_sensor.getAltitude()); + + if (BME280_initialized) { + telemetry.addTemperature(TELEM_CHANNEL_SELF, BME280.readTemperature()); + telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, BME280.readHumidity()); + telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, BME280.readPressure()); + telemetry.addAltitude(TELEM_CHANNEL_SELF, BME280.readAltitude(TELEM_BME280_SEALEVELPRESSURE_HPA)); } } return true; -} - -int EnvironmentSensorManager::getNumSettings() const { - return NUM_SENSOR_SETTINGS; -} - -const char* EnvironmentSensorManager::getSettingName(int i) const { - if (i >= 0 && i < NUM_SENSOR_SETTINGS) { - return INA3221_CHANNEL_NAMES[i]; - } - return NULL; -} - -const char* EnvironmentSensorManager::getSettingValue(int i) const { - if (i >= 0 && i < NUM_SENSOR_SETTINGS) { - return INA3221_sensor.getChannelEnabled(i) == true ? "1" : "0"; - } - return NULL; -} - -bool EnvironmentSensorManager::setSettingValue(const char* name, const char* value) { - for (int i = 0; i < NUM_SENSOR_SETTINGS; i++) { - if (strcmp(name, INA3221_CHANNEL_NAMES[i]) == 0) { - bool channel_enabled = strcmp(value, "1") == 0 ? true : false; - INA3221_sensor.setChannelEnabled(i, channel_enabled); - return true; - } - } - return false; } \ No newline at end of file diff --git a/src/helpers/sensors/EnvironmentSensorManager.h b/src/helpers/sensors/EnvironmentSensorManager.h index 318de001..2852805a 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.h +++ b/src/helpers/sensors/EnvironmentSensorManager.h @@ -1,33 +1,37 @@ #pragma once #include -#include "INA3221Sensor.h" -#include "INA219Sensor.h" -#include "AHTX0Sensor.h" -#include "BME280Sensor.h" +#include +#include +#include +#include +#include #define NUM_SENSOR_SETTINGS 3 -#define TELEM_INA3221_SETTING_CH1 "INA3221-1" -#define TELEM_INA3221_SETTING_CH2 "INA3221-2" -#define TELEM_INA3221_SETTING_CH3 "INA3221-3" +#define TELEM_AHTX_ADDRESS 0x38 // AHT10, AHT20 temperature and humidity sensor I2C address +#define TELEM_BME280_ADDRESS 0x76 // BME280 environmental sensor I2C address +#define TELEM_INA3221_ADDRESS 0x42 // INA3221 3 channel current sensor I2C address +#define TELEM_INA219_ADDRESS 0x40 // INA219 single channel current sensor I2C address + +#define TELEM_INA3221_SHUNT_VALUE 0.100 // most variants will have a 0.1 ohm shunts +#define TELEM_INA3221_NUM_CHANNELS 3 + +#define TELEM_INA219_SHUNT_VALUE 0.100 // shunt value in ohms (may differ between manufacturers) +#define TELEM_INA219_MAX_CURRENT 5 + +#define TELEM_BME280_SEALEVELPRESSURE_HPA (1013.25) // Athmospheric pressure at sea level class EnvironmentSensorManager : public SensorManager { -// INA3221 channels in telemetry -const char * INA3221_CHANNEL_NAMES[NUM_SENSOR_SETTINGS] = { TELEM_INA3221_SETTING_CH1, TELEM_INA3221_SETTING_CH2, TELEM_INA3221_SETTING_CH3}; - protected: int next_available_channel = TELEM_CHANNEL_SELF + 1; - INA3221Sensor INA3221_sensor; - AHTX0Sensor AHTX0_sensor; - INA219Sensor INA219_sensor; - BME280Sensor BME280_sensor; + + bool INA3221_initialized = false; + bool INA219_initialized = false; + bool BME280_initialized = false; + bool AHTX0_initialized = false; public: EnvironmentSensorManager(){}; bool begin() override; bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override; - int getNumSettings() const override; - const char* getSettingName(int i) const override; - const char* getSettingValue(int i) const override; - bool setSettingValue(const char* name, const char* value) override; }; diff --git a/src/helpers/sensors/INA3221Sensor.h b/src/helpers/sensors/INA3221Sensor.h deleted file mode 100644 index f3618a9f..00000000 --- a/src/helpers/sensors/INA3221Sensor.h +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once - -#include -#include - -#define TELEM_INA3221_ADDRESS 0x42 // INA3221 3 channel current sensor I2C address -#define TELEM_INA3221_SHUNT_VALUE 0.100 // most variants will have a 0.1 ohm shunts - -#define NUM_CHANNELS 3 - -static INA3221 INA_3221(TELEM_INA3221_ADDRESS, &Wire); - -class INA3221Sensor { - bool initialized = false; - -public: - void begin() { - if (INA_3221.begin()) { - MESH_DEBUG_PRINTLN("Found INA3221 at address: %02X", INA_3221.getAddress()); - MESH_DEBUG_PRINTLN("%04X %04X %04X", INA_3221.getDieID(), INA_3221.getManufacturerID(), INA_3221.getConfiguration()); - - for(int i = 0; i < 3; i++) { - INA_3221.setShuntR(i, TELEM_INA3221_SHUNT_VALUE); - } - initialized = true; - } else { - initialized = false; - MESH_DEBUG_PRINTLN("INA3221 was not found at I2C address %02X", TELEM_INA3221_ADDRESS); - } - } - - bool isInitialized() const { return initialized; } - - int numChannels() const { return NUM_CHANNELS; } - - float getVoltage(int channel) const { - if (initialized && channel >=0 && channel < NUM_CHANNELS) { - return INA_3221.getBusVoltage(channel); - } - return 0; - } - - float getCurrent(int channel) const { - if (initialized && channel >=0 && channel < NUM_CHANNELS) { - return INA_3221.getCurrent(channel); - } - return 0; - } - - float getPower (int channel) const { - if (initialized && channel >=0 && channel < NUM_CHANNELS) { - return INA_3221.getPower(channel); - } - return 0; - } - - bool setChannelEnabled(int channel, bool enabled) { - if (initialized && channel >=0 && channel < NUM_CHANNELS) { - INA_3221.enableChannel(channel); - return true; - } - return false; - } - - bool getChannelEnabled(int channel) const { - if (initialized && channel >=0 && channel < NUM_CHANNELS) { - return INA_3221.getEnableChannel(channel); - } - return false; - } -}; diff --git a/variants/promicro/platformio.ini b/variants/promicro/platformio.ini index 7b6771e0..e70223e2 100644 --- a/variants/promicro/platformio.ini +++ b/variants/promicro/platformio.ini @@ -19,10 +19,10 @@ build_src_filter = ${nrf52840_base.build_src_filter} +<../variants/promicro> lib_deps= ${nrf52840_base.lib_deps} adafruit/Adafruit SSD1306 @ ^2.5.13 - robtillaart/INA3221 @ ^0.4.1 - robtillaart/INA219 @ ^0.4.1 - adafruit/Adafruit AHTX0@^2.0.5 - adafruit/Adafruit BME280 Library@^2.3.0 + adafruit/Adafruit INA3221 Library @ ^1.0.1 + adafruit/Adafruit INA219 @ ^1.2.3 + adafruit/Adafruit AHTX0 @ ^2.0.5 + adafruit/Adafruit BME280 Library @ ^2.3.0 [env:Faketec_Repeater] extends = Faketec @@ -124,9 +124,10 @@ build_src_filter = + +<../variants/promicro> lib_deps= ${nrf52840_base.lib_deps} - robtillaart/INA3221 @ ^0.4.1 - robtillaart/INA219 @ ^0.4.1 - adafruit/Adafruit AHTX0@^2.0.5 + adafruit/Adafruit INA3221 Library @ ^1.0.1 + adafruit/Adafruit INA219 @ ^1.2.3 + adafruit/Adafruit AHTX0 @ ^2.0.5 + adafruit/Adafruit BME280 Library @ ^2.3.0 [env:ProMicroLLCC68_Repeater] extends = ProMicroLLCC68 From af0d55548c46f7085813e068e19d987319b68128 Mon Sep 17 00:00:00 2001 From: Normunds Gavars Date: Thu, 22 May 2025 00:22:43 +0300 Subject: [PATCH 14/41] Remove unused defines --- src/helpers/sensors/EnvironmentSensorManager.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/helpers/sensors/EnvironmentSensorManager.h b/src/helpers/sensors/EnvironmentSensorManager.h index 2852805a..e335a413 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.h +++ b/src/helpers/sensors/EnvironmentSensorManager.h @@ -17,9 +17,6 @@ #define TELEM_INA3221_SHUNT_VALUE 0.100 // most variants will have a 0.1 ohm shunts #define TELEM_INA3221_NUM_CHANNELS 3 -#define TELEM_INA219_SHUNT_VALUE 0.100 // shunt value in ohms (may differ between manufacturers) -#define TELEM_INA219_MAX_CURRENT 5 - #define TELEM_BME280_SEALEVELPRESSURE_HPA (1013.25) // Athmospheric pressure at sea level class EnvironmentSensorManager : public SensorManager { From 375a31a436b15468a8c7da2018173293658e530f Mon Sep 17 00:00:00 2001 From: Normunds Gavars Date: Thu, 22 May 2025 00:28:20 +0300 Subject: [PATCH 15/41] Remove INA219 wrapper --- src/helpers/sensors/INA219Sensor.h | 48 ------------------------------ 1 file changed, 48 deletions(-) delete mode 100644 src/helpers/sensors/INA219Sensor.h diff --git a/src/helpers/sensors/INA219Sensor.h b/src/helpers/sensors/INA219Sensor.h deleted file mode 100644 index 1f641ab2..00000000 --- a/src/helpers/sensors/INA219Sensor.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include -#include - -#define TELEM_INA219_ADDRESS 0x40 // INA219 single channel current sensor I2C address -#define TELEM_INA219_SHUNT_VALUE 0.100 // shunt value in ohms (may differ between manufacturers) -#define TELEM_INA219_MAX_CURRENT 5 - -static INA219 INA_219(TELEM_INA219_ADDRESS, &Wire); - -class INA219Sensor { - bool initialized = false; -public: - void begin() { - if (INA_219.begin()) { - MESH_DEBUG_PRINTLN("Found INA219 at address: %02X", INA_219.getAddress()); - INA_219.setMaxCurrentShunt(TELEM_INA219_MAX_CURRENT, TELEM_INA219_SHUNT_VALUE); - initialized = true; - } else { - initialized = false; - MESH_DEBUG_PRINTLN("INA219 was not found at I2C address %02X", TELEM_INA219_ADDRESS); - } - } - - bool isInitialized() const { return initialized; } - - float getVoltage() const { - if (initialized) { - return INA_219.getBusVoltage(); - } - return 0; - } - - float getCurrent() const { - if (initialized) { - return INA_219.getCurrent(); - } - return 0; - } - - float getPower() const { - if (initialized) { - return INA_219.getPower(); - } - return 0; - } -}; From 5a0ac2a0310c67ea56b0e30a9fb6a8623f0066db Mon Sep 17 00:00:00 2001 From: Normunds Gavars Date: Thu, 22 May 2025 00:35:03 +0300 Subject: [PATCH 16/41] Add sensors to build path for ProMicroLLCC68 --- variants/promicro/platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/variants/promicro/platformio.ini b/variants/promicro/platformio.ini index e70223e2..568e20d7 100644 --- a/variants/promicro/platformio.ini +++ b/variants/promicro/platformio.ini @@ -122,6 +122,7 @@ build_flags = ${nrf52840_base.build_flags} build_src_filter = ${nrf52840_base.build_src_filter} + + + +<../variants/promicro> lib_deps= ${nrf52840_base.lib_deps} adafruit/Adafruit INA3221 Library @ ^1.0.1 From c4df0ed1c55522871d7915d89ad29e04757d1a7a Mon Sep 17 00:00:00 2001 From: Normunds Gavars Date: Thu, 22 May 2025 00:38:51 +0300 Subject: [PATCH 17/41] Remove NUM_SENSOR_SETTINGS --- src/helpers/sensors/EnvironmentSensorManager.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/helpers/sensors/EnvironmentSensorManager.h b/src/helpers/sensors/EnvironmentSensorManager.h index e335a413..fa3a1a1e 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.h +++ b/src/helpers/sensors/EnvironmentSensorManager.h @@ -7,8 +7,6 @@ #include #include -#define NUM_SENSOR_SETTINGS 3 - #define TELEM_AHTX_ADDRESS 0x38 // AHT10, AHT20 temperature and humidity sensor I2C address #define TELEM_BME280_ADDRESS 0x76 // BME280 environmental sensor I2C address #define TELEM_INA3221_ADDRESS 0x42 // INA3221 3 channel current sensor I2C address From 02b6f4a2856cdc4b2fad4d675d8444637aa92e81 Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Thu, 22 May 2025 15:26:30 +1000 Subject: [PATCH 18/41] * Companion: telemetry_mode_env added to prefs --- examples/companion_radio/NodePrefs.h | 1 + examples/companion_radio/main.cpp | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/examples/companion_radio/NodePrefs.h b/examples/companion_radio/NodePrefs.h index 2f209c54..09d04266 100644 --- a/examples/companion_radio/NodePrefs.h +++ b/examples/companion_radio/NodePrefs.h @@ -19,6 +19,7 @@ struct NodePrefs { // persisted to file uint8_t tx_power_dbm; uint8_t telemetry_mode_base; uint8_t telemetry_mode_loc; + uint8_t telemetry_mode_env; float rx_delay_base; uint32_t ble_pin; }; diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index ecf03b6a..03a8c90a 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -661,6 +661,12 @@ protected: permissions |= cp & TELEM_PERM_LOCATION; } + if (_prefs.telemetry_mode_env == TELEM_MODE_ALLOW_ALL) { + permissions |= TELEM_PERM_ENVIRONMENT; + } else if (_prefs.telemetry_mode_env == TELEM_MODE_ALLOW_FLAGS) { + permissions |= cp & TELEM_PERM_ENVIRONMENT; + } + if (permissions & TELEM_PERM_BASE) { // only respond if base permission bit is set telemetry.reset(); telemetry.addVoltage(TELEM_CHANNEL_SELF, (float)board.getBattMilliVolts() / 1000.0f); @@ -824,7 +830,7 @@ public: file.read((uint8_t *) &_prefs.tx_power_dbm, sizeof(_prefs.tx_power_dbm)); // 68 file.read((uint8_t *) &_prefs.telemetry_mode_base, sizeof(_prefs.telemetry_mode_base)); // 69 file.read((uint8_t *) &_prefs.telemetry_mode_loc, sizeof(_prefs.telemetry_mode_loc)); // 70 - file.read(pad, 1); // 71 + file.read((uint8_t *) &_prefs.telemetry_mode_env, sizeof(_prefs.telemetry_mode_env)); // 71 file.read((uint8_t *) &_prefs.rx_delay_base, sizeof(_prefs.rx_delay_base)); // 72 file.read(pad, 4); // 76 file.read((uint8_t *) &_prefs.ble_pin, sizeof(_prefs.ble_pin)); // 80 @@ -945,7 +951,7 @@ public: file.write((uint8_t *) &_prefs.tx_power_dbm, sizeof(_prefs.tx_power_dbm)); // 68 file.write((uint8_t *) &_prefs.telemetry_mode_base, sizeof(_prefs.telemetry_mode_base)); // 69 file.write((uint8_t *) &_prefs.telemetry_mode_loc, sizeof(_prefs.telemetry_mode_loc)); // 70 - file.write(pad, 1); // 71 + file.write((uint8_t *) &_prefs.telemetry_mode_env, sizeof(_prefs.telemetry_mode_env)); // 71 file.write((uint8_t *) &_prefs.rx_delay_base, sizeof(_prefs.rx_delay_base)); // 72 file.write(pad, 4); // 76 file.write((uint8_t *) &_prefs.ble_pin, sizeof(_prefs.ble_pin)); // 80 @@ -990,7 +996,7 @@ public: memcpy(&out_frame[i], &lon, 4); i += 4; out_frame[i++] = 0; // reserved out_frame[i++] = 0; // reserved - out_frame[i++] = (_prefs.telemetry_mode_loc << 2) | (_prefs.telemetry_mode_base); // v5+ + out_frame[i++] = (_prefs.telemetry_mode_env << 4) | (_prefs.telemetry_mode_loc << 2) | (_prefs.telemetry_mode_base); // v5+ out_frame[i++] = _prefs.manual_add_contacts; uint32_t freq = _prefs.freq * 1000; @@ -1282,6 +1288,7 @@ public: if (len >= 3) { _prefs.telemetry_mode_base = cmd_frame[2] & 0x03; // v5+ _prefs.telemetry_mode_loc = (cmd_frame[2] >> 2) & 0x03; + _prefs.telemetry_mode_env = (cmd_frame[2] >> 4) & 0x03; } savePrefs(); writeOKFrame(); From a466d3cf80d91ab7a16e882dd7ba29af6dce81b9 Mon Sep 17 00:00:00 2001 From: taco Date: Thu, 22 May 2025 15:36:20 +1000 Subject: [PATCH 19/41] added serial GPS support to EnvironmentSensorClass based on T114 serial GPS and EnvironmentSensorClass. --- .../sensors/EnvironmentSensorManager.cpp | 93 ++++++++++++++++++- .../sensors/EnvironmentSensorManager.h | 19 +++- variants/promicro/platformio.ini | 6 +- variants/promicro/target.cpp | 4 +- 4 files changed, 117 insertions(+), 5 deletions(-) diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp index 6d39e905..c82235c6 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.cpp +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -1,5 +1,8 @@ #include "EnvironmentSensorManager.h" + +#include + static Adafruit_AHTX0 AHTX0; static Adafruit_BME280 BME280; static Adafruit_INA3221 INA3221; @@ -44,11 +47,14 @@ bool EnvironmentSensorManager::begin() { BME280_initialized = false; MESH_DEBUG_PRINTLN("BME280 was not found at I2C address %02X", TELEM_BME280_ADDRESS); } - + initSerialGPS(); return true; } bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { + if (requester_permissions & TELEM_PERM_LOCATION) { // does requester have permission? + telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, 0.0f); + } next_available_channel = TELEM_CHANNEL_SELF + 1; if (requester_permissions & TELEM_PERM_ENVIRONMENT) { if (INA3221_initialized) { @@ -86,5 +92,90 @@ bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, Cayen } } + initSerialGPS(); + return true; +} + + +int EnvironmentSensorManager::getNumSettings() const { + return gps_detected ? 1 : 0; // only show GPS setting if GPS is detected +} + +const char* EnvironmentSensorManager::getSettingName(int i) const { + return (gps_detected && i == 0) ? "gps" : NULL; +} + +const char* EnvironmentSensorManager::getSettingValue(int i) const { + if (gps_detected && i == 0) { + return gps_active ? "1" : "0"; + } + return NULL; +} + +bool EnvironmentSensorManager::setSettingValue(const char* name, const char* value) { + if (gps_detected && strcmp(name, "gps") == 0) { + if (strcmp(value, "0") == 0) { + stop_gps(); + } else { + start_gps(); + } + return true; + } + return false; // not supported +} + + + + +void EnvironmentSensorManager::initSerialGPS() { + Serial1.setPins(PIN_GPS_TX, PIN_GPS_RX); + Serial1.begin(9600); + + // Try to detect if GPS is physically connected to determine if we should expose the setting + pinMode(PIN_GPS_EN, OUTPUT); + digitalWrite(PIN_GPS_EN, HIGH); // Power on GPS + + // Give GPS a moment to power up and send data + delay(1000); + + // We'll consider GPS detected if we see any data on Serial1 + gps_detected = (Serial1.available() > 0); + + if (gps_detected) { + MESH_DEBUG_PRINTLN("GPS detected"); + digitalWrite(PIN_GPS_EN, LOW); // Power off GPS until the setting is changed + } else { + MESH_DEBUG_PRINTLN("No GPS detected"); + digitalWrite(PIN_GPS_EN, LOW); + } + +} + + +void EnvironmentSensorManager::start_gps() { + gps_active = true; + pinMode(PIN_GPS_EN, OUTPUT); + digitalWrite(PIN_GPS_EN, HIGH); +} + +void EnvironmentSensorManager::stop_gps() { + gps_active = false; + pinMode(PIN_GPS_EN, OUTPUT); + digitalWrite(PIN_GPS_EN, LOW); +} + +void EnvironmentSensorManager::loop() { + static long next_gps_update = 0; + + _location->loop(); + + if (millis() > next_gps_update) { + if (_location->isValid()) { + node_lat = ((double)_location->getLatitude())/1000000.; + node_lon = ((double)_location->getLongitude())/1000000.; + MESH_DEBUG_PRINTLN("lat %f lon %f", node_lat, node_lon); + } + next_gps_update = millis() + 1000; + } } \ No newline at end of file diff --git a/src/helpers/sensors/EnvironmentSensorManager.h b/src/helpers/sensors/EnvironmentSensorManager.h index fa3a1a1e..51ac3051 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.h +++ b/src/helpers/sensors/EnvironmentSensorManager.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -25,8 +26,22 @@ protected: bool INA219_initialized = false; bool BME280_initialized = false; bool AHTX0_initialized = false; + + bool gps_active = false; + bool gps_detected = false; + LocationProvider* _location; + + void start_gps(); + void stop_gps(); + void initSerialGPS(); + public: - EnvironmentSensorManager(){}; + EnvironmentSensorManager(LocationProvider &location): _location(&location){}; bool begin() override; - bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override; + bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override; + void loop() override; + int getNumSettings() const override; + const char* getSettingName(int i) const override; + const char* getSettingValue(int i) const override; + bool setSettingValue(const char* name, const char* value) override; }; diff --git a/variants/promicro/platformio.ini b/variants/promicro/platformio.ini index 568e20d7..9e2ee075 100644 --- a/variants/promicro/platformio.ini +++ b/variants/promicro/platformio.ini @@ -13,6 +13,9 @@ build_flags = ${nrf52840_base.build_flags} -D PIN_BOARD_SDA=8 -D PIN_OLED_RESET=-1 -D PIN_USER_BTN=6 + -D PIN_GPS_RX=3 + -D PIN_GPS_TX=4 + -D PIN_GPS_EN=5 build_src_filter = ${nrf52840_base.build_src_filter} + + @@ -23,7 +26,8 @@ lib_deps= ${nrf52840_base.lib_deps} adafruit/Adafruit INA219 @ ^1.2.3 adafruit/Adafruit AHTX0 @ ^2.0.5 adafruit/Adafruit BME280 Library @ ^2.3.0 - + stevemarple/MicroNMEA @ ^2.0.6 + [env:Faketec_Repeater] extends = Faketec build_src_filter = ${Faketec.build_src_filter} diff --git a/variants/promicro/target.cpp b/variants/promicro/target.cpp index 841bd1dc..666f43f5 100644 --- a/variants/promicro/target.cpp +++ b/variants/promicro/target.cpp @@ -1,6 +1,7 @@ #include #include "target.h" #include +#include PromicroBoard board; @@ -10,7 +11,8 @@ WRAPPER_CLASS radio_driver(radio, board); VolatileRTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); -EnvironmentSensorManager sensors; +MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); +EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea); #ifdef DISPLAY_CLASS DISPLAY_CLASS display; From 1d94df1d048d9f2476db41fa7a4a501150dd481d Mon Sep 17 00:00:00 2001 From: Memo <58190287+memo-567@users.noreply.github.com> Date: Thu, 22 May 2025 12:06:34 +0000 Subject: [PATCH 20/41] Update platformio.ini --- variants/heltec_v3/platformio.ini | 35 +++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/variants/heltec_v3/platformio.ini b/variants/heltec_v3/platformio.ini index 0814ad4d..0b7ea006 100644 --- a/variants/heltec_v3/platformio.ini +++ b/variants/heltec_v3/platformio.ini @@ -19,9 +19,14 @@ build_flags = -D SX126X_RX_BOOSTED_GAIN=1 build_src_filter = ${esp32_base.build_src_filter} +<../variants/heltec_v3> + + lib_deps = ${esp32_base.lib_deps} adafruit/Adafruit SSD1306 @ ^2.5.13 + adafruit/Adafruit INA3221 Library @ ^1.0.1 + adafruit/Adafruit INA219 @ ^1.2.3 + adafruit/Adafruit AHTX0 @ ^2.0.5 + adafruit/Adafruit BME280 Library @ ^2.3.0 [env:Heltec_v3_repeater] extends = Heltec_lora32_v3 @@ -38,9 +43,14 @@ build_flags = build_src_filter = ${Heltec_lora32_v3.build_src_filter} + +<../examples/simple_repeater> + + lib_deps = ${Heltec_lora32_v3.lib_deps} ${esp32_ota.lib_deps} + adafruit/Adafruit INA3221 Library @ ^1.0.1 + adafruit/Adafruit INA219 @ ^1.2.3 + adafruit/Adafruit AHTX0 @ ^2.0.5 + adafruit/Adafruit BME280 Library @ ^2.3.0 [env:Heltec_v3_room_server] extends = Heltec_lora32_v3 @@ -57,9 +67,14 @@ build_flags = build_src_filter = ${Heltec_lora32_v3.build_src_filter} + +<../examples/simple_room_server> + + lib_deps = ${Heltec_lora32_v3.lib_deps} ${esp32_ota.lib_deps} + adafruit/Adafruit INA3221 Library @ ^1.0.1 + adafruit/Adafruit INA219 @ ^1.2.3 + adafruit/Adafruit AHTX0 @ ^2.0.5 + adafruit/Adafruit BME280 Library @ ^2.3.0 [env:Heltec_v3_terminal_chat] extends = Heltec_lora32_v3 @@ -71,9 +86,14 @@ build_flags = ; -D MESH_DEBUG=1 build_src_filter = ${Heltec_lora32_v3.build_src_filter} +<../examples/simple_secure_chat/main.cpp> + + lib_deps = ${Heltec_lora32_v3.lib_deps} densaugeo/base64 @ ~1.4.0 + adafruit/Adafruit INA3221 Library @ ^1.0.1 + adafruit/Adafruit INA219 @ ^1.2.3 + adafruit/Adafruit AHTX0 @ ^2.0.5 + adafruit/Adafruit BME280 Library @ ^2.3.0 [env:Heltec_v3_companion_radio_usb] extends = Heltec_lora32_v3 @@ -89,9 +109,14 @@ build_flags = build_src_filter = ${Heltec_lora32_v3.build_src_filter} + +<../examples/companion_radio> + + lib_deps = ${Heltec_lora32_v3.lib_deps} densaugeo/base64 @ ~1.4.0 + adafruit/Adafruit INA3221 Library @ ^1.0.1 + adafruit/Adafruit INA219 @ ^1.2.3 + adafruit/Adafruit AHTX0 @ ^2.0.5 + adafruit/Adafruit BME280 Library @ ^2.3.0 [env:Heltec_v3_companion_radio_ble] extends = Heltec_lora32_v3 @@ -111,9 +136,14 @@ build_src_filter = ${Heltec_lora32_v3.build_src_filter} + + +<../examples/companion_radio> + + lib_deps = ${Heltec_lora32_v3.lib_deps} densaugeo/base64 @ ~1.4.0 + adafruit/Adafruit INA3221 Library @ ^1.0.1 + adafruit/Adafruit INA219 @ ^1.2.3 + adafruit/Adafruit AHTX0 @ ^2.0.5 + adafruit/Adafruit BME280 Library @ ^2.3.0 [env:Heltec_v3_companion_radio_wifi] extends = Heltec_lora32_v3 @@ -133,9 +163,14 @@ build_src_filter = ${Heltec_lora32_v3.build_src_filter} + + +<../examples/companion_radio> + + lib_deps = ${Heltec_lora32_v3.lib_deps} densaugeo/base64 @ ~1.4.0 + adafruit/Adafruit INA3221 Library @ ^1.0.1 + adafruit/Adafruit INA219 @ ^1.2.3 + adafruit/Adafruit AHTX0 @ ^2.0.5 + adafruit/Adafruit BME280 Library @ ^2.3.0 [env:Heltec_WSL3_repeater] extends = Heltec_lora32_v3 From 648953ce8d5ed8d3e63c51f5376592df38d771be Mon Sep 17 00:00:00 2001 From: Memo <58190287+memo-567@users.noreply.github.com> Date: Thu, 22 May 2025 12:07:06 +0000 Subject: [PATCH 21/41] Update target.cpp --- variants/heltec_v3/target.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variants/heltec_v3/target.cpp b/variants/heltec_v3/target.cpp index ab9b709f..be99a1e3 100644 --- a/variants/heltec_v3/target.cpp +++ b/variants/heltec_v3/target.cpp @@ -14,7 +14,7 @@ WRAPPER_CLASS radio_driver(radio, board); ESP32RTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); -SensorManager sensors; +EnvironmentSensorManager sensors; #ifdef DISPLAY_CLASS DISPLAY_CLASS display; From 0caa2b4cd1b9ed45262539ee9e95c9cec76a0bc3 Mon Sep 17 00:00:00 2001 From: Memo <58190287+memo-567@users.noreply.github.com> Date: Thu, 22 May 2025 12:07:45 +0000 Subject: [PATCH 22/41] Update target.h --- variants/heltec_v3/target.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/variants/heltec_v3/target.h b/variants/heltec_v3/target.h index 76ad58a7..701f9cd5 100644 --- a/variants/heltec_v3/target.h +++ b/variants/heltec_v3/target.h @@ -7,6 +7,7 @@ #include #include #include +#include #ifdef DISPLAY_CLASS #include #endif @@ -14,7 +15,7 @@ extern HeltecV3Board board; extern WRAPPER_CLASS radio_driver; extern AutoDiscoverRTCClock rtc_clock; -extern SensorManager sensors; +extern EnvironmentSensorManager sensors; #ifdef DISPLAY_CLASS extern DISPLAY_CLASS display; From f9473235c618306fcba5284a6b948bba3a3c4ad1 Mon Sep 17 00:00:00 2001 From: Florent Date: Thu, 22 May 2025 11:46:05 +0200 Subject: [PATCH 23/41] rak3x72 : first commit --- boards/rak3172.json | 33 ++++++++++++ src/helpers/stm32/InternalFileSystem.cpp | 3 ++ variants/rak3x72/platformio.ini | 33 ++++++++++++ variants/rak3x72/target.cpp | 67 ++++++++++++++++++++++++ variants/rak3x72/target.h | 27 ++++++++++ variants/rak3x72/variant.h | 5 ++ variants/wio-e5/platformio.ini | 5 +- variants/wio-e5/target.cpp | 8 ++- variants/wio-e5/target.h | 9 +++- 9 files changed, 185 insertions(+), 5 deletions(-) create mode 100644 boards/rak3172.json create mode 100644 variants/rak3x72/platformio.ini create mode 100644 variants/rak3x72/target.cpp create mode 100644 variants/rak3x72/target.h create mode 100644 variants/rak3x72/variant.h diff --git a/boards/rak3172.json b/boards/rak3172.json new file mode 100644 index 00000000..dbb70b03 --- /dev/null +++ b/boards/rak3172.json @@ -0,0 +1,33 @@ +{ + "build": { + "arduino": { + "variant_h": "variant_RAK3172_MODULE.h" + }, + "core": "stm32", + "cpu": "cortex-m4", + "extra_flags": "-DSTM32WL -DSTM32WLxx -DSTM32WLE5xx", + "framework_extra_flags": { + "arduino": "-DUSE_CM4_STARTUP_FILE -DARDUINO_RAK3172_MODULE" + }, + "f_cpu": "48000000L", + "mcu": "stm32wle5ccu", + "product_line": "STM32WLE5xx", + "variant": "STM32WLxx/WL54CCU_WL55CCU_WLE4C(8-B-C)U_WLE5C(8-B-C)U" + }, + "debug": { + "default_tools": ["stlink"], + "jlink_device": "STM32WLE5CC", + "openocd_target": "stm32wlx", + "svd_path": "STM32WLE5_CM4.svd" + }, + "frameworks": ["arduino"], + "name": "BB-STM32WL", + "upload": { + "maximum_ram_size": 65536, + "maximum_size": 262144, + "protocol": "stlink", + "protocols": ["stlink", "jlink"] + }, + "url": "https://store.rakwireless.com/products/wisduo-lpwan-module-rak3172", + "vendor": "RAK" +} diff --git a/src/helpers/stm32/InternalFileSystem.cpp b/src/helpers/stm32/InternalFileSystem.cpp index 47706bac..2714ec6b 100644 --- a/src/helpers/stm32/InternalFileSystem.cpp +++ b/src/helpers/stm32/InternalFileSystem.cpp @@ -126,6 +126,9 @@ InternalFileSystem::InternalFileSystem(void) bool InternalFileSystem::begin(void) { + #ifdef FORMAT_FS + this->format(); + #endif // failed to mount, erase all sector then format and mount again if ( !Adafruit_LittleFS::begin() ) { diff --git a/variants/rak3x72/platformio.ini b/variants/rak3x72/platformio.ini new file mode 100644 index 00000000..94e8f595 --- /dev/null +++ b/variants/rak3x72/platformio.ini @@ -0,0 +1,33 @@ +[rak3x72] +extends = stm32_base +board = rak3172 +board_upload.maximum_size = 229376 ; 32kb for FS +build_flags = ${stm32_base.build_flags} + -D RADIO_CLASS=CustomSTM32WLx + -D WRAPPER_CLASS=CustomSTM32WLxWrapper + -D SPI_INTERFACES_COUNT=0 + -D RX_BOOSTED_GAIN=true + -I variants/rak3x72 +build_src_filter = ${stm32_base.build_src_filter} + +<../variants/rak3x72> + +[env:rak3x72-repeater] +extends = rak3x72 +build_flags = ${rak3x72.build_flags} + -D LORA_TX_POWER=22 + -D ADVERT_NAME='"RAK3x72 Repeater"' + -D ADMIN_PASSWORD='"password"' +build_src_filter = ${rak3x72.build_src_filter} + +<../examples/simple_repeater/main.cpp> + +[env:rak3x72_companion_radio_usb] +extends = rak3x72 +build_flags = ${rak3x72.build_flags} +; -D FORMAT_FS=true + -D LORA_TX_POWER=22 + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 +build_src_filter = ${rak3x72.build_src_filter} + +<../examples/companion_radio/*.cpp> +lib_deps = ${rak3x72.lib_deps} + densaugeo/base64 @ ~1.4.0 diff --git a/variants/rak3x72/target.cpp b/variants/rak3x72/target.cpp new file mode 100644 index 00000000..4cb5929a --- /dev/null +++ b/variants/rak3x72/target.cpp @@ -0,0 +1,67 @@ +#include +#include "target.h" +#include + +RAK3x72Board board; + +RADIO_CLASS radio = new STM32WLx_Module(); + +WRAPPER_CLASS radio_driver(radio, board); + +static const uint32_t rfswitch_pins[] = {LORAWAN_RFSWITCH_PINS, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC}; +static const Module::RfSwitchMode_t rfswitch_table[] = { + {STM32WLx::MODE_IDLE, {LOW, LOW}}, + {STM32WLx::MODE_RX, {HIGH, LOW}}, + {STM32WLx::MODE_TX_LP, {LOW, HIGH}}, + {STM32WLx::MODE_TX_HP, {LOW, HIGH}}, + END_OF_MODE_TABLE, +}; + +VolatileRTCClock rtc_clock; +SensorManager sensors; + +#ifndef LORA_CR + #define LORA_CR 5 +#endif + +bool radio_init() { +// rtc_clock.begin(Wire); + + radio.setRfSwitchTable(rfswitch_pins, rfswitch_table); + + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, 0, 0); // TCXO set to 0 for RAK3172 + + if (status != RADIOLIB_ERR_NONE) { + Serial.print("ERROR: radio init failed: "); + Serial.println(status); + return false; // fail + } + + #ifdef RX_BOOSTED_GAIN + radio.setRxBoostedGainMode(RX_BOOSTED_GAIN); + #endif + + radio.setCRC(1); + + return true; // success +} + +uint32_t radio_get_rng_seed() { + return radio.random(0x7FFFFFFF); +} + +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { + radio.setFrequency(freq); + radio.setSpreadingFactor(sf); + radio.setBandwidth(bw); + radio.setCodingRate(cr); +} + +void radio_set_tx_power(uint8_t dbm) { + radio.setOutputPower(dbm); +} + +mesh::LocalIdentity radio_new_identity() { + RadioNoiseListener rng(radio); + return mesh::LocalIdentity(&rng); // create new random identity +} diff --git a/variants/rak3x72/target.h b/variants/rak3x72/target.h new file mode 100644 index 00000000..a4c47bc6 --- /dev/null +++ b/variants/rak3x72/target.h @@ -0,0 +1,27 @@ +#pragma once + +#define RADIOLIB_STATIC_ONLY 1 +#include +#include +#include +#include +#include +#include + +class RAK3x72Board : public STM32Board { +public: + const char* getManufacturerName() const override { + return "RAK 3x72"; + } +}; + +extern RAK3x72Board board; +extern WRAPPER_CLASS radio_driver; +extern VolatileRTCClock rtc_clock; +extern SensorManager sensors; + +bool radio_init(); +uint32_t radio_get_rng_seed(); +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); +void radio_set_tx_power(uint8_t dbm); +mesh::LocalIdentity radio_new_identity(); diff --git a/variants/rak3x72/variant.h b/variants/rak3x72/variant.h new file mode 100644 index 00000000..4405be0b --- /dev/null +++ b/variants/rak3x72/variant.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +#undef RNG diff --git a/variants/wio-e5/platformio.ini b/variants/wio-e5/platformio.ini index 4de13e7f..d8f7954f 100644 --- a/variants/wio-e5/platformio.ini +++ b/variants/wio-e5/platformio.ini @@ -6,6 +6,7 @@ build_flags = ${stm32_base.build_flags} -D RADIO_CLASS=CustomSTM32WLx -D WRAPPER_CLASS=CustomSTM32WLxWrapper -D SPI_INTERFACES_COUNT=0 + -D RX_BOOSTED_GAIN=true -I variants/wio-e5 build_src_filter = ${stm32_base.build_src_filter} +<../variants/wio-e5> @@ -13,7 +14,7 @@ build_src_filter = ${stm32_base.build_src_filter} [env:wio-e5-repeater] extends = lora_e5 build_flags = ${lora_e5.build_flags} - -D LORA_TX_POWER=20 + -D LORA_TX_POWER=22 -D ADVERT_NAME='"WIO-E5 Repeater"' -D ADMIN_PASSWORD='"password"' build_src_filter = ${lora_e5.build_src_filter} @@ -22,7 +23,7 @@ build_src_filter = ${lora_e5.build_src_filter} [env:wio-e5_companion_radio_usb] extends = lora_e5 build_flags = ${lora_e5.build_flags} - -D LORA_TX_POWER=20 + -D LORA_TX_POWER=22 -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 build_src_filter = ${lora_e5.build_src_filter} diff --git a/variants/wio-e5/target.cpp b/variants/wio-e5/target.cpp index aee0dafb..8ccbe384 100644 --- a/variants/wio-e5/target.cpp +++ b/variants/wio-e5/target.cpp @@ -2,7 +2,7 @@ #include "target.h" #include -STM32Board board; +WIOE5Board board; RADIO_CLASS radio = new STM32WLx_Module(); @@ -42,7 +42,11 @@ bool radio_init() { Serial.println(status); return false; // fail } - + + #ifdef RX_BOOSTED_GAIN + radio.setRxBoostedGainMode(RX_BOOSTED_GAIN); + #endif + radio.setCRC(1); return true; // success diff --git a/variants/wio-e5/target.h b/variants/wio-e5/target.h index f2dae108..cc6131cf 100644 --- a/variants/wio-e5/target.h +++ b/variants/wio-e5/target.h @@ -8,7 +8,14 @@ #include #include -extern STM32Board board; +class WIOE5Board : public STM32Board { +public: + const char* getManufacturerName() const override { + return "Seeed Wio E5"; + } +}; + +extern WIOE5Board board; extern WRAPPER_CLASS radio_driver; extern VolatileRTCClock rtc_clock; extern SensorManager sensors; From cd7fc59f067e30ce34d3aeb381b16c09066cfa9c Mon Sep 17 00:00:00 2001 From: Memo <58190287+memo-567@users.noreply.github.com> Date: Thu, 22 May 2025 13:24:26 +0000 Subject: [PATCH 24/41] Update platformio.ini --- variants/heltec_v3/platformio.ini | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/variants/heltec_v3/platformio.ini b/variants/heltec_v3/platformio.ini index 0b7ea006..9f4c23c1 100644 --- a/variants/heltec_v3/platformio.ini +++ b/variants/heltec_v3/platformio.ini @@ -47,10 +47,6 @@ build_src_filter = ${Heltec_lora32_v3.build_src_filter} lib_deps = ${Heltec_lora32_v3.lib_deps} ${esp32_ota.lib_deps} - adafruit/Adafruit INA3221 Library @ ^1.0.1 - adafruit/Adafruit INA219 @ ^1.2.3 - adafruit/Adafruit AHTX0 @ ^2.0.5 - adafruit/Adafruit BME280 Library @ ^2.3.0 [env:Heltec_v3_room_server] extends = Heltec_lora32_v3 @@ -71,10 +67,6 @@ build_src_filter = ${Heltec_lora32_v3.build_src_filter} lib_deps = ${Heltec_lora32_v3.lib_deps} ${esp32_ota.lib_deps} - adafruit/Adafruit INA3221 Library @ ^1.0.1 - adafruit/Adafruit INA219 @ ^1.2.3 - adafruit/Adafruit AHTX0 @ ^2.0.5 - adafruit/Adafruit BME280 Library @ ^2.3.0 [env:Heltec_v3_terminal_chat] extends = Heltec_lora32_v3 @@ -90,10 +82,6 @@ build_src_filter = ${Heltec_lora32_v3.build_src_filter} lib_deps = ${Heltec_lora32_v3.lib_deps} densaugeo/base64 @ ~1.4.0 - adafruit/Adafruit INA3221 Library @ ^1.0.1 - adafruit/Adafruit INA219 @ ^1.2.3 - adafruit/Adafruit AHTX0 @ ^2.0.5 - adafruit/Adafruit BME280 Library @ ^2.3.0 [env:Heltec_v3_companion_radio_usb] extends = Heltec_lora32_v3 @@ -113,10 +101,6 @@ build_src_filter = ${Heltec_lora32_v3.build_src_filter} lib_deps = ${Heltec_lora32_v3.lib_deps} densaugeo/base64 @ ~1.4.0 - adafruit/Adafruit INA3221 Library @ ^1.0.1 - adafruit/Adafruit INA219 @ ^1.2.3 - adafruit/Adafruit AHTX0 @ ^2.0.5 - adafruit/Adafruit BME280 Library @ ^2.3.0 [env:Heltec_v3_companion_radio_ble] extends = Heltec_lora32_v3 @@ -140,10 +124,6 @@ build_src_filter = ${Heltec_lora32_v3.build_src_filter} lib_deps = ${Heltec_lora32_v3.lib_deps} densaugeo/base64 @ ~1.4.0 - adafruit/Adafruit INA3221 Library @ ^1.0.1 - adafruit/Adafruit INA219 @ ^1.2.3 - adafruit/Adafruit AHTX0 @ ^2.0.5 - adafruit/Adafruit BME280 Library @ ^2.3.0 [env:Heltec_v3_companion_radio_wifi] extends = Heltec_lora32_v3 @@ -167,10 +147,6 @@ build_src_filter = ${Heltec_lora32_v3.build_src_filter} lib_deps = ${Heltec_lora32_v3.lib_deps} densaugeo/base64 @ ~1.4.0 - adafruit/Adafruit INA3221 Library @ ^1.0.1 - adafruit/Adafruit INA219 @ ^1.2.3 - adafruit/Adafruit AHTX0 @ ^2.0.5 - adafruit/Adafruit BME280 Library @ ^2.3.0 [env:Heltec_WSL3_repeater] extends = Heltec_lora32_v3 From c7fe21184020a9968e6c61e77087f3637368b53a Mon Sep 17 00:00:00 2001 From: Florent de Lamotte Date: Thu, 22 May 2025 16:24:20 +0200 Subject: [PATCH 25/41] rak3x72 : report bat voltage --- variants/rak3x72/target.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/variants/rak3x72/target.h b/variants/rak3x72/target.h index a4c47bc6..c39b69b1 100644 --- a/variants/rak3x72/target.h +++ b/variants/rak3x72/target.h @@ -8,11 +8,19 @@ #include #include +#define PIN_VBAT_READ A0 +#define ADC_MULTIPLIER (5 * 1.73 * 1000) + class RAK3x72Board : public STM32Board { public: const char* getManufacturerName() const override { return "RAK 3x72"; } + + uint16_t getBattMilliVolts() override { + uint32_t raw = analogRead(PIN_VBAT_READ); + return (ADC_MULTIPLIER * raw) / 1024; + } }; extern RAK3x72Board board; From e1351effb18cd3d3554027e175b144e23b10c6bb Mon Sep 17 00:00:00 2001 From: Memo <58190287+memo-567@users.noreply.github.com> Date: Thu, 22 May 2025 15:50:54 +0000 Subject: [PATCH 26/41] Update platformio.ini --- variants/heltec_v3/platformio.ini | 6 ------ 1 file changed, 6 deletions(-) diff --git a/variants/heltec_v3/platformio.ini b/variants/heltec_v3/platformio.ini index 9f4c23c1..a5687987 100644 --- a/variants/heltec_v3/platformio.ini +++ b/variants/heltec_v3/platformio.ini @@ -43,7 +43,6 @@ build_flags = build_src_filter = ${Heltec_lora32_v3.build_src_filter} + +<../examples/simple_repeater> - + lib_deps = ${Heltec_lora32_v3.lib_deps} ${esp32_ota.lib_deps} @@ -63,7 +62,6 @@ build_flags = build_src_filter = ${Heltec_lora32_v3.build_src_filter} + +<../examples/simple_room_server> - + lib_deps = ${Heltec_lora32_v3.lib_deps} ${esp32_ota.lib_deps} @@ -78,7 +76,6 @@ build_flags = ; -D MESH_DEBUG=1 build_src_filter = ${Heltec_lora32_v3.build_src_filter} +<../examples/simple_secure_chat/main.cpp> - + lib_deps = ${Heltec_lora32_v3.lib_deps} densaugeo/base64 @ ~1.4.0 @@ -97,7 +94,6 @@ build_flags = build_src_filter = ${Heltec_lora32_v3.build_src_filter} + +<../examples/companion_radio> - + lib_deps = ${Heltec_lora32_v3.lib_deps} densaugeo/base64 @ ~1.4.0 @@ -120,7 +116,6 @@ build_src_filter = ${Heltec_lora32_v3.build_src_filter} + + +<../examples/companion_radio> - + lib_deps = ${Heltec_lora32_v3.lib_deps} densaugeo/base64 @ ~1.4.0 @@ -143,7 +138,6 @@ build_src_filter = ${Heltec_lora32_v3.build_src_filter} + + +<../examples/companion_radio> - + lib_deps = ${Heltec_lora32_v3.lib_deps} densaugeo/base64 @ ~1.4.0 From e742d1f7228a4e155b2b98178744c39cf8dd884c Mon Sep 17 00:00:00 2001 From: cod3doomy Date: Thu, 22 May 2025 16:50:06 -0700 Subject: [PATCH 27/41] t-beam supreme: minor GPS and BME fixes Fixed GPS initial state to default to off after init. Removed redundant current limit define --- .../platformio.ini | 1 - .../lilygo_tbeam_supreme_SX1262/target.cpp | 54 +++++++++++-------- variants/lilygo_tbeam_supreme_SX1262/target.h | 2 + 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/variants/lilygo_tbeam_supreme_SX1262/platformio.ini b/variants/lilygo_tbeam_supreme_SX1262/platformio.ini index 4367dc15..8e46f22c 100644 --- a/variants/lilygo_tbeam_supreme_SX1262/platformio.ini +++ b/variants/lilygo_tbeam_supreme_SX1262/platformio.ini @@ -12,7 +12,6 @@ build_flags = -D RADIO_CLASS=CustomSX1262 -D WRAPPER_CLASS=CustomSX1262Wrapper -D DISPLAY_CLASS=SH1106Display - -D SX126X_CURRENT_LIMIT=140 -D SX126X_RX_BOOSTED_GAIN=1 -D SX126X_CURRENT_LIMIT=140 build_src_filter = ${esp32_base.build_src_filter} diff --git a/variants/lilygo_tbeam_supreme_SX1262/target.cpp b/variants/lilygo_tbeam_supreme_SX1262/target.cpp index 4dbfd625..dfe453ee 100644 --- a/variants/lilygo_tbeam_supreme_SX1262/target.cpp +++ b/variants/lilygo_tbeam_supreme_SX1262/target.cpp @@ -370,23 +370,28 @@ void TbeamSupSensorManager::sleep_gps() { bool TbeamSupSensorManager::begin() { //init BME280 if (! bme.begin(0x77, &Wire)) { - MESH_DEBUG_PRINTLN("Could not find a valid BME280 sensor, check wiring!"); + MESH_DEBUG_PRINTLN("Could not find a valid BME280 sensor"); + bme_active = false; } else MESH_DEBUG_PRINTLN("BME280 found and init!"); + bme_active = true; // init GPS port Serial1.begin(GPS_BAUD_RATE, SERIAL_8N1, P_GPS_RX, P_GPS_TX); - bool result = false; + bool gps_alive = false; for ( int i = 0; i < 3; ++i) { - result = l76kProbe(); - if (result) { - gps_active = true; - return result; + gps_alive = l76kProbe(); + if (gps_alive) { + MESH_DEBUG_PRINTLN("GPS is init and active. Shutting down for initial state."); + sleep_gps(); + return gps_alive; } } - return result; + gps_active = gps_alive; + MESH_DEBUG_PRINTLN("GPS init failed and GPS is not active"); + return gps_alive; } bool TbeamSupSensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { @@ -422,17 +427,17 @@ void TbeamSupSensorManager::loop() { node_pres = (bme.readPressure() / 100.0F); #ifdef MESH_DEBUG - Serial.print("Temperature = "); - Serial.print(node_temp); - Serial.println(" *C"); + // Serial.print("Temperature = "); + // Serial.print(node_temp); + // Serial.println(" *C"); - Serial.print("Humidity = "); - Serial.print(node_hum); - Serial.println(" %"); + // Serial.print("Humidity = "); + // Serial.print(node_hum); + // Serial.println(" %"); - Serial.print("Pressure = "); - Serial.print(node_pres); - Serial.println(" hPa"); + // Serial.print("Pressure = "); + // Serial.print(node_pres); + // Serial.println(" hPa"); // Serial.print("Approx. Altitude = "); // Serial.print(node_alt); @@ -443,17 +448,24 @@ void TbeamSupSensorManager::loop() { } } -int TbeamSupSensorManager::getNumSettings() const { return 1; } // just one supported: "gps" (power switch) +int TbeamSupSensorManager::getNumSettings() const { + return sensorNum; +} const char* TbeamSupSensorManager::getSettingName(int i) const { - return i == 0 ? "gps" : NULL; + switch(i){ + case 0: return "gps"; + case 1: return "bme280"; + default: NULL; + } } const char* TbeamSupSensorManager::getSettingValue(int i) const { - if (i == 0) { - return gps_active ? "1" : "0"; + switch(i){ + case 0: return gps_active == true ? "1" : "0"; + case 1: return bme_active == true ? "1" : "0"; + default: NULL; } - return NULL; } bool TbeamSupSensorManager::setSettingValue(const char* name, const char* value) { diff --git a/variants/lilygo_tbeam_supreme_SX1262/target.h b/variants/lilygo_tbeam_supreme_SX1262/target.h index dbb24a8e..6acf6cdf 100644 --- a/variants/lilygo_tbeam_supreme_SX1262/target.h +++ b/variants/lilygo_tbeam_supreme_SX1262/target.h @@ -12,9 +12,11 @@ class TbeamSupSensorManager: public SensorManager { bool gps_active = false; + bool bme_active = false; LocationProvider * _nmea; Adafruit_BME280 bme; double node_temp, node_hum, node_pres; + int sensorNum = 2; #define SEALEVELPRESSURE_HPA (1013.25) From 23f54dd9248655fcad9e17d3ba90adb544c94dff Mon Sep 17 00:00:00 2001 From: taco Date: Fri, 23 May 2025 14:34:34 +1000 Subject: [PATCH 28/41] fix: remove stray initSerialGPS call --- src/helpers/sensors/EnvironmentSensorManager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp index c82235c6..2594d91b 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.cpp +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -92,7 +92,6 @@ bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, Cayen } } - initSerialGPS(); return true; } From efa2b4b1b73e02f4da010fb47eff948d6870d19a Mon Sep 17 00:00:00 2001 From: seagull9000 Date: Fri, 23 May 2025 17:58:13 +1200 Subject: [PATCH 29/41] RTTTL-tone-for-Channel-Message I was a bit remiss in removing the tone for channel message event - this puts one in. So: DM event - plays a tone (per current) Channel Message - new shorter tone All others aren't defined at present. Need muting function before we get too carried away. --- examples/companion_radio/UITask.cpp | 2 + src/helpers/ui/button.cpp | 292 ++++++++++++++++++++++++++++ src/helpers/ui/button.h | 79 ++++++++ 3 files changed, 373 insertions(+) create mode 100644 src/helpers/ui/button.cpp create mode 100644 src/helpers/ui/button.h diff --git a/examples/companion_radio/UITask.cpp b/examples/companion_radio/UITask.cpp index f97b47f4..58ffc4d0 100644 --- a/examples/companion_radio/UITask.cpp +++ b/examples/companion_radio/UITask.cpp @@ -67,6 +67,8 @@ switch(bet){ buzzer.play("MsgRcv3:d=4,o=6,b=200:32e,32g,32b,16c7"); break; case UIEventType::channelMessage: + buzzer.play("kerplop:d=16,o=6,b=120:32g#,32c#"); + break; case UIEventType::roomMessage: case UIEventType::newContactMessage: case UIEventType::none: diff --git a/src/helpers/ui/button.cpp b/src/helpers/ui/button.cpp new file mode 100644 index 00000000..7e715b44 --- /dev/null +++ b/src/helpers/ui/button.cpp @@ -0,0 +1,292 @@ +#include "Button.h" + +Button::Button() : + _pin(0), + _inputMode(INPUT_PULLUP), + _buttonPressedState(HIGH), // Assuming INPUT_PULLUP, so HIGH is unpressed + _lastButtonState(HIGH), + _buttonState(false), // Debounced state: false is unpressed + _lastDebouncedState(false), + _lastDebounceTime(0), + _pressStartTime(0), + _releaseTime(0), + _currentSequenceCount(0), + _lastPressEndTime(0), + _callbackCount(0) +{ + for (uint8_t i = 0; i < MAX_PRESSES_IN_SEQUENCE; ++i) { + _currentSequence[i] = ButtonPressType::NONE; + } + for (uint8_t i = 0; i < MAX_CALLBACKS; ++i) { + _registeredCallbacks[i].count = 0; + _registeredCallbacks[i].callback = nullptr; + _registeredCallbacks[i].triggeredInSequence = false; + for (uint8_t j = 0; j < MAX_PRESSES_IN_SEQUENCE; ++j) { + _registeredCallbacks[i].sequence[j] = ButtonPressType::NONE; + } + } +} + +void Button::attach(uint8_t pin, uint8_t inputMode) { + _pin = pin; + _inputMode = inputMode; + pinMode(_pin, _inputMode); + if (_inputMode == INPUT_PULLUP) { + _buttonPressedState = LOW; // Pressed is LOW for PULLUP + _lastButtonState = HIGH; // Initial unpressed state + } else { + _buttonPressedState = HIGH; // Pressed is HIGH for PULLDOWN or regular INPUT + _lastButtonState = LOW; // Initial unpressed state + } + _lastDebouncedState = false; // Not pressed + _buttonState = false; // Not pressed +} + +void Button::update() { + if (_pin == 0) return; // Not attached + + bool reading = digitalRead(_pin); + unsigned long currentTime = millis(); + + // Debounce logic + if (reading != _lastButtonState) { + _lastDebounceTime = currentTime; + } + _lastButtonState = reading; + + if ((currentTime - _lastDebounceTime) > DEBOUNCE_DELAY) { + bool currentDebouncedState = (reading == _buttonPressedState); + + // Edge detection + if (currentDebouncedState != _lastDebouncedState) { + _lastDebouncedState = currentDebouncedState; + + if (currentDebouncedState) { // Button pressed + _pressStartTime = currentTime; + // If a new press starts too long after the previous one, reset sequence + if (_currentSequenceCount > 0 && (currentTime - _lastPressEndTime) > SHORT_PRESS_TIMEOUT) { + _resetSequence(); + } + } else { // Button released + _releaseTime = currentTime; + unsigned long pressDuration = _releaseTime - _pressStartTime; + ButtonPressType pressType = _determinePressType(pressDuration); + + if (pressType != ButtonPressType::NONE) { + _addPressToSequence(pressType); + _lastPressEndTime = currentTime; // Mark end time for next press timeout + _evaluateSequences(); + } + } + } + } + + // Check for sequence timeout if a sequence is in progress + if (_currentSequenceCount > 0 && (currentTime - _lastPressEndTime) > SHORT_PRESS_TIMEOUT) { + // If we timed out, and haven't triggered anything specific from the partial sequence, + // it's time to reset. Callbacks for partial matches should have already fired in _evaluateSequences. + // This handles the case where a sequence like S1 is defined, and the user presses S, then waits. + // We need to ensure S1 callback fires if it exists, even if S2 or S3 are also defined. + // _evaluateSequences called on release handles this. This timeout mainly resets for the next input. + _resetSequence(); + } +} + + +ButtonPressType Button::_determinePressType(unsigned long pressDuration) { + if (pressDuration >= LONG_LONG_PRESS_MIN_DURATION) { + return ButtonPressType::LL; + } else if (pressDuration >= LONGISH_PRESS_MIN_DURATION && pressDuration < LONGISH_PRESS_MAX_DURATION) { + return ButtonPressType::LS; + } else if (pressDuration > DEBOUNCE_DELAY && pressDuration <= SHORT_PRESS_MAX_DURATION) { // Ensure it's more than debounce + return ButtonPressType::S; + } + return ButtonPressType::NONE; +} + +void Button::_addPressToSequence(ButtonPressType pressType) { + if (_currentSequenceCount < MAX_PRESSES_IN_SEQUENCE) { + // Specific handling for LL: it can only be LL1 + if (pressType == ButtonPressType::LL) { + if (_currentSequenceCount == 0) { // LL only valid as the first press in its "sequence" + _currentSequence[_currentSequenceCount++] = pressType; + } else { + // An LL press occurred after other presses, which is not a defined LL1 sequence. + // Treat as an invalid sequence progression, so reset. + _resetSequence(); + // Potentially start a new sequence with this LL if it was intended as LL1. + // For simplicity now, we just reset. More complex logic could try to salvage. + } + } else if (pressType == ButtonPressType::LS) { + // LS can form sequences up to LS3 + // Check if previous was also LS or if sequence is empty + if (_currentSequenceCount == 0 || _currentSequence[_currentSequenceCount -1] == ButtonPressType::LS) { + _currentSequence[_currentSequenceCount++] = pressType; + } else { + // Mixing LS with S in a sequence is not explicitly defined as LS1/2/3 or S1/2/3 + // So, reset the sequence and start new with this LS. + _resetSequence(); + _currentSequence[_currentSequenceCount++] = pressType; + } + } else if (pressType == ButtonPressType::S) { + // S can form sequences up to S3 + // Check if previous was also S or if sequence is empty + if (_currentSequenceCount == 0 || _currentSequence[_currentSequenceCount -1] == ButtonPressType::S) { + _currentSequence[_currentSequenceCount++] = pressType; + } else { + // Mixing S with LS in a sequence is not S1/2/3 or LS1/2/3 + // So, reset the sequence and start new with this S. + _resetSequence(); + _currentSequence[_currentSequenceCount++] = pressType; + } + } + } else { + // Sequence array is full, this shouldn't normally happen if MAX_PRESSES_IN_SEQUENCE is large enough. + // Reset to be safe. + _resetSequence(); + // And add the current press as the start of a new sequence. + if (pressType != ButtonPressType::NONE) { // ensure it's a valid press + _currentSequence[_currentSequenceCount++] = pressType; + } + } +} + +void Button::_evaluateSequences() { + if (_currentSequenceCount == 0) return; + + bool exactMatchFound = false; + + for (uint8_t i = 0; i < _callbackCount; ++i) { + ButtonSequence& registered = _registeredCallbacks[i]; + if (registered.callback == nullptr) continue; + + if (registered.count == _currentSequenceCount) { + bool match = true; + for (uint8_t j = 0; j < _currentSequenceCount; ++j) { + if (_currentSequence[j] != registered.sequence[j]) { + match = false; + break; + } + } + if (match) { + // Exact match found + if (!registered.triggeredInSequence) { // Check if already triggered for this evaluation pass + registered.callback(); + registered.triggeredInSequence = true; // Mark as triggered for this pass + } + exactMatchFound = true; + // For an exact match, we generally reset the current sequence + // as it has been fully consumed by a callback. + } + } + } + + // After checking all callbacks, reset their triggeredInSequence flags for the next evaluation pass + for (uint8_t i = 0; i < _callbackCount; ++i) { + _registeredCallbacks[i].triggeredInSequence = false; + } + + // If an exact match was found, the sequence is "consumed" and should be reset. + // This allows, for example, S1 to trigger, then S2 to trigger, then S3. + // If we don't reset, S1 would trigger, then S1+S2 would require an (S,S) callback. + // The current logic means S triggers S1 callback, then if another S comes, (S,S) triggers S2 callback. + if (exactMatchFound) { + _resetSequence(); + } else { + // If no exact match, but the sequence is full (e.g., S, S, S and no S3 callback) + // or if it's an LL press (which is always a sequence of 1) + // then we should reset to allow new sequences. + if (_currentSequenceCount >= MAX_PRESSES_IN_SEQUENCE || + (_currentSequenceCount > 0 && _currentSequence[_currentSequenceCount -1] == ButtonPressType::LL)) { + _resetSequence(); + } + // Also, if the current sequence is S,S and there's no S2 callback, + // but there IS an S1 callback, S1 should have triggered. + // The current _evaluateSequences iterates all callbacks. + // The problem is if a user defines S and S,S. + // Press S: S callback fires. Current sequence is {S}. + // Press S again: Current sequence becomes {S,S}. S,S callback fires. Sequence resets. This is good. + + // What if user defines S, S,S, S,S,S. + // Press 1: S fires. Seq={S}. + // Press 2: S,S fires. Seq={S,S}. + // Press 3: S,S,S fires. Seq={S,S,S}. + // The reset on exact match handles this. + + // What if only S,S,S is defined? + // Press 1: Seq={S}. No exact match. No reset. + // Press 2: Seq={S,S}. No exact match. No reset. + // Press 3: Seq={S,S,S}. S,S,S fires. Seq resets. Good. + + // What if only S is defined? + // Press 1: Seq={S}. S fires. Seq resets. Good. + // User presses S, S, S. + // S -> S fires, seq resets. + // S -> S fires, seq resets. + // S -> S fires, seq resets. + // This seems correct. A sequence ends once it matches *a* callback. + + // Exception: LL is always a single event. + if (_currentSequenceCount == 1 && _currentSequence[0] == ButtonPressType::LL) { + // LL callback would have fired if registered. Sequence should reset. + // This is handled by `exactMatchFound` leading to reset, + // or by the `_currentSequence[_currentSequenceCount -1] == ButtonPressType::LL` condition above. + } + } +} + + +void Button::_resetSequence() { + _currentSequenceCount = 0; + for (uint8_t i = 0; i < MAX_PRESSES_IN_SEQUENCE; ++i) { + _currentSequence[i] = ButtonPressType::NONE; + } + // _lastPressEndTime is not reset here, because it's used to see if a *new* press + // is starting a new sequence or continuing one (within SHORT_PRESS_TIMEOUT). + // When a sequence fully resets (e.g. due to timeout or completion), + // the _pressStartTime of the *next* press will be compared to the _lastPressEndTime + // of the *previous* press that completed/timed-out the sequence. +} + +bool Button::onPress(ButtonPressType pressType, ButtonCallback callback) { + if (pressType == ButtonPressType::NONE) return false; + // This is a shorthand for a sequence of one. + return onPressSequence(&pressType, 1, callback); +} + +bool Button::onPressSequence(const ButtonPressType types[], uint8_t count, ButtonCallback callback) { + if (_callbackCount >= MAX_CALLBACKS || count == 0 || count > MAX_PRESSES_IN_SEQUENCE) { + return false; // No space or invalid sequence + } + + // Restriction: LL can only be a sequence of 1. + if (count > 1) { + for(uint8_t i=0; i < count; ++i) { + if (types[i] == ButtonPressType::LL) return false; // LL cannot be part of a multi-press sequence definition. + } + } + // Restriction: Sequences must be homogenous (all S or all LS), or a single LL. + if (count > 1) { + ButtonPressType firstType = types[0]; + if (firstType == ButtonPressType::LL) return false; // Should have been caught above. + for (uint8_t i = 1; i < count; ++i) { + if (types[i] != firstType || types[i] == ButtonPressType::LL) { + // Heterogeneous sequence (e.g. S, LS) or LL in multi-press is not allowed by problem def. + return false; + } + } + } + + + _registeredCallbacks[_callbackCount].count = count; + for (uint8_t i = 0; i < count; ++i) { + _registeredCallbacks[_callbackCount].sequence[i] = types[i]; + } + for (uint8_t i = count; i < MAX_PRESSES_IN_SEQUENCE; ++i) { // Zero out rest + _registeredCallbacks[_callbackCount].sequence[i] = ButtonPressType::NONE; + } + _registeredCallbacks[_callbackCount].callback = callback; + _registeredCallbacks[_callbackCount].triggeredInSequence = false; + _callbackCount++; + return true; +} \ No newline at end of file diff --git a/src/helpers/ui/button.h b/src/helpers/ui/button.h new file mode 100644 index 00000000..0f0e3b92 --- /dev/null +++ b/src/helpers/ui/button.h @@ -0,0 +1,79 @@ +#ifndef BUTTON_H +#define BUTTON_H + +#include + +// Maximum number of presses in a sequence (e.g., S3, LS3) +#define MAX_PRESSES_IN_SEQUENCE 3 +// Maximum number of sequences that can be registered +#define MAX_CALLBACKS 10 +// Debounce delay in milliseconds +#define DEBOUNCE_DELAY 50 +// Time to distinguish between short presses in a sequence (ms) +#define SHORT_PRESS_TIMEOUT 500 +// Short press max duration (ms) +#define SHORT_PRESS_MAX_DURATION (SHORT_PRESS_TIMEOUT - 1) // Must be less than timeout +// Longish press min duration (ms) +#define LONGISH_PRESS_MIN_DURATION 1000 +// Longish press max duration (ms) +#define LONGISH_PRESS_MAX_DURATION 2500 +// Long-Long press min duration (ms) +#define LONG_LONG_PRESS_MIN_DURATION 4000 + + +// Enum to represent different press types +enum class ButtonPressType { + NONE, + S, // Short Press + LS, // Longish Press + LL // Long-Long Press +}; + +// Type alias for the callback function +typedef void (*ButtonCallback)(); + +struct ButtonSequence { + ButtonPressType sequence[MAX_PRESSES_IN_SEQUENCE]; + uint8_t count; // Number of presses in this specific sequence + ButtonCallback callback; + bool triggeredInSequence; // To prevent multiple triggers during a sequence evaluation +}; + +class Button { +public: + Button(); + void attach(uint8_t pin, uint8_t inputMode = INPUT_PULLUP); + void update(); + + // Methods to add callbacks + // For single press types (e.g., one long-long press) + bool onPress(ButtonPressType pressType, ButtonCallback callback); + // For sequences of presses (e.g., S, S, S or LS, LS) + bool onPressSequence(const ButtonPressType types[], uint8_t count, ButtonCallback callback); + +private: + uint8_t _pin; + uint8_t _inputMode; + bool _buttonPressedState; // Physical state of the button (HIGH/LOW) + bool _lastButtonState; // Previous physical state for change detection + bool _buttonState; // Debounced button state (true for pressed) + bool _lastDebouncedState; // Last debounced state + + unsigned long _lastDebounceTime; + unsigned long _pressStartTime; + unsigned long _releaseTime; + + ButtonPressType _currentSequence[MAX_PRESSES_IN_SEQUENCE]; + uint8_t _currentSequenceCount; + unsigned long _lastPressEndTime; // Time when the last press in a potential sequence ended + + ButtonSequence _registeredCallbacks[MAX_CALLBACKS]; + uint8_t _callbackCount; + + void _resetSequence(); + void _addPressToSequence(ButtonPressType pressType); + void _evaluateSequences(); + ButtonPressType _determinePressType(unsigned long pressDuration); +}; + +#endif // BUTTON_H \ No newline at end of file From 400c4353dc72141140906c9cfcdf06123c093994 Mon Sep 17 00:00:00 2001 From: taco Date: Fri, 23 May 2025 17:08:23 +1000 Subject: [PATCH 30/41] REFACTOR: sensors are now wrapped in conditionals --- .../sensors/EnvironmentSensorManager.cpp | 119 +++++++++++------- .../sensors/EnvironmentSensorManager.h | 40 ++++-- variants/promicro/platformio.ini | 7 +- 3 files changed, 110 insertions(+), 56 deletions(-) diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp index 2594d91b..b5f5cd48 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.cpp +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -1,15 +1,45 @@ #include "EnvironmentSensorManager.h" - -#include - +#if ENV_INCLUDE_AHTX0 static Adafruit_AHTX0 AHTX0; +#endif +#if ENV_INCLUDE_BME280 static Adafruit_BME280 BME280; +#endif +#if ENV_INCLUDE_INA3221 static Adafruit_INA3221 INA3221; +#endif +#if ENV_INCLUDE_INA219 static Adafruit_INA219 INA219(TELEM_INA219_ADDRESS); +#endif bool EnvironmentSensorManager::begin() { + #if ENV_INCLUDE_GPS + initBasicGPS(); + #endif + #if ENV_INCLUDE_AHTX0 + if (AHTX0.begin(&Wire, 0, TELEM_AHTX_ADDRESS)) { + MESH_DEBUG_PRINTLN("Found AHT10/AHT20 at address: %02X", TELEM_AHTX_ADDRESS); + AHTX0_initialized = true; + } else { + AHTX0_initialized = false; + MESH_DEBUG_PRINTLN("AHT10/AHT20 was not found at I2C address %02X", TELEM_AHTX_ADDRESS); + } + #endif + + #if ENV_INCLUDE_BME280 + if (BME280.begin(TELEM_BME280_ADDRESS, &Wire)) { + MESH_DEBUG_PRINTLN("Found BME280 at address: %02X", TELEM_BME280_ADDRESS); + MESH_DEBUG_PRINTLN("BME sensor ID: %02X", BME280.sensorID()); + BME280_initialized = true; + } else { + BME280_initialized = false; + MESH_DEBUG_PRINTLN("BME280 was not found at I2C address %02X", TELEM_BME280_ADDRESS); + } + #endif + + #if ENV_INCLUDE_INA3221 if (INA3221.begin(TELEM_INA3221_ADDRESS, &Wire)) { MESH_DEBUG_PRINTLN("Found INA3221 at address: %02X", TELEM_INA3221_ADDRESS); MESH_DEBUG_PRINTLN("%04X %04X", INA3221.getDieID(), INA3221.getManufacturerID()); @@ -22,7 +52,9 @@ bool EnvironmentSensorManager::begin() { INA3221_initialized = false; MESH_DEBUG_PRINTLN("INA3221 was not found at I2C address %02X", TELEM_INA3221_ADDRESS); } + #endif + #if ENV_INCLUDE_INA219 if (INA219.begin(&Wire)) { MESH_DEBUG_PRINTLN("Found INA219 at address: %02X", TELEM_INA219_ADDRESS); INA219_initialized = true; @@ -30,33 +62,39 @@ bool EnvironmentSensorManager::begin() { INA219_initialized = false; MESH_DEBUG_PRINTLN("INA219 was not found at I2C address %02X", TELEM_INA219_ADDRESS); } + #endif - if (AHTX0.begin(&Wire, 0, TELEM_AHTX_ADDRESS)) { - MESH_DEBUG_PRINTLN("Found AHT10/AHT20 at address: %02X", TELEM_AHTX_ADDRESS); - AHTX0_initialized = true; - } else { - AHTX0_initialized = false; - MESH_DEBUG_PRINTLN("AHT10/AHT20 was not found at I2C address %02X", TELEM_AHTX_ADDRESS); - } - - if (BME280.begin(TELEM_BME280_ADDRESS, &Wire)) { - MESH_DEBUG_PRINTLN("Found BME280 at address: %02X", TELEM_BME280_ADDRESS); - MESH_DEBUG_PRINTLN("BME sensor ID: %02X", BME280.sensorID); - BME280_initialized = true; - } else { - BME280_initialized = false; - MESH_DEBUG_PRINTLN("BME280 was not found at I2C address %02X", TELEM_BME280_ADDRESS); - } - initSerialGPS(); return true; } bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { - if (requester_permissions & TELEM_PERM_LOCATION) { // does requester have permission? - telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, 0.0f); - } next_available_channel = TELEM_CHANNEL_SELF + 1; + + if (requester_permissions & TELEM_PERM_LOCATION) { + telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, 0.0f); // allow lat/lon via telemetry even if no GPS is detected + } + if (requester_permissions & TELEM_PERM_ENVIRONMENT) { + + #if ENV_INCLUDE_AHTX0 + if (AHTX0_initialized) { + sensors_event_t humidity, temp; + AHTX0.getEvent(&humidity, &temp); + telemetry.addTemperature(TELEM_CHANNEL_SELF, temp.temperature); + telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, humidity.relative_humidity); + } + #endif + + #if ENV_INCLUDE_BME280 + if (BME280_initialized) { + telemetry.addTemperature(TELEM_CHANNEL_SELF, BME280.readTemperature()); + telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, BME280.readHumidity()); + telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, BME280.readPressure()); + telemetry.addAltitude(TELEM_CHANNEL_SELF, BME280.readAltitude(TELEM_BME280_SEALEVELPRESSURE_HPA)); + } + #endif + + #if ENV_INCLUDE_INA3221 if (INA3221_initialized) { for(int i = 0; i < TELEM_INA3221_NUM_CHANNELS; i++) { // add only enabled INA3221 channels to telemetry @@ -70,49 +108,46 @@ bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, Cayen } } } + #endif + + #if ENV_INCLUDE_INA219 if (INA219_initialized) { telemetry.addVoltage(next_available_channel, INA219.getBusVoltage_V()); telemetry.addCurrent(next_available_channel, INA219.getCurrent_mA() / 1000); telemetry.addPower(next_available_channel, INA219.getPower_mW() / 1000); next_available_channel++; } - if (AHTX0_initialized) { - sensors_event_t humidity, temp; - AHTX0.getEvent(&humidity, &temp); + #endif - telemetry.addTemperature(TELEM_CHANNEL_SELF, temp.temperature); - telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, humidity.relative_humidity); - } - - if (BME280_initialized) { - telemetry.addTemperature(TELEM_CHANNEL_SELF, BME280.readTemperature()); - telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, BME280.readHumidity()); - telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, BME280.readPressure()); - telemetry.addAltitude(TELEM_CHANNEL_SELF, BME280.readAltitude(TELEM_BME280_SEALEVELPRESSURE_HPA)); - } } - return true; } int EnvironmentSensorManager::getNumSettings() const { + #if ENV_INCLUDE_GPS return gps_detected ? 1 : 0; // only show GPS setting if GPS is detected + #endif } const char* EnvironmentSensorManager::getSettingName(int i) const { + #if ENV_INCLUDE_GPS return (gps_detected && i == 0) ? "gps" : NULL; + #endif } const char* EnvironmentSensorManager::getSettingValue(int i) const { + #if ENV_INCLUDE_GPS if (gps_detected && i == 0) { return gps_active ? "1" : "0"; } + #endif return NULL; } bool EnvironmentSensorManager::setSettingValue(const char* name, const char* value) { + #if ENV_INCLUDE_GPS if (gps_detected && strcmp(name, "gps") == 0) { if (strcmp(value, "0") == 0) { stop_gps(); @@ -121,13 +156,12 @@ bool EnvironmentSensorManager::setSettingValue(const char* name, const char* val } return true; } + #endif return false; // not supported } - - - -void EnvironmentSensorManager::initSerialGPS() { +#if ENV_INCLUDE_GPS +void EnvironmentSensorManager::initBasicGPS() { Serial1.setPins(PIN_GPS_TX, PIN_GPS_RX); Serial1.begin(9600); @@ -177,4 +211,5 @@ void EnvironmentSensorManager::loop() { } next_gps_update = millis() + 1000; } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/src/helpers/sensors/EnvironmentSensorManager.h b/src/helpers/sensors/EnvironmentSensorManager.h index 51ac3051..2a2d6b81 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.h +++ b/src/helpers/sensors/EnvironmentSensorManager.h @@ -1,45 +1,59 @@ #pragma once +#include #include #include -#include -#include -#include -#include -#include + +#if ENV_INCLUDE_AHTX0 #define TELEM_AHTX_ADDRESS 0x38 // AHT10, AHT20 temperature and humidity sensor I2C address +#include +#endif +#if ENV_INCLUDE_BME280 #define TELEM_BME280_ADDRESS 0x76 // BME280 environmental sensor I2C address +#define TELEM_BME280_SEALEVELPRESSURE_HPA (1013.25) // Athmospheric pressure at sea level +#include +#endif +#if ENV_INCLUDE_INA3221 #define TELEM_INA3221_ADDRESS 0x42 // INA3221 3 channel current sensor I2C address -#define TELEM_INA219_ADDRESS 0x40 // INA219 single channel current sensor I2C address - #define TELEM_INA3221_SHUNT_VALUE 0.100 // most variants will have a 0.1 ohm shunts #define TELEM_INA3221_NUM_CHANNELS 3 +#include +#endif +#if ENV_INCLUDE_INA219 +#define TELEM_INA219_ADDRESS 0x40 // INA219 single channel current sensor I2C address +#include +#endif + -#define TELEM_BME280_SEALEVELPRESSURE_HPA (1013.25) // Athmospheric pressure at sea level class EnvironmentSensorManager : public SensorManager { protected: int next_available_channel = TELEM_CHANNEL_SELF + 1; + bool AHTX0_initialized = false; + bool BME280_initialized = false; bool INA3221_initialized = false; bool INA219_initialized = false; - bool BME280_initialized = false; - bool AHTX0_initialized = false; - bool gps_active = false; - bool gps_detected = false; LocationProvider* _location; + bool gps_detected = false; + bool gps_active = false; + #if ENV_INCLUDE_GPS void start_gps(); void stop_gps(); - void initSerialGPS(); + void initBasicGPS(); + #endif + public: EnvironmentSensorManager(LocationProvider &location): _location(&location){}; bool begin() override; bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override; + #if ENV_INCLUDE_GPS void loop() override; + #endif int getNumSettings() const override; const char* getSettingName(int i) const override; const char* getSettingValue(int i) const override; diff --git a/variants/promicro/platformio.ini b/variants/promicro/platformio.ini index 9e2ee075..11f73d81 100644 --- a/variants/promicro/platformio.ini +++ b/variants/promicro/platformio.ini @@ -16,6 +16,11 @@ build_flags = ${nrf52840_base.build_flags} -D PIN_GPS_RX=3 -D PIN_GPS_TX=4 -D PIN_GPS_EN=5 + -D ENV_INCLUDE_GPS=1 + -D ENV_INCLUDE_AHTX0=1 + -D ENV_INCLUDE_BME280=1 + -D ENV_INCLUDE_INA3221=1 + -D ENV_INCLUDE_INA219=1 build_src_filter = ${nrf52840_base.build_src_filter} + + @@ -103,7 +108,7 @@ build_flags = ${Faketec.build_flags} -D OFFLINE_QUEUE_SIZE=256 -D DISPLAY_CLASS=SSD1306Display ; -D MESH_PACKET_LOGGING=1 -; -D MESH_DEBUG=1 + -D MESH_DEBUG=1 build_src_filter = ${Faketec.build_src_filter} + +<../examples/companion_radio> From 5630533d220171e538663dc915a3dcc7ee8265cc Mon Sep 17 00:00:00 2001 From: seagull9000 Date: Fri, 23 May 2025 17:58:13 +1200 Subject: [PATCH 31/41] RTTTL-tone-for-Channel-Message I was a bit remiss in removing the tone for channel message event - this puts one in. So: DM event - plays a tone (per current) Channel Message - new shorter tone All others aren't defined at present. Need muting function before we get too carried away. --- examples/companion_radio/UITask.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/companion_radio/UITask.cpp b/examples/companion_radio/UITask.cpp index f97b47f4..58ffc4d0 100644 --- a/examples/companion_radio/UITask.cpp +++ b/examples/companion_radio/UITask.cpp @@ -67,6 +67,8 @@ switch(bet){ buzzer.play("MsgRcv3:d=4,o=6,b=200:32e,32g,32b,16c7"); break; case UIEventType::channelMessage: + buzzer.play("kerplop:d=16,o=6,b=120:32g#,32c#"); + break; case UIEventType::roomMessage: case UIEventType::newContactMessage: case UIEventType::none: From 5987e95ce909fb2e4a9aba381b4d8e3924eb2f9f Mon Sep 17 00:00:00 2001 From: taco Date: Fri, 23 May 2025 18:58:45 +1000 Subject: [PATCH 32/41] refactor: more conditionals for GPS also re-added some missing returns. --- src/helpers/sensors/EnvironmentSensorManager.cpp | 6 ++++-- src/helpers/sensors/EnvironmentSensorManager.h | 6 +++++- variants/promicro/target.cpp | 13 ++++++++++--- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp index b5f5cd48..c300cbe4 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.cpp +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -127,14 +127,16 @@ bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, Cayen int EnvironmentSensorManager::getNumSettings() const { #if ENV_INCLUDE_GPS - return gps_detected ? 1 : 0; // only show GPS setting if GPS is detected + return gps_detected ? 1 : 0; // only show GPS setting if GPS is detected #endif + return NULL; } const char* EnvironmentSensorManager::getSettingName(int i) const { #if ENV_INCLUDE_GPS - return (gps_detected && i == 0) ? "gps" : NULL; + return (gps_detected && i == 0) ? "gps" : NULL; #endif + return NULL; } const char* EnvironmentSensorManager::getSettingValue(int i) const { diff --git a/src/helpers/sensors/EnvironmentSensorManager.h b/src/helpers/sensors/EnvironmentSensorManager.h index 2a2d6b81..2a72f2d0 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.h +++ b/src/helpers/sensors/EnvironmentSensorManager.h @@ -36,11 +36,11 @@ protected: bool INA3221_initialized = false; bool INA219_initialized = false; - LocationProvider* _location; bool gps_detected = false; bool gps_active = false; #if ENV_INCLUDE_GPS + LocationProvider* _location; void start_gps(); void stop_gps(); void initBasicGPS(); @@ -48,7 +48,11 @@ protected: public: + #if ENV_INCLUDE_GPS EnvironmentSensorManager(LocationProvider &location): _location(&location){}; + #else + EnvironmentSensorManager(){}; + #endif bool begin() override; bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override; #if ENV_INCLUDE_GPS diff --git a/variants/promicro/target.cpp b/variants/promicro/target.cpp index 666f43f5..2369bd7a 100644 --- a/variants/promicro/target.cpp +++ b/variants/promicro/target.cpp @@ -1,7 +1,9 @@ #include #include "target.h" #include -#include + +#if ENV_INCLUDE_GPS +#endif PromicroBoard board; @@ -11,8 +13,13 @@ WRAPPER_CLASS radio_driver(radio, board); VolatileRTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); -MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); -EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea); +#if ENV_INCLUDE_GPS + #include + MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); + EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea); +#else + EnvironmentSensorManager sensors; +#endif #ifdef DISPLAY_CLASS DISPLAY_CLASS display; From 0defa837d8394932463044ccfc62e87d259cdf99 Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Fri, 23 May 2025 19:12:32 +1000 Subject: [PATCH 33/41] * EnvironmentSensorManager: some tidy ups --- .../sensors/EnvironmentSensorManager.cpp | 22 ++++++++++++++---- .../sensors/EnvironmentSensorManager.h | 23 ------------------- 2 files changed, 18 insertions(+), 27 deletions(-) diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp index c300cbe4..dda1fd55 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.cpp +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -1,15 +1,29 @@ #include "EnvironmentSensorManager.h" #if ENV_INCLUDE_AHTX0 +#define TELEM_AHTX_ADDRESS 0x38 // AHT10, AHT20 temperature and humidity sensor I2C address +#include static Adafruit_AHTX0 AHTX0; #endif + #if ENV_INCLUDE_BME280 +#define TELEM_BME280_ADDRESS 0x76 // BME280 environmental sensor I2C address +#define TELEM_BME280_SEALEVELPRESSURE_HPA (1013.25) // Athmospheric pressure at sea level +#include static Adafruit_BME280 BME280; #endif + #if ENV_INCLUDE_INA3221 +#define TELEM_INA3221_ADDRESS 0x42 // INA3221 3 channel current sensor I2C address +#define TELEM_INA3221_SHUNT_VALUE 0.100 // most variants will have a 0.1 ohm shunts +#define TELEM_INA3221_NUM_CHANNELS 3 +#include static Adafruit_INA3221 INA3221; #endif + #if ENV_INCLUDE_INA219 +#define TELEM_INA219_ADDRESS 0x40 // INA219 single channel current sensor I2C address +#include static Adafruit_INA219 INA219(TELEM_INA219_ADDRESS); #endif @@ -128,15 +142,17 @@ bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, Cayen int EnvironmentSensorManager::getNumSettings() const { #if ENV_INCLUDE_GPS return gps_detected ? 1 : 0; // only show GPS setting if GPS is detected + #else + return 0; #endif - return NULL; } const char* EnvironmentSensorManager::getSettingName(int i) const { #if ENV_INCLUDE_GPS return (gps_detected && i == 0) ? "gps" : NULL; + #else + return NULL; #endif - return NULL; } const char* EnvironmentSensorManager::getSettingValue(int i) const { @@ -184,10 +200,8 @@ void EnvironmentSensorManager::initBasicGPS() { MESH_DEBUG_PRINTLN("No GPS detected"); digitalWrite(PIN_GPS_EN, LOW); } - } - void EnvironmentSensorManager::start_gps() { gps_active = true; pinMode(PIN_GPS_EN, OUTPUT); diff --git a/src/helpers/sensors/EnvironmentSensorManager.h b/src/helpers/sensors/EnvironmentSensorManager.h index 2a72f2d0..c9ec6870 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.h +++ b/src/helpers/sensors/EnvironmentSensorManager.h @@ -4,29 +4,6 @@ #include #include - -#if ENV_INCLUDE_AHTX0 -#define TELEM_AHTX_ADDRESS 0x38 // AHT10, AHT20 temperature and humidity sensor I2C address -#include -#endif -#if ENV_INCLUDE_BME280 -#define TELEM_BME280_ADDRESS 0x76 // BME280 environmental sensor I2C address -#define TELEM_BME280_SEALEVELPRESSURE_HPA (1013.25) // Athmospheric pressure at sea level -#include -#endif -#if ENV_INCLUDE_INA3221 -#define TELEM_INA3221_ADDRESS 0x42 // INA3221 3 channel current sensor I2C address -#define TELEM_INA3221_SHUNT_VALUE 0.100 // most variants will have a 0.1 ohm shunts -#define TELEM_INA3221_NUM_CHANNELS 3 -#include -#endif -#if ENV_INCLUDE_INA219 -#define TELEM_INA219_ADDRESS 0x40 // INA219 single channel current sensor I2C address -#include -#endif - - - class EnvironmentSensorManager : public SensorManager { protected: int next_available_channel = TELEM_CHANNEL_SELF + 1; From f8b45ec01ed30ebbfaff089d728ad923c6e52c25 Mon Sep 17 00:00:00 2001 From: Normunds Gavars Date: Fri, 23 May 2025 21:24:02 +0300 Subject: [PATCH 34/41] Add sensor support to Xiao Nrf --- variants/xiao_nrf52/platformio.ini | 12 ++++++++++++ variants/xiao_nrf52/target.cpp | 2 +- variants/xiao_nrf52/target.h | 4 ++-- variants/xiao_nrf52/variant.h | 4 ++-- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/variants/xiao_nrf52/platformio.ini b/variants/xiao_nrf52/platformio.ini index 5083b1a3..2f468f4f 100644 --- a/variants/xiao_nrf52/platformio.ini +++ b/variants/xiao_nrf52/platformio.ini @@ -16,6 +16,11 @@ lib_ignore = lib_deps = ${nrf52_base.lib_deps} rweather/Crypto @ ^0.4.0 + adafruit/Adafruit INA3221 Library @ ^1.0.1 + adafruit/Adafruit INA219 @ ^1.2.3 + adafruit/Adafruit AHTX0 @ ^2.0.5 + adafruit/Adafruit BME280 Library @ ^2.3.0 + [Xiao_nrf52] extends = nrf52840_xiao @@ -35,8 +40,15 @@ build_flags = ${nrf52840_xiao.build_flags} -D SX126X_DIO3_TCXO_VOLTAGE=1.8 -D SX126X_CURRENT_LIMIT=140 -D SX126X_RX_BOOSTED_GAIN=1 + -D PIN_WIRE_SCL=6 + -D PIN_WIRE_SDA=7 + -D ENV_INCLUDE_AHTX0=1 + -D ENV_INCLUDE_BME280=1 + -D ENV_INCLUDE_INA3221=1 + -D ENV_INCLUDE_INA219=1 build_src_filter = ${nrf52840_xiao.build_src_filter} + + + + +<../variants/xiao_nrf52> debug_tool = jlink diff --git a/variants/xiao_nrf52/target.cpp b/variants/xiao_nrf52/target.cpp index 1d23e76a..c78ea159 100644 --- a/variants/xiao_nrf52/target.cpp +++ b/variants/xiao_nrf52/target.cpp @@ -9,7 +9,7 @@ RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BU WRAPPER_CLASS radio_driver(radio, board); VolatileRTCClock rtc_clock; -SensorManager sensors; +EnvironmentSensorManager sensors; #ifndef LORA_CR #define LORA_CR 5 diff --git a/variants/xiao_nrf52/target.h b/variants/xiao_nrf52/target.h index 868664b5..ec298a43 100644 --- a/variants/xiao_nrf52/target.h +++ b/variants/xiao_nrf52/target.h @@ -6,12 +6,12 @@ #include #include #include -#include +#include extern XiaoNrf52Board board; extern WRAPPER_CLASS radio_driver; extern VolatileRTCClock rtc_clock; -extern SensorManager sensors; +extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); diff --git a/variants/xiao_nrf52/variant.h b/variants/xiao_nrf52/variant.h index 0d0950af..d941463e 100644 --- a/variants/xiao_nrf52/variant.h +++ b/variants/xiao_nrf52/variant.h @@ -110,8 +110,8 @@ static const uint8_t A5 = PIN_A5; // Wire Interfaces #define WIRE_INTERFACES_COUNT (1) -#define PIN_WIRE_SDA (17) // 4 and 5 are used for the sx1262 ! -#define PIN_WIRE_SCL (16) // use WIRE1_SDA +// #define PIN_WIRE_SDA (17) // 4 and 5 are used for the sx1262 ! +// #define PIN_WIRE_SCL (16) // use WIRE1_SDA static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; From 5cb2ba8c6283a62b2a2802129f8c47717d85ce72 Mon Sep 17 00:00:00 2001 From: recrof Date: Sat, 24 May 2025 07:05:33 +0200 Subject: [PATCH 35/41] added repeater and room server roles to heltec wireless tracker --- variants/heltec_tracker/platformio.ini | 44 ++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/variants/heltec_tracker/platformio.ini b/variants/heltec_tracker/platformio.ini index f54eda86..d62771f4 100644 --- a/variants/heltec_tracker/platformio.ini +++ b/variants/heltec_tracker/platformio.ini @@ -31,6 +31,8 @@ build_src_filter = ${esp32_base.build_src_filter} +<../variants/heltec_tracker> lib_deps = ${esp32_base.lib_deps} + stevemarple/MicroNMEA @ ^2.0.6 + adafruit/Adafruit ST7735 and ST7789 Library @ ^1.11.0 [env:Heltec_Wireless_Tracker_companion_radio_ble] extends = Heltec_tracker_base @@ -56,5 +58,43 @@ build_src_filter = ${Heltec_tracker_base.build_src_filter} lib_deps = ${Heltec_tracker_base.lib_deps} densaugeo/base64 @ ~1.4.0 - stevemarple/MicroNMEA @ ^2.0.6 - adafruit/Adafruit ST7735 and ST7789 Library @ ^1.11.0 + +[env:Heltec_Wireless_Tracker_repeater] +extends = Heltec_tracker_base +build_flags = + ${Heltec_tracker_base.build_flags} + -D DISPLAY_ROTATION=1 + -D DISPLAY_CLASS=ST7735Display + -D ADVERT_NAME='"Heltec Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D MAX_NEIGHBOURS=8 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Heltec_tracker_base.build_src_filter} + + + +<../examples/simple_repeater> +lib_deps = + ${Heltec_tracker_base.lib_deps} + ${esp32_ota.lib_deps} + +[env:Heltec_Wireless_Tracker_room_server] +extends = Heltec_tracker_base +build_flags = + ${Heltec_tracker_base.build_flags} + -D DISPLAY_ROTATION=1 + -D DISPLAY_CLASS=ST7735Display + -D ADVERT_NAME='"Heltec Room"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${Heltec_tracker_base.build_src_filter} + + + +<../examples/simple_room_server> +lib_deps = + ${Heltec_tracker_base.lib_deps} + ${esp32_ota.lib_deps} From 0bad7ee1068e66965a3569e7f8b748af8ed14dee Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Sat, 24 May 2025 16:19:19 +1000 Subject: [PATCH 36/41] * ver bump to 1.6.2 --- examples/companion_radio/main.cpp | 4 ++-- examples/simple_repeater/main.cpp | 4 ++-- examples/simple_room_server/main.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index 03a8c90a..13db88c0 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -81,11 +81,11 @@ static uint32_t _atoi(const char* sp) { #define FIRMWARE_VER_CODE 5 #ifndef FIRMWARE_BUILD_DATE - #define FIRMWARE_BUILD_DATE "17 May 2025" + #define FIRMWARE_BUILD_DATE "24 May 2025" #endif #ifndef FIRMWARE_VERSION - #define FIRMWARE_VERSION "v1.6.1" + #define FIRMWARE_VERSION "v1.6.2" #endif #define CMD_APP_START 1 diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index 5e04de54..12c843b7 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -22,11 +22,11 @@ /* ------------------------------ Config -------------------------------- */ #ifndef FIRMWARE_BUILD_DATE - #define FIRMWARE_BUILD_DATE "17 May 2025" + #define FIRMWARE_BUILD_DATE "24 May 2025" #endif #ifndef FIRMWARE_VERSION - #define FIRMWARE_VERSION "v1.6.1" + #define FIRMWARE_VERSION "v1.6.2" #endif #ifndef LORA_FREQ diff --git a/examples/simple_room_server/main.cpp b/examples/simple_room_server/main.cpp index 5ffef515..dad7ce78 100644 --- a/examples/simple_room_server/main.cpp +++ b/examples/simple_room_server/main.cpp @@ -22,11 +22,11 @@ /* ------------------------------ Config -------------------------------- */ #ifndef FIRMWARE_BUILD_DATE - #define FIRMWARE_BUILD_DATE "17 May 2025" + #define FIRMWARE_BUILD_DATE "24 May 2025" #endif #ifndef FIRMWARE_VERSION - #define FIRMWARE_VERSION "v1.6.1" + #define FIRMWARE_VERSION "v1.6.2" #endif #ifndef LORA_FREQ From 42284edcfe1e46de9501599ed5716ffd827aa4de Mon Sep 17 00:00:00 2001 From: Memo <58190287+memo-567@users.noreply.github.com> Date: Sat, 24 May 2025 10:39:05 +0000 Subject: [PATCH 37/41] Update platformio.ini --- variants/heltec_v3/platformio.ini | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/variants/heltec_v3/platformio.ini b/variants/heltec_v3/platformio.ini index a5687987..28c6d562 100644 --- a/variants/heltec_v3/platformio.ini +++ b/variants/heltec_v3/platformio.ini @@ -17,6 +17,10 @@ build_flags = -D SX126X_DIO3_TCXO_VOLTAGE=1.8 -D SX126X_CURRENT_LIMIT=140 -D SX126X_RX_BOOSTED_GAIN=1 + -D ENV_INCLUDE_AHTX0=1 + -D ENV_INCLUDE_BME280=1 + -D ENV_INCLUDE_INA3221=1 + -D ENV_INCLUDE_INA219=1 build_src_filter = ${esp32_base.build_src_filter} +<../variants/heltec_v3> + From e5ddb8a598d91fd4a1cf1d43c8c5c9e18b777867 Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Mon, 26 May 2025 12:23:52 +1000 Subject: [PATCH 38/41] * RAK: "start ota" now replies with Bluetooth MAC address --- src/helpers/nrf52/RAK4631Board.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/helpers/nrf52/RAK4631Board.cpp b/src/helpers/nrf52/RAK4631Board.cpp index eb1a42c5..c75ecf29 100644 --- a/src/helpers/nrf52/RAK4631Board.cpp +++ b/src/helpers/nrf52/RAK4631Board.cpp @@ -80,6 +80,11 @@ bool RAK4631Board::startOTAUpdate(const char* id, char reply[]) { Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds - strcpy(reply, "OK - started"); + uint8_t mac_addr[6]; + memset(mac_addr, 0, sizeof(mac_addr)); + Bluefruit.getAddr(mac_addr); + sprintf(reply, "OK - mac: %02X:%02X:%02X:%02X:%02X:%02X", + mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); + return true; } From 4b103ca0de7fdcad35ac7cf59f539e822e7a024d Mon Sep 17 00:00:00 2001 From: cod3doomy Date: Sun, 25 May 2025 21:23:31 -0700 Subject: [PATCH 39/41] t-beam supreme: fixes and consolidation Made changes requested by Scott Simplified gps init sequence and removed unnecessary code Reverted SensorManager change Updated PMU flow to enable header outputs --- src/helpers/SensorManager.h | 2 +- src/helpers/TBeamS3SupremeBoard.h | 4 +- .../lilygo_tbeam_supreme_SX1262/target.cpp | 139 +++++------------- variants/lilygo_tbeam_supreme_SX1262/target.h | 4 +- 4 files changed, 44 insertions(+), 105 deletions(-) diff --git a/src/helpers/SensorManager.h b/src/helpers/SensorManager.h index 41c34e55..0e4bc27d 100644 --- a/src/helpers/SensorManager.h +++ b/src/helpers/SensorManager.h @@ -13,7 +13,7 @@ public: double node_lat, node_lon; // modify these, if you want to affect Advert location double node_altitude; // altitude in meters - SensorManager() { node_lat = 0; node_lon = 0; node_altitude = 0;} + SensorManager() { node_lat = 0; node_lon = 0; node_altitude = 0; } virtual bool begin() { return false; } virtual bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { return false; } virtual void loop() { } diff --git a/src/helpers/TBeamS3SupremeBoard.h b/src/helpers/TBeamS3SupremeBoard.h index 1ae6a230..ccb8e24c 100644 --- a/src/helpers/TBeamS3SupremeBoard.h +++ b/src/helpers/TBeamS3SupremeBoard.h @@ -61,10 +61,10 @@ public: void begin() { - power_init(); - ESP32Board::begin(); + power_init(); + esp_reset_reason_t reason = esp_reset_reason(); if (reason == ESP_RST_DEEPSLEEP) { long wakeup_source = esp_sleep_get_ext1_wakeup_status(); diff --git a/variants/lilygo_tbeam_supreme_SX1262/target.cpp b/variants/lilygo_tbeam_supreme_SX1262/target.cpp index dfe453ee..6a37f7c2 100644 --- a/variants/lilygo_tbeam_supreme_SX1262/target.cpp +++ b/variants/lilygo_tbeam_supreme_SX1262/target.cpp @@ -143,9 +143,9 @@ bool TBeamS3SupremeBoard::power_init() PMU.setChargingLedMode(XPOWERS_CHG_LED_CTRL_CHG); // Set up PMU interrupts - // MESH_DEBUG_PRINTLN("Setting up PMU interrupts"); - // pinMode(PIN_PMU_IRQ, INPUT_PULLUP); - // attachInterrupt(PIN_PMU_IRQ, setPMUIntFlag, FALLING); + MESH_DEBUG_PRINTLN("Setting up PMU interrupts"); + pinMode(PIN_PMU_IRQ, INPUT_PULLUP); + attachInterrupt(PIN_PMU_IRQ, setPMUIntFlag, FALLING); // GPS MESH_DEBUG_PRINTLN("Setting and enabling a-ldo4 for GPS"); @@ -188,22 +188,22 @@ bool TBeamS3SupremeBoard::power_init() PMU.enableBLDO1(); // Out to header pins - // MESH_DEBUG_PRINTLN("Setting and enabling b-ldo2 for output to header"); - // PMU.setBLDO2Voltage(3300); - // PMU.enableBLDO2(); + MESH_DEBUG_PRINTLN("Setting and enabling b-ldo2 for output to header"); + PMU.setBLDO2Voltage(3300); + PMU.enableBLDO2(); - // MESH_DEBUG_PRINTLN("Setting and enabling dcdc4 for output to header"); - // PMU.setDC4Voltage(XPOWERS_AXP2101_DCDC4_VOL2_MAX); // 1.8V - // PMU.enableDC4(); + MESH_DEBUG_PRINTLN("Setting and enabling dcdc4 for output to header"); + PMU.setDC4Voltage(XPOWERS_AXP2101_DCDC4_VOL2_MAX); // 1.8V + PMU.enableDC4(); - // MESH_DEBUG_PRINTLN("Setting and enabling dcdc5 for output to header"); - // PMU.setDC5Voltage(3300); - // PMU.enableDC5(); + MESH_DEBUG_PRINTLN("Setting and enabling dcdc5 for output to header"); + PMU.setDC5Voltage(3300); + PMU.enableDC5(); // Unused power rails - MESH_DEBUG_PRINTLN("Disabling unused supplies dcdc2, dldo1 and dldo2"); + MESH_DEBUG_PRINTLN("Disabling unused supplies dcdc2, dcdc5, dldo1 and dldo2"); PMU.disableDC2(); - PMU.disableDC5(); + //PMU.disableDC5(); PMU.disableDLDO1(); PMU.disableDLDO2(); @@ -223,18 +223,18 @@ bool TBeamS3SupremeBoard::power_init() PMU.enableVbusVoltageMeasure(); // Reset and re-enable PMU interrupts - // MESH_DEBUG_PRINTLN("Re-enable interrupts"); - // PMU.disableIRQ(XPOWERS_AXP2101_ALL_IRQ); - // PMU.clearIrqStatus(); - // PMU.enableIRQ( - // XPOWERS_AXP2101_BAT_INSERT_IRQ | XPOWERS_AXP2101_BAT_REMOVE_IRQ | // Battery interrupts - // XPOWERS_AXP2101_VBUS_INSERT_IRQ | XPOWERS_AXP2101_VBUS_REMOVE_IRQ | // VBUS interrupts - // XPOWERS_AXP2101_PKEY_SHORT_IRQ | XPOWERS_AXP2101_PKEY_LONG_IRQ | // Power Key interrupts - // XPOWERS_AXP2101_BAT_CHG_DONE_IRQ | XPOWERS_AXP2101_BAT_CHG_START_IRQ // Charging interrupts - // ); + MESH_DEBUG_PRINTLN("Re-enable interrupts"); + PMU.disableIRQ(XPOWERS_AXP2101_ALL_IRQ); + PMU.clearIrqStatus(); + PMU.enableIRQ( + XPOWERS_AXP2101_BAT_INSERT_IRQ | XPOWERS_AXP2101_BAT_REMOVE_IRQ | // Battery interrupts + XPOWERS_AXP2101_VBUS_INSERT_IRQ | XPOWERS_AXP2101_VBUS_REMOVE_IRQ | // VBUS interrupts + XPOWERS_AXP2101_PKEY_SHORT_IRQ | XPOWERS_AXP2101_PKEY_LONG_IRQ | // Power Key interrupts + XPOWERS_AXP2101_BAT_CHG_DONE_IRQ | XPOWERS_AXP2101_BAT_CHG_START_IRQ // Charging interrupts + ); #ifdef MESH_DEBUG - // scanDevices(&Wire); - // scanDevices(&Wire1); + scanDevices(&Wire); + scanDevices(&Wire1); printPMU(); #endif @@ -259,56 +259,6 @@ static bool readStringUntil(Stream& s, char dest[], size_t max_len, char term, u return millis() < timeout; // false, if timed out } -static bool l76kProbe() -{ - bool result = false; - uint32_t startTimeout ; - Serial1.write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n"); - delay(5); - // Get version information - startTimeout = millis() + 3000; - MESH_DEBUG_PRINTLN("Trying to init L76K GPS"); - // Serial1.flush(); - while (Serial1.available()) { - int c = Serial1.read(); - // Serial.write(c); - // Serial.print("."); - // Serial.flush(); - // Serial1.flush(); - if (millis() > startTimeout) { - MESH_DEBUG_PRINTLN("L76K NMEA timeout!"); - return false; - } - }; - - Serial1.flush(); - delay(200); - - Serial1.write("$PCAS06,0*1B\r\n"); - - char ver[100]; - if (!readStringUntil(Serial1, ver, sizeof(ver), '\n', 500)) { - MESH_DEBUG_PRINTLN("Get L76K timeout!"); - return false; - } - - if (memcmp(ver, "$GPTXT,01,01,02", 15) == 0) { - MESH_DEBUG_PRINTLN("L76K GNSS init succeeded, using L76K GNSS Module\n"); - result = true; - } - delay(500); - - // Initialize the L76K Chip, use GPS + GLONASS - Serial1.write("$PCAS04,5*1C\r\n"); - delay(250); - // only ask for RMC and GGA - Serial1.write("$PCAS03,1,0,0,0,1,0,0,0,0,0,,,0,0*02\r\n"); - delay(250); - // Switch to Vehicle Mode, since SoftRF enables Aviation < 2g - Serial1.write("$PCAS11,3*1E\r\n"); - return result; -} - bool radio_init() { fallback_clock.begin(); @@ -380,25 +330,16 @@ bool TbeamSupSensorManager::begin() { // init GPS port Serial1.begin(GPS_BAUD_RATE, SERIAL_8N1, P_GPS_RX, P_GPS_TX); - bool gps_alive = false; - for ( int i = 0; i < 3; ++i) { - gps_alive = l76kProbe(); - if (gps_alive) { - MESH_DEBUG_PRINTLN("GPS is init and active. Shutting down for initial state."); - sleep_gps(); - return gps_alive; - } - } - gps_active = gps_alive; - MESH_DEBUG_PRINTLN("GPS init failed and GPS is not active"); - return gps_alive; + MESH_DEBUG_PRINTLN("Sleeping GPS for initial state"); + sleep_gps(); + return true; } bool TbeamSupSensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { 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) { // does requester have permission? + if (requester_permissions & TELEM_PERM_ENVIRONMENT && bme_active) { // does requester have permission? telemetry.addTemperature(TELEM_CHANNEL_SELF, node_temp); telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, node_hum); telemetry.addBarometricPressure(TELEM_CHANNEL_SELF, node_pres); @@ -413,20 +354,21 @@ void TbeamSupSensorManager::loop() { _nmea->loop(); if (millis() > next_update) { - if (_nmea->isValid()) { + if (_nmea->isValid() && gps_active) { node_lat = ((double)_nmea->getLatitude())/1000000.; node_lon = ((double)_nmea->getLongitude())/1000000.; node_altitude = ((double)_nmea->getAltitude()) / 1000.0; - //Serial.printf("lat %f lon %f\r\n", _lat, _lon); + MESH_DEBUG_PRINT("lat %f lon %f alt %f\r\n", node_lat, node_lon, node_altitude); } //read BME280 values - //node_alt = bme.readAltitude(SEALEVELPRESSURE_HPA); - node_temp = bme.readTemperature(); - node_hum = bme.readHumidity(); - node_pres = (bme.readPressure() / 100.0F); - - #ifdef MESH_DEBUG + if(bme_active){ + //node_alt = bme.readAltitude(SEALEVELPRESSURE_HPA); + node_temp = bme.readTemperature(); + node_hum = bme.readHumidity(); + node_pres = (bme.readPressure() / 100.0F); + + #ifdef MESH_DEBUG // Serial.print("Temperature = "); // Serial.print(node_temp); // Serial.println(" *C"); @@ -442,7 +384,8 @@ void TbeamSupSensorManager::loop() { // Serial.print("Approx. Altitude = "); // Serial.print(node_alt); // Serial.println(" m"); - #endif + #endif + } next_update = millis() + 1000; } @@ -455,7 +398,6 @@ int TbeamSupSensorManager::getNumSettings() const { const char* TbeamSupSensorManager::getSettingName(int i) const { switch(i){ case 0: return "gps"; - case 1: return "bme280"; default: NULL; } } @@ -463,7 +405,6 @@ const char* TbeamSupSensorManager::getSettingName(int i) const { const char* TbeamSupSensorManager::getSettingValue(int i) const { switch(i){ case 0: return gps_active == true ? "1" : "0"; - case 1: return bme_active == true ? "1" : "0"; default: NULL; } } diff --git a/variants/lilygo_tbeam_supreme_SX1262/target.h b/variants/lilygo_tbeam_supreme_SX1262/target.h index 6acf6cdf..293580ee 100644 --- a/variants/lilygo_tbeam_supreme_SX1262/target.h +++ b/variants/lilygo_tbeam_supreme_SX1262/target.h @@ -16,7 +16,7 @@ class TbeamSupSensorManager: public SensorManager { LocationProvider * _nmea; Adafruit_BME280 bme; double node_temp, node_hum, node_pres; - int sensorNum = 2; + int sensorNum = 1; #define SEALEVELPRESSURE_HPA (1013.25) @@ -65,8 +65,6 @@ enum { OSC32768_ONLINE = _BV(13), }; -void scanDevices(TwoWire *w); -static bool l76kProbe(); bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); From 3ae2e851a0f58e3b976129522e63a9dddb898c22 Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Mon, 26 May 2025 14:39:44 +1000 Subject: [PATCH 40/41] * minor tidy ups --- variants/lilygo_tbeam_supreme_SX1262/platformio.ini | 2 +- variants/lilygo_tbeam_supreme_SX1262/target.cpp | 2 +- variants/lilygo_tbeam_supreme_SX1262/target.h | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/variants/lilygo_tbeam_supreme_SX1262/platformio.ini b/variants/lilygo_tbeam_supreme_SX1262/platformio.ini index 8e46f22c..4e6721f9 100644 --- a/variants/lilygo_tbeam_supreme_SX1262/platformio.ini +++ b/variants/lilygo_tbeam_supreme_SX1262/platformio.ini @@ -67,8 +67,8 @@ build_flags = -D MAX_CONTACTS=100 -D MAX_GROUP_CHANNELS=8 -D BLE_PIN_CODE=123456 - -D BLE_DEBUG_LOGGING=1 -D OFFLINE_QUEUE_SIZE=256 +; -D BLE_DEBUG_LOGGING=1 ; -D ENABLE_PRIVATE_KEY_IMPORT=1 ; -D ENABLE_PRIVATE_KEY_EXPORT=1 ; -D MESH_PACKET_LOGGING=8 diff --git a/variants/lilygo_tbeam_supreme_SX1262/target.cpp b/variants/lilygo_tbeam_supreme_SX1262/target.cpp index 6a37f7c2..4b38b11d 100644 --- a/variants/lilygo_tbeam_supreme_SX1262/target.cpp +++ b/variants/lilygo_tbeam_supreme_SX1262/target.cpp @@ -392,7 +392,7 @@ void TbeamSupSensorManager::loop() { } int TbeamSupSensorManager::getNumSettings() const { - return sensorNum; + return 1; } const char* TbeamSupSensorManager::getSettingName(int i) const { diff --git a/variants/lilygo_tbeam_supreme_SX1262/target.h b/variants/lilygo_tbeam_supreme_SX1262/target.h index 293580ee..a3023750 100644 --- a/variants/lilygo_tbeam_supreme_SX1262/target.h +++ b/variants/lilygo_tbeam_supreme_SX1262/target.h @@ -16,7 +16,6 @@ class TbeamSupSensorManager: public SensorManager { LocationProvider * _nmea; Adafruit_BME280 bme; double node_temp, node_hum, node_pres; - int sensorNum = 1; #define SEALEVELPRESSURE_HPA (1013.25) From 0e90b73110d290dd5b548d048ad0d7a3e62f9562 Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Mon, 26 May 2025 19:52:32 +1000 Subject: [PATCH 41/41] * companion: PUSH_CODE_LOGIN_SUCCESS frame, now includes server clock timestamp --- examples/companion_radio/main.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index 13db88c0..6eee0591 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -695,6 +695,7 @@ protected: if (memcmp(&data[4], "OK", 2) == 0) { // legacy Repeater login OK response out_frame[i++] = PUSH_CODE_LOGIN_SUCCESS; out_frame[i++] = 0; // legacy: is_admin = false + memcpy(&out_frame[i], contact.id.pub_key, 6); i += 6; // pub_key_prefix } else if (data[4] == RESP_SERVER_LOGIN_OK) { // new login response uint16_t keep_alive_secs = ((uint16_t)data[5]) * 16; if (keep_alive_secs > 0) { @@ -702,11 +703,13 @@ protected: } out_frame[i++] = PUSH_CODE_LOGIN_SUCCESS; out_frame[i++] = data[6]; // permissions (eg. is_admin) + memcpy(&out_frame[i], contact.id.pub_key, 6); i += 6; // pub_key_prefix + memcpy(&out_frame[i], &tag, 4); i += 4; // NEW: include server timestamp } else { out_frame[i++] = PUSH_CODE_LOGIN_FAIL; out_frame[i++] = 0; // reserved + memcpy(&out_frame[i], contact.id.pub_key, 6); i += 6; // pub_key_prefix } - memcpy(&out_frame[i], contact.id.pub_key, 6); i += 6; // pub_key_prefix _serial->writeFrame(out_frame, i); } else if (len > 4 && // check for status response pending_status && memcmp(&pending_status, contact.id.pub_key, 4) == 0 // legacy matching scheme