From 8a27743e43ba40eb13d2fd6ed9b5f91598d09402 Mon Sep 17 00:00:00 2001 From: Normunds Gavars Date: Mon, 19 May 2025 17:24:54 +0300 Subject: [PATCH 01/20] 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 a950343f057ce2035e5dd853de890459bd4ded4a Mon Sep 17 00:00:00 2001 From: AndreaB Date: Mon, 19 May 2025 16:52:24 +0100 Subject: [PATCH 02/20] Increase the delay to 1500 to allow enough time for T114 GPS to start up successfully. --- variants/t114/target.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variants/t114/target.cpp b/variants/t114/target.cpp index fe3d14f9..a57a55e2 100644 --- a/variants/t114/target.cpp +++ b/variants/t114/target.cpp @@ -97,7 +97,7 @@ bool T114SensorManager::begin() { digitalWrite(GPS_EN, HIGH); // Power on GPS // Give GPS a moment to power up and send data - delay(500); + delay(1500); // We'll consider GPS detected if we see any data on Serial1 gps_detected = (Serial1.available() > 0); From 3cf78a952ba9e23bbfb05706bb17f318879c7c1c Mon Sep 17 00:00:00 2001 From: Normunds Gavars Date: Mon, 19 May 2025 19:37:30 +0300 Subject: [PATCH 03/20] 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 04/20] 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 4a90042b08b6fe36dcb13c04e4d8f9855ed2fe0f Mon Sep 17 00:00:00 2001 From: Rob Loranger Date: Sun, 18 May 2025 15:38:57 -0700 Subject: [PATCH 05/20] add GPS for nano g2 hardcoded interval of 1 minute after first fix obtained --- variants/nano_g2_ultra/nano-g2.cpp | 5 +- variants/nano_g2_ultra/platformio.ini | 2 +- variants/nano_g2_ultra/target.cpp | 107 +++++++++++++++++++++++++- variants/nano_g2_ultra/target.h | 26 ++++++- variants/nano_g2_ultra/variant.h | 4 + 5 files changed, 135 insertions(+), 9 deletions(-) diff --git a/variants/nano_g2_ultra/nano-g2.cpp b/variants/nano_g2_ultra/nano-g2.cpp index 731fa873..8088ddd0 100644 --- a/variants/nano_g2_ultra/nano-g2.cpp +++ b/variants/nano_g2_ultra/nano-g2.cpp @@ -27,11 +27,10 @@ void NanoG2Ultra::begin() // for future use, sub-classes SHOULD call this from their begin() startup_reason = BD_STARTUP_NORMAL; + // set user button pinMode(PIN_BUTTON1, INPUT); + // the external notification circuit is shared for both buzzer and led - // need to find out the switch state or somehow write a function that can - // sound the buzzer or signal the led. the led will stay on once brought HIGH - // and can be then brought LOW. It turns off with a hardware btn. pinMode(EXT_NOTIFY_OUT, OUTPUT); digitalWrite(EXT_NOTIFY_OUT, LOW); diff --git a/variants/nano_g2_ultra/platformio.ini b/variants/nano_g2_ultra/platformio.ini index dc8e81ac..af652e3e 100644 --- a/variants/nano_g2_ultra/platformio.ini +++ b/variants/nano_g2_ultra/platformio.ini @@ -53,4 +53,4 @@ lib_deps = densaugeo/base64 @ ~1.4.0 adafruit/Adafruit SH110X @ ~2.1.13 adafruit/Adafruit GFX Library @ ^1.12.1 - + stevemarple/MicroNMEA @ ^2.0.6 diff --git a/variants/nano_g2_ultra/target.cpp b/variants/nano_g2_ultra/target.cpp index d8c5ef8e..33824f62 100644 --- a/variants/nano_g2_ultra/target.cpp +++ b/variants/nano_g2_ultra/target.cpp @@ -1,6 +1,7 @@ #include #include "target.h" #include +#include NanoG2Ultra board; @@ -10,10 +11,11 @@ WRAPPER_CLASS radio_driver(radio, board); VolatileRTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); -SensorManager sensors; +MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); +NanoG2UltraSensorManager sensors = NanoG2UltraSensorManager(nmea); #ifdef DISPLAY_CLASS - DISPLAY_CLASS display; +DISPLAY_CLASS display; #endif #ifndef LORA_CR @@ -73,6 +75,107 @@ void radio_set_tx_power(uint8_t dbm) radio.setOutputPower(dbm); } +void NanoG2UltraSensorManager::start_gps() +{ + if (!gps_active) + { + MESH_DEBUG_PRINTLN("starting GPS"); + digitalWrite(PIN_GPS_STANDBY, HIGH); + gps_active = true; + } +} + +void NanoG2UltraSensorManager::stop_gps() +{ + if (gps_active) + { + MESH_DEBUG_PRINTLN("stopping GPS"); + digitalWrite(PIN_GPS_STANDBY, LOW); + gps_active = false; + } +} + +bool NanoG2UltraSensorManager::begin() +{ + Serial1.setPins(PIN_GPS_TX, PIN_GPS_RX); // be sure to tx into rx and rx into tx + Serial1.begin(115200); + + pinMode(PIN_GPS_STANDBY, OUTPUT); + digitalWrite(PIN_GPS_STANDBY, HIGH); // Wake GPS from standby + delay(500); + + // We'll consider GPS detected if we see any data on Serial1 + if (Serial1.available() > 0) + { + MESH_DEBUG_PRINTLN("GPS detected"); + } + else + { + MESH_DEBUG_PRINTLN("No GPS detected"); + } + digitalWrite(GPS_EN, LOW); // Put GPS back into standby mode + return true; +} + +bool NanoG2UltraSensorManager::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); + } + return true; +} + +void NanoG2UltraSensorManager::loop() +{ + static long next_gps_update = 0; + _location->loop(); + if (millis() > next_gps_update && gps_active) // don't bother if gps position is not enabled + { + if (_location->isValid()) + { + node_lat = ((double)_location->getLatitude()) / 1000000.; + node_lon = ((double)_location->getLongitude()) / 1000000.; + node_altitude = ((double)_location->getAltitude()) / 1000.0; + MESH_DEBUG_PRINTLN("lat %f lon %f", node_lat, node_lon); + } + next_gps_update = millis() + (1000 * 60); // after initial update, only check every minute TODO: should be configurable + } +} + +int NanoG2UltraSensorManager::getNumSettings() const { return 1; } // just one supported: "gps" (power switch) + +const char *NanoG2UltraSensorManager::getSettingName(int i) const +{ + return i == 0 ? "gps" : NULL; +} + +const char *NanoG2UltraSensorManager::getSettingValue(int i) const +{ + if (i == 0) + { + return gps_active ? "1" : "0"; + } + return NULL; +} + +bool NanoG2UltraSensorManager::setSettingValue(const char *name, const char *value) +{ + if (strcmp(name, "gps") == 0) + { + if (strcmp(value, "0") == 0) + { + stop_gps(); + } + else + { + start_gps(); + } + return true; + } + return false; // not supported +} + mesh::LocalIdentity radio_new_identity() { RadioNoiseListener rng(radio); diff --git a/variants/nano_g2_ultra/target.h b/variants/nano_g2_ultra/target.h index b0af0a8d..e0d891e9 100644 --- a/variants/nano_g2_ultra/target.h +++ b/variants/nano_g2_ultra/target.h @@ -8,16 +8,36 @@ #include #include #ifdef DISPLAY_CLASS - #include +#include #endif +#include + +class NanoG2UltraSensorManager : public SensorManager +{ + bool gps_active = false; + LocationProvider *_location; + + void start_gps(); + void stop_gps(); + +public: + NanoG2UltraSensorManager(LocationProvider &location) : _location(&location) {} + bool begin() 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; +}; extern NanoG2Ultra board; extern WRAPPER_CLASS radio_driver; extern AutoDiscoverRTCClock rtc_clock; -extern SensorManager sensors; +extern NanoG2UltraSensorManager sensors; #ifdef DISPLAY_CLASS - extern DISPLAY_CLASS display; +extern DISPLAY_CLASS display; #endif bool radio_init(); diff --git a/variants/nano_g2_ultra/variant.h b/variants/nano_g2_ultra/variant.h index b0cc3100..b8a53fcf 100644 --- a/variants/nano_g2_ultra/variant.h +++ b/variants/nano_g2_ultra/variant.h @@ -130,11 +130,15 @@ External serial flash W25Q16JV_IQ * GPS pins */ +#define HAS_GPS 1 #define GPS_L76K #define PIN_GPS_STANDBY (0 + 13) // An output to wake GPS, low means allow sleep, high means force wake STANDBY #define PIN_GPS_TX (0 + 9) // This is for bits going TOWARDS the CPU #define PIN_GPS_RX (0 + 10) // This is for bits going TOWARDS the GPS +#define GPS_RX_PIN PIN_GPS_RX +#define GPS_TX_PIN PIN_GPS_TX + // #define GPS_THREAD_INTERVAL 50 From be88bea42d45919ecccd11aefefc9ab0b559fed9 Mon Sep 17 00:00:00 2001 From: seagull9000 Date: Tue, 20 May 2025 13:26:40 +1200 Subject: [PATCH 06/20] initial support for generic RTTTL notifier --- examples/companion_radio/buzzer.cpp | 54 +++++++++++++++++++++++++++++ examples/companion_radio/buzzer.h | 36 +++++++++++++++++++ examples/companion_radio/main.cpp | 20 ++++++++++- variants/t1000-e/platformio.ini | 3 ++ 4 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 examples/companion_radio/buzzer.cpp create mode 100644 examples/companion_radio/buzzer.h diff --git a/examples/companion_radio/buzzer.cpp b/examples/companion_radio/buzzer.cpp new file mode 100644 index 00000000..0465bf16 --- /dev/null +++ b/examples/companion_radio/buzzer.cpp @@ -0,0 +1,54 @@ +#ifdef PIN_BUZZER +#include "buzzer.h" + +void genericBuzzer::begin() { + Serial.print("DBG: Setting up buzzer on pin "); + Serial.println(PIN_BUZZER); + #ifdef PIN_BUZZER_EN + pinMode(PIN_BUZZER_EN, OUTPUT); + digitalWrite(PIN_BUZZER_EN, HIGH); + #endif + + quiet(false); + pinMode(PIN_BUZZER, OUTPUT); + startup(); +} + +void genericBuzzer::play(const char *melody) { + if (isPlaying()) // interrupt existing + { + rtttl::stop(); + } + + if (_is_quiet) return; + + rtttl::begin(PIN_BUZZER,melody); +// Serial.print("DBG: Playing melody - isQuiet: "); +// Serial.println(isQuiet()); +} + +bool genericBuzzer::isPlaying() { + return rtttl::isPlaying(); +} + +void genericBuzzer::loop() { + if (!rtttl::done()) rtttl::play(); +} + +void genericBuzzer::startup() { + play(startup_song); +} + +void genericBuzzer::shutdown() { + play(shutdown_song); +} + +void genericBuzzer::quiet(bool buzzer_state) { + _is_quiet = buzzer_state; +} + +bool genericBuzzer::isQuiet() { + return _is_quiet; +} + +#endif // ifdef PIN_BUZZER \ No newline at end of file diff --git a/examples/companion_radio/buzzer.h b/examples/companion_radio/buzzer.h new file mode 100644 index 00000000..9f3f3fd3 --- /dev/null +++ b/examples/companion_radio/buzzer.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include + +/* class abstracts underlying RTTTL library + + Just a simple imlementation to start. At the moment use same + melody for message and discovery + Suggest enum type for different sounds + - on message + - on discovery + + TODO + - make message ring tone configurable + +*/ +class genericBuzzer +{ + public: + void begin(); // set up buzzer port + void play(const char *melody); // Generic play function + void loop(); // loop driven-nonblocking + void startup(); // play startup sound + void shutdown(); // play shutdown sound + bool isPlaying(); // returns true if a sound is still playing else false + void quiet(bool buzzer_state); // enables or disables the buzzer + bool isQuiet(); // get buzzer state on/off + + private: + // gemini's picks: + const char *startup_song = "Startup:d=4,o=5,b=160:16c6,16e6,8g6"; + const char *shutdown_song = "Shutdown:d=4,o=5,b=100:8g5,16e5,16c5"; + + bool _is_quiet = true; +}; diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index 2cfb833b..8b4b437f 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -66,6 +66,11 @@ static UITask ui_task(&board); #endif +#ifdef PIN_BUZZER + #include "buzzer.h" + genericBuzzer buzzer; +#endif + // Believe it or not, this std C function is busted on some platforms! static uint32_t _atoi(const char* sp) { uint32_t n = 0; @@ -484,7 +489,12 @@ class MyMesh : public BaseChatMesh { } void soundBuzzer() { - // TODO + #if defined(PIN_BUZZER) + // gemini's pick + buzzer.play("MsgRcv3:d=4,o=6,b=200:32e,32g,32b,16c7"); + //Serial.println("DBG: Buzzzzzz"); + #endif + } protected: @@ -1553,6 +1563,10 @@ public: ui_task.setHasConnection(_serial->isConnected()); ui_task.loop(); #endif + + #ifdef PIN_BUZZER + if (buzzer.isPlaying()) buzzer.loop(); + #endif } }; @@ -1620,6 +1634,10 @@ void setup() { board.begin(); +#ifdef PIN_BUZZER + buzzer.begin(); +#endif + #ifdef DISPLAY_CLASS DisplayDriver* disp = NULL; if (display.begin()) { diff --git a/variants/t1000-e/platformio.ini b/variants/t1000-e/platformio.ini index 927655af..e61ea939 100644 --- a/variants/t1000-e/platformio.ini +++ b/variants/t1000-e/platformio.ini @@ -47,9 +47,12 @@ build_flags = ${t1000-e.build_flags} -D RX_BOOSTED_GAIN=true -D RF_SWITCH_TABLE -D DISPLAY_CLASS=NullDisplayDriver + -D PIN_BUZZER=25 + -D PIN_BUZZER_EN=37 ; P1/5 - required for T1000-E build_src_filter = ${t1000-e.build_src_filter} + +<../examples/companion_radio/*.cpp> lib_deps = ${t1000-e.lib_deps} densaugeo/base64 @ ~1.4.0 stevemarple/MicroNMEA @ ^2.0.6 + end2endzone/NonBlockingRTTTL@^1.3.0 \ No newline at end of file From 7e90d386e2312743ad21d80edd7e258982a687d9 Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Tue, 20 May 2025 11:52:55 +1000 Subject: [PATCH 07/20] * refactored buzzer concept to UITask * moved buzzer.h/cpp to helpers/ui --- examples/companion_radio/UITask.cpp | 16 +++++++++ examples/companion_radio/UITask.h | 8 +++++ examples/companion_radio/main.cpp | 34 +++++-------------- .../helpers/ui}/buzzer.cpp | 0 .../helpers/ui}/buzzer.h | 0 variants/t1000-e/platformio.ini | 1 + variants/t114/variant.h | 2 +- 7 files changed, 35 insertions(+), 26 deletions(-) rename {examples/companion_radio => src/helpers/ui}/buzzer.cpp (100%) rename {examples/companion_radio => src/helpers/ui}/buzzer.h (100%) diff --git a/examples/companion_radio/UITask.cpp b/examples/companion_radio/UITask.cpp index 5293c0c7..7a031b76 100644 --- a/examples/companion_radio/UITask.cpp +++ b/examples/companion_radio/UITask.cpp @@ -53,6 +53,18 @@ void UITask::begin(DisplayDriver* display, NodePrefs* node_prefs, const char* bu // v1.2.3 (1 Jan 2025) sprintf(_version_info, "%s (%s)", version, build_date); + +#ifdef PIN_BUZZER + buzzer.begin(); +#endif +} + +void UITask::soundBuzzer() { +#if defined(PIN_BUZZER) + // gemini's pick + buzzer.play("MsgRcv3:d=4,o=6,b=200:32e,32g,32b,16c7"); + //Serial.println("DBG: Buzzzzzz"); +#endif } void UITask::msgRead(int msgcount) { @@ -248,6 +260,10 @@ void UITask::loop() { buttonHandler(); userLedHandler(); +#ifdef PIN_BUZZER + if (buzzer.isPlaying()) buzzer.loop(); +#endif + if (_display != NULL && _display->isOn()) { static bool _firstBoot = true; if(_firstBoot && millis() >= BOOT_SCREEN_MILLIS) { diff --git a/examples/companion_radio/UITask.h b/examples/companion_radio/UITask.h index 58d68564..30374145 100644 --- a/examples/companion_radio/UITask.h +++ b/examples/companion_radio/UITask.h @@ -4,11 +4,18 @@ #include #include +#ifdef PIN_BUZZER + #include +#endif + #include "NodePrefs.h" class UITask { DisplayDriver* _display; mesh::MainBoard* _board; +#ifdef PIN_BUZZER + genericBuzzer buzzer; +#endif unsigned long _next_refresh, _auto_off; bool _connected; uint32_t _pin_code; @@ -37,5 +44,6 @@ public: void clearMsgPreview(); void msgRead(int msgcount); void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount); + void soundBuzzer(); void loop(); }; diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index 8b4b437f..c71fcd81 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -66,11 +66,6 @@ static UITask ui_task(&board); #endif -#ifdef PIN_BUZZER - #include "buzzer.h" - genericBuzzer buzzer; -#endif - // Believe it or not, this std C function is busted on some platforms! static uint32_t _atoi(const char* sp) { uint32_t n = 0; @@ -488,15 +483,6 @@ class MyMesh : public BaseChatMesh { return 0; // queue is empty } - void soundBuzzer() { - #if defined(PIN_BUZZER) - // gemini's pick - buzzer.play("MsgRcv3:d=4,o=6,b=200:32e,32g,32b,16c7"); - //Serial.println("DBG: Buzzzzzz"); - #endif - - } - protected: float getAirtimeBudgetFactor() const override { return _prefs.airtime_factor; @@ -533,7 +519,9 @@ protected: _serial->writeFrame(out_frame, 1 + PUB_KEY_SIZE); } } else { - soundBuzzer(); + #ifdef DISPLAY_CLASS + ui_task.soundBuzzer(); + #endif } saveContacts(); @@ -594,7 +582,9 @@ protected: frame[0] = PUSH_CODE_MSG_WAITING; // send push 'tickle' _serial->writeFrame(frame, 1); } else { - soundBuzzer(); + #ifdef DISPLAY_CLASS + ui_task.soundBuzzer(); + #endif } #ifdef DISPLAY_CLASS ui_task.newMsg(path_len, from.name, text, offline_queue_len); @@ -645,7 +635,9 @@ protected: frame[0] = PUSH_CODE_MSG_WAITING; // send push 'tickle' _serial->writeFrame(frame, 1); } else { - soundBuzzer(); + #ifdef DISPLAY_CLASS + ui_task.soundBuzzer(); + #endif } #ifdef DISPLAY_CLASS ui_task.newMsg(path_len, "Public", text, offline_queue_len); @@ -1563,10 +1555,6 @@ public: ui_task.setHasConnection(_serial->isConnected()); ui_task.loop(); #endif - - #ifdef PIN_BUZZER - if (buzzer.isPlaying()) buzzer.loop(); - #endif } }; @@ -1634,10 +1622,6 @@ void setup() { board.begin(); -#ifdef PIN_BUZZER - buzzer.begin(); -#endif - #ifdef DISPLAY_CLASS DisplayDriver* disp = NULL; if (display.begin()) { diff --git a/examples/companion_radio/buzzer.cpp b/src/helpers/ui/buzzer.cpp similarity index 100% rename from examples/companion_radio/buzzer.cpp rename to src/helpers/ui/buzzer.cpp diff --git a/examples/companion_radio/buzzer.h b/src/helpers/ui/buzzer.h similarity index 100% rename from examples/companion_radio/buzzer.h rename to src/helpers/ui/buzzer.h diff --git a/variants/t1000-e/platformio.ini b/variants/t1000-e/platformio.ini index e61ea939..00974208 100644 --- a/variants/t1000-e/platformio.ini +++ b/variants/t1000-e/platformio.ini @@ -51,6 +51,7 @@ build_flags = ${t1000-e.build_flags} -D PIN_BUZZER_EN=37 ; P1/5 - required for T1000-E build_src_filter = ${t1000-e.build_src_filter} + + + +<../examples/companion_radio/*.cpp> lib_deps = ${t1000-e.lib_deps} densaugeo/base64 @ ~1.4.0 diff --git a/variants/t114/variant.h b/variants/t114/variant.h index d4802341..a0fd2e4f 100644 --- a/variants/t114/variant.h +++ b/variants/t114/variant.h @@ -109,7 +109,7 @@ //////////////////////////////////////////////////////////////////////////////// // Buzzer -#define PIN_BUZZER (46) +// #define PIN_BUZZER (46) //////////////////////////////////////////////////////////////////////////////// From c31c48025a3618ca48aaeb059bd7ff0fbeed06d7 Mon Sep 17 00:00:00 2001 From: Rob Loranger Date: Mon, 19 May 2025 19:28:44 -0700 Subject: [PATCH 08/20] enable external notify for nano g2 ultra uses new non blocking rtttl --- variants/nano_g2_ultra/platformio.ini | 3 +++ 1 file changed, 3 insertions(+) diff --git a/variants/nano_g2_ultra/platformio.ini b/variants/nano_g2_ultra/platformio.ini index af652e3e..98feb35c 100644 --- a/variants/nano_g2_ultra/platformio.ini +++ b/variants/nano_g2_ultra/platformio.ini @@ -40,6 +40,7 @@ build_flags = -D BLE_DEBUG_LOGGING=1 -D OFFLINE_QUEUE_SIZE=256 -D DISPLAY_CLASS=SH1106Display + -D PIN_BUZZER=4 ; -D ENABLE_PRIVATE_KEY_IMPORT=1 ; -D ENABLE_PRIVATE_KEY_EXPORT=1 ; -D MESH_PACKET_LOGGING=1 @@ -47,6 +48,7 @@ build_flags = build_src_filter = ${Nano_G2_Ultra.build_src_filter} + + + + +<../examples/companion_radio> lib_deps = ${Nano_G2_Ultra.lib_deps} @@ -54,3 +56,4 @@ lib_deps = adafruit/Adafruit SH110X @ ~2.1.13 adafruit/Adafruit GFX Library @ ^1.12.1 stevemarple/MicroNMEA @ ^2.0.6 + end2endzone/NonBlockingRTTTL@^1.3.0 From 56b84408e48f371f580a4e6ed47c499c5a172bfd Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Tue, 20 May 2025 16:29:09 +1000 Subject: [PATCH 09/20] * workaround for nRF + LittleFS glitch with seek/truncate --- examples/companion_radio/main.cpp | 8 ++++---- examples/simple_secure_chat/main.cpp | 4 ++-- src/helpers/CommonCLI.cpp | 2 +- src/helpers/IdentityStore.cpp | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index c71fcd81..fab8a86f 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -271,8 +271,8 @@ class MyMesh : public BaseChatMesh { void saveContacts() { #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) + _fs->remove("/contacts3"); File file = _fs->open("/contacts3", FILE_O_WRITE); - if (file) { file.seek(0); file.truncate(); } #elif defined(RP2040_PLATFORM) File file = _fs->open("/contacts3", "w"); #else @@ -336,8 +336,8 @@ class MyMesh : public BaseChatMesh { void saveChannels() { #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) + _fs->remove("/channels2"); File file = _fs->open("/channels2", FILE_O_WRITE); - if (file) { file.seek(0); file.truncate(); } #elif defined(RP2040_PLATFORM) File file = _fs->open("/channels2", "w"); #else @@ -393,8 +393,8 @@ class MyMesh : public BaseChatMesh { sprintf(path, "/bl/%s", fname); #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) + _fs->remove(path); File f = _fs->open(path, FILE_O_WRITE); - if (f) { f.seek(0); f.truncate(); } #elif defined(RP2040_PLATFORM) File f = _fs->open(path, "w"); #else @@ -915,8 +915,8 @@ public: void savePrefs() { #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) + _fs->remove("/new_prefs"); File file = _fs->open("/new_prefs", FILE_O_WRITE); - if (file) { file.seek(0); file.truncate(); } #elif defined(RP2040_PLATFORM) File file = _fs->open("/new_prefs", "w"); #else diff --git a/examples/simple_secure_chat/main.cpp b/examples/simple_secure_chat/main.cpp index 1d0d847f..63ff20da 100644 --- a/examples/simple_secure_chat/main.cpp +++ b/examples/simple_secure_chat/main.cpp @@ -127,8 +127,8 @@ class MyMesh : public BaseChatMesh, ContactVisitor { void saveContacts() { #if defined(NRF52_PLATFORM) + _fs->remove("/contacts"); File file = _fs->open("/contacts", FILE_O_WRITE); - if (file) { file.seek(0); file.truncate(); } #elif defined(RP2040_PLATFORM) File file = _fs->open("/contacts", "w"); #else @@ -341,8 +341,8 @@ public: void savePrefs() { #if defined(NRF52_PLATFORM) + _fs->remove("/node_prefs"); File file = _fs->open("/node_prefs", FILE_O_WRITE); - if (file) { file.seek(0); file.truncate(); } #elif defined(RP2040_PLATFORM) File file = _fs->open("/node_prefs", "w"); #else diff --git a/src/helpers/CommonCLI.cpp b/src/helpers/CommonCLI.cpp index 29b3a4e2..8b8296f5 100644 --- a/src/helpers/CommonCLI.cpp +++ b/src/helpers/CommonCLI.cpp @@ -74,8 +74,8 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) { void CommonCLI::savePrefs(FILESYSTEM* fs) { #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) + fs->remove("/com_prefs"); File file = fs->open("/com_prefs", FILE_O_WRITE); - if (file) { file.seek(0); file.truncate(); } #elif defined(RP2040_PLATFORM) File file = fs->open("/com_prefs", "w"); #else diff --git a/src/helpers/IdentityStore.cpp b/src/helpers/IdentityStore.cpp index 85f146c5..dc85d69c 100644 --- a/src/helpers/IdentityStore.cpp +++ b/src/helpers/IdentityStore.cpp @@ -47,8 +47,8 @@ bool IdentityStore::save(const char *name, const mesh::LocalIdentity& id) { sprintf(filename, "%s/%s.id", _dir, name); #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) + _fs->remove(filename); File file = _fs->open(filename, FILE_O_WRITE); - if (file) { file.seek(0); file.truncate(); } #elif defined(RP2040_PLATFORM) File file = _fs->open(filename, "w"); #else @@ -69,8 +69,8 @@ bool IdentityStore::save(const char *name, const mesh::LocalIdentity& id, const sprintf(filename, "%s/%s.id", _dir, name); #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) + _fs->remove(filename); File file = _fs->open(filename, FILE_O_WRITE); - if (file) { file.seek(0); file.truncate(); } #elif defined(RP2040_PLATFORM) File file = _fs->open(filename, "w"); #else From f82844f43f5ae01d8942d3ed281a84821a08eda3 Mon Sep 17 00:00:00 2001 From: seagull9000 Date: Tue, 20 May 2025 19:09:49 +1200 Subject: [PATCH 10/20] RTTTL on message types --- examples/companion_radio/UITask.cpp | 19 +++++++++++++++---- examples/companion_radio/UITask.h | 2 +- examples/companion_radio/main.cpp | 4 ++-- src/helpers/ui/buzzer.h | 10 ++++++++++ 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/examples/companion_radio/UITask.cpp b/examples/companion_radio/UITask.cpp index 7a031b76..7d0fb613 100644 --- a/examples/companion_radio/UITask.cpp +++ b/examples/companion_radio/UITask.cpp @@ -59,12 +59,23 @@ void UITask::begin(DisplayDriver* display, NodePrefs* node_prefs, const char* bu #endif } -void UITask::soundBuzzer() { +void UITask::soundBuzzer(buzzerEventType bet) { #if defined(PIN_BUZZER) - // gemini's pick - buzzer.play("MsgRcv3:d=4,o=6,b=200:32e,32g,32b,16c7"); - //Serial.println("DBG: Buzzzzzz"); +switch(bet){ + case buzzerEventType::contactMessage: + // gemini's pick + buzzer.play("MsgRcv3:d=4,o=6,b=200:32e,32g,32b,16c7"); + break; + case buzzerEventType::channelMessage: + case buzzerEventType::roomMessage: + case buzzerEventType::newContactMessage: + case buzzerEventType::noBuzzer: + default: + break; +} #endif + Serial.print("DBG: Buzzzzzz -> "); + Serial.println((int) bet); } void UITask::msgRead(int msgcount) { diff --git a/examples/companion_radio/UITask.h b/examples/companion_radio/UITask.h index 30374145..02125e6f 100644 --- a/examples/companion_radio/UITask.h +++ b/examples/companion_radio/UITask.h @@ -44,6 +44,6 @@ public: void clearMsgPreview(); void msgRead(int msgcount); void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount); - void soundBuzzer(); + void soundBuzzer(buzzerEventType bet = buzzerEventType::noBuzzer); void loop(); }; diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index c71fcd81..14676ad8 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -520,7 +520,7 @@ protected: } } else { #ifdef DISPLAY_CLASS - ui_task.soundBuzzer(); + ui_task.soundBuzzer(buzzerEventType::newContactMessage); #endif } @@ -583,7 +583,7 @@ protected: _serial->writeFrame(frame, 1); } else { #ifdef DISPLAY_CLASS - ui_task.soundBuzzer(); + ui_task.soundBuzzer(buzzerEventType::contactMessage); #endif } #ifdef DISPLAY_CLASS diff --git a/src/helpers/ui/buzzer.h b/src/helpers/ui/buzzer.h index 9f3f3fd3..aa3e418c 100644 --- a/src/helpers/ui/buzzer.h +++ b/src/helpers/ui/buzzer.h @@ -15,6 +15,16 @@ - make message ring tone configurable */ + +enum class buzzerEventType +{ + noBuzzer, + contactMessage, + channelMessage, + roomMessage, + newContactMessage +}; + class genericBuzzer { public: From 7507f889a5871dda08048d945352d21339b47372 Mon Sep 17 00:00:00 2001 From: seagull9000 Date: Tue, 20 May 2025 19:33:21 +1200 Subject: [PATCH 11/20] fix location and naming of enum --- examples/companion_radio/UITask.cpp | 16 ++++++++-------- examples/companion_radio/UITask.h | 12 +++++++++++- examples/companion_radio/main.cpp | 6 +++--- src/helpers/ui/buzzer.cpp | 4 ++-- src/helpers/ui/buzzer.h | 9 --------- 5 files changed, 24 insertions(+), 23 deletions(-) diff --git a/examples/companion_radio/UITask.cpp b/examples/companion_radio/UITask.cpp index 7d0fb613..f97b47f4 100644 --- a/examples/companion_radio/UITask.cpp +++ b/examples/companion_radio/UITask.cpp @@ -59,23 +59,23 @@ void UITask::begin(DisplayDriver* display, NodePrefs* node_prefs, const char* bu #endif } -void UITask::soundBuzzer(buzzerEventType bet) { +void UITask::soundBuzzer(UIEventType bet) { #if defined(PIN_BUZZER) switch(bet){ - case buzzerEventType::contactMessage: + case UIEventType::contactMessage: // gemini's pick buzzer.play("MsgRcv3:d=4,o=6,b=200:32e,32g,32b,16c7"); break; - case buzzerEventType::channelMessage: - case buzzerEventType::roomMessage: - case buzzerEventType::newContactMessage: - case buzzerEventType::noBuzzer: + case UIEventType::channelMessage: + case UIEventType::roomMessage: + case UIEventType::newContactMessage: + case UIEventType::none: default: break; } #endif - Serial.print("DBG: Buzzzzzz -> "); - Serial.println((int) bet); +// Serial.print("DBG: Buzzzzzz -> "); +// Serial.println((int) bet); } void UITask::msgRead(int msgcount) { diff --git a/examples/companion_radio/UITask.h b/examples/companion_radio/UITask.h index 02125e6f..134b5a16 100644 --- a/examples/companion_radio/UITask.h +++ b/examples/companion_radio/UITask.h @@ -10,6 +10,15 @@ #include "NodePrefs.h" + enum class UIEventType +{ + none, + contactMessage, + channelMessage, + roomMessage, + newContactMessage +}; + class UITask { DisplayDriver* _display; mesh::MainBoard* _board; @@ -31,6 +40,7 @@ class UITask { void userLedHandler(); void renderBatteryIndicator(uint16_t batteryMilliVolts); + public: UITask(mesh::MainBoard* board) : _board(board), _display(NULL) { @@ -44,6 +54,6 @@ public: void clearMsgPreview(); void msgRead(int msgcount); void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount); - void soundBuzzer(buzzerEventType bet = buzzerEventType::noBuzzer); + void soundBuzzer(UIEventType bet = UIEventType::none); void loop(); }; diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index 14676ad8..a7878b51 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -520,7 +520,7 @@ protected: } } else { #ifdef DISPLAY_CLASS - ui_task.soundBuzzer(buzzerEventType::newContactMessage); + ui_task.soundBuzzer(UIEventType::newContactMessage); #endif } @@ -583,7 +583,7 @@ protected: _serial->writeFrame(frame, 1); } else { #ifdef DISPLAY_CLASS - ui_task.soundBuzzer(buzzerEventType::contactMessage); + ui_task.soundBuzzer(UIEventType::contactMessage); #endif } #ifdef DISPLAY_CLASS @@ -636,7 +636,7 @@ protected: _serial->writeFrame(frame, 1); } else { #ifdef DISPLAY_CLASS - ui_task.soundBuzzer(); + ui_task.soundBuzzer(UIEventType::channelMessage); #endif } #ifdef DISPLAY_CLASS diff --git a/src/helpers/ui/buzzer.cpp b/src/helpers/ui/buzzer.cpp index 0465bf16..ccc18cd3 100644 --- a/src/helpers/ui/buzzer.cpp +++ b/src/helpers/ui/buzzer.cpp @@ -2,8 +2,8 @@ #include "buzzer.h" void genericBuzzer::begin() { - Serial.print("DBG: Setting up buzzer on pin "); - Serial.println(PIN_BUZZER); +// Serial.print("DBG: Setting up buzzer on pin "); +// Serial.println(PIN_BUZZER); #ifdef PIN_BUZZER_EN pinMode(PIN_BUZZER_EN, OUTPUT); digitalWrite(PIN_BUZZER_EN, HIGH); diff --git a/src/helpers/ui/buzzer.h b/src/helpers/ui/buzzer.h index aa3e418c..0a500552 100644 --- a/src/helpers/ui/buzzer.h +++ b/src/helpers/ui/buzzer.h @@ -16,15 +16,6 @@ */ -enum class buzzerEventType -{ - noBuzzer, - contactMessage, - channelMessage, - roomMessage, - newContactMessage -}; - class genericBuzzer { public: From d9c1cffac2878ccf6964c93870df976cd74582eb Mon Sep 17 00:00:00 2001 From: liamcottle Date: Tue, 20 May 2025 20:51:46 +1200 Subject: [PATCH 12/20] allow setting default node name for companion via build flag --- examples/companion_radio/main.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index d97244b2..ecf03b6a 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -863,6 +863,11 @@ public: mesh::Utils::toHex(pub_key_hex, self_id.pub_key, 4); strcpy(_prefs.node_name, pub_key_hex); + // if name is provided as a build flag, use that as default node name instead + #ifdef ADVERT_NAME + strcpy(_prefs.node_name, ADVERT_NAME); + #endif + // load persisted prefs if (_fs->exists("/new_prefs")) { loadPrefsInt("/new_prefs"); // new filename From d42c3f91a2467beadad0ace509e87985db455b28 Mon Sep 17 00:00:00 2001 From: recrof Date: Tue, 20 May 2025 14:05:11 +0200 Subject: [PATCH 13/20] lilygo tbeam sx1276: forgot to add SX127X_CURRENT_LIMIT=120 --- variants/lilygo_tbeam/platformio.ini | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/variants/lilygo_tbeam/platformio.ini b/variants/lilygo_tbeam/platformio.ini index 14ce144e..c471e44c 100644 --- a/variants/lilygo_tbeam/platformio.ini +++ b/variants/lilygo_tbeam/platformio.ini @@ -7,6 +7,7 @@ build_flags = -D LILYGO_TBEAM -D RADIO_CLASS=CustomSX1276 -D WRAPPER_CLASS=CustomSX1276Wrapper + -D SX127X_CURRENT_LIMIT=120 -D LORA_TX_POWER=20 -D P_LORA_TX_LED=4 -D PIN_BOARD_SDA=21 @@ -31,8 +32,6 @@ build_flags = -D BLE_PIN_CODE=123456 -D BLE_DEBUG_LOGGING=1 -D OFFLINE_QUEUE_SIZE=256 -; -D MESH_PACKET_LOGGING=1 -; -D MESH_DEBUG=1 ; -D RADIOLIB_DEBUG_BASIC=1 ; -D ENABLE_PRIVATE_KEY_IMPORT=1 ; -D ENABLE_PRIVATE_KEY_EXPORT=1 From e14ea72699bd346ddf98fd97682c69182bacb656 Mon Sep 17 00:00:00 2001 From: recrof Date: Tue, 20 May 2025 14:20:42 +0200 Subject: [PATCH 14/20] fix: missing SX126X_CURRENT_LIMIT --- 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 d3447673..e618613c 100644 --- a/variants/lilygo_tbeam_supreme_SX1262/platformio.ini +++ b/variants/lilygo_tbeam_supreme_SX1262/platformio.ini @@ -12,6 +12,7 @@ build_flags = -D WRAPPER_CLASS=CustomSX1262Wrapper ;-D DISPLAY_CLASS=SSD1306Display ;Needs to be modified for SH1106 -D SX126X_RX_BOOSTED_GAIN=1 + -D SX126X_CURRENT_LIMIT=140 build_src_filter = ${esp32_base.build_src_filter} +<../variants/lilygo_tbeam_supreme_SX1262> board_build.partitions = min_spiffs.csv ; get around 4mb flash limit From 98d94d9423066518c9f61aff7a0564b1651ef842 Mon Sep 17 00:00:00 2001 From: Normunds Gavars Date: Thu, 22 May 2025 00:19:00 +0300 Subject: [PATCH 15/20] 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 16/20] 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 17/20] 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 18/20] 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 19/20] 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 20/20] * 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();