From cd787232caadc35794e3a406e22645bc2ed1176f Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Fri, 2 Jun 2023 06:32:34 -0500 Subject: [PATCH] Use INA for device battery level (#2536) * WIP * Continued wip * We got em * Voltage sensor base class * INA voltage * Log it * Stacie's mom has got it going on * Move declaration up * Last one * Sneaky little bugger * Macro guard to avoid calling methods --- src/Power.cpp | 43 ++++++++++++++++++- src/main.h | 4 +- .../Telemetry/EnvironmentTelemetry.cpp | 12 +----- src/modules/Telemetry/Sensor/INA219Sensor.cpp | 13 +++++- src/modules/Telemetry/Sensor/INA219Sensor.h | 4 +- src/modules/Telemetry/Sensor/INA260Sensor.cpp | 10 ++++- src/modules/Telemetry/Sensor/INA260Sensor.h | 4 +- .../Telemetry/Sensor/TelemetrySensor.h | 9 +++- src/modules/Telemetry/Sensor/VoltageSensor.h | 7 +++ src/power.h | 8 +++- 10 files changed, 92 insertions(+), 22 deletions(-) create mode 100644 src/modules/Telemetry/Sensor/VoltageSensor.h diff --git a/src/Power.cpp b/src/Power.cpp index 1f4c3535a..37d80a31f 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -37,12 +37,18 @@ static const adc_atten_t atten = ADC_ATTENUATION; #endif #endif // BATTERY_PIN && ARCH_ESP32 +#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) +INA260Sensor ina260Sensor; +INA219Sensor ina219Sensor; +#endif + #ifdef HAS_PMU #include "XPowersAXP192.tpp" #include "XPowersAXP2101.tpp" #include "XPowersLibInterface.hpp" XPowersLibInterface *PMU = NULL; #else + // Copy of the base class defined in axp20x.h. // I'd rather not inlude axp20x.h as it brings Wire dependency. class HasBatteryLevel @@ -128,6 +134,13 @@ class AnalogBatteryLevel : public HasBatteryLevel virtual uint16_t getBattVoltage() override { +#if defined(HAS_TELEMETRY) && !defined(ARCH_PORTDUINO) && !defined(HAS_PMU) + if (hasINA()) { + LOG_DEBUG("Using INA on I2C addr 0x%x for device battery voltage\n", config.power.device_battery_ina_address); + return getINAVoltage(); + } +#endif + #ifndef ADC_MULTIPLIER #define ADC_MULTIPLIER 2.0 #endif @@ -246,6 +259,35 @@ class AnalogBatteryLevel : public HasBatteryLevel const float fullVolt = BAT_FULLVOLT, emptyVolt = BAT_EMPTYVOLT, chargingVolt = BAT_CHARGINGVOLT, noBatVolt = BAT_NOBATVOLT; float last_read_value = 0.0; uint32_t last_read_time_ms = 0; + +#if defined(HAS_TELEMETRY) && !defined(ARCH_PORTDUINO) + uint16_t getINAVoltage() + { + if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219] == config.power.device_battery_ina_address) { + return ina219Sensor.getBusVoltageMv(); + } else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA260] == config.power.device_battery_ina_address) { + return ina260Sensor.getBusVoltageMv(); + } + return 0; + } + + bool hasINA() + { + if (!config.power.device_battery_ina_address) { + return false; + } + if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219] == config.power.device_battery_ina_address) { + if (!ina219Sensor.isInitialized()) + return ina219Sensor.runOnce() > 0; + return ina219Sensor.isRunning(); + } else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA260] == config.power.device_battery_ina_address) { + if (!ina260Sensor.isInitialized()) + return ina260Sensor.runOnce() > 0; + return ina260Sensor.isRunning(); + } + return false; + } +#endif }; AnalogBatteryLevel analogLevel; @@ -639,7 +681,6 @@ bool Power::axpChipInit() // GNSS VDD 3300mV PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300); PMU->enablePowerOutput(XPOWERS_ALDO3); - } else if (HW_VENDOR == meshtastic_HardwareModel_LILYGO_TBEAM_S3_CORE) { // t-beam s3 core /** diff --git a/src/main.h b/src/main.h index 0d23dd10c..93baec590 100644 --- a/src/main.h +++ b/src/main.h @@ -38,8 +38,6 @@ extern bool isUSBPowered; extern ATECCX08A atecc; #endif -extern uint8_t nodeTelemetrySensorsMap[_meshtastic_TelemetrySensorType_MAX + 1]; - extern int TCPPort; // set by Portduino // Global Screen singleton. @@ -69,4 +67,4 @@ void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop(), clearBonds(); meshtastic_DeviceMetadata getDeviceMetadata(); // FIXME, we default to 4MHz SPI, SPI mode 0, check if the datasheet says it can really do that -extern SPISettings spiSettings; +extern SPISettings spiSettings; \ No newline at end of file diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index 76385197a..5cdc4bf4d 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -7,6 +7,7 @@ #include "Router.h" #include "configuration.h" #include "main.h" +#include "power.h" #include #include @@ -14,8 +15,6 @@ #include "Sensor/BME280Sensor.h" #include "Sensor/BME680Sensor.h" #include "Sensor/BMP280Sensor.h" -#include "Sensor/INA219Sensor.h" -#include "Sensor/INA260Sensor.h" #include "Sensor/LPS22HBSensor.h" #include "Sensor/MCP9808Sensor.h" #include "Sensor/SHT31Sensor.h" @@ -25,8 +24,6 @@ BMP280Sensor bmp280Sensor; BME280Sensor bme280Sensor; BME680Sensor bme680Sensor; MCP9808Sensor mcp9808Sensor; -INA260Sensor ina260Sensor; -INA219Sensor ina219Sensor; SHTC3Sensor shtc3Sensor; LPS22HBSensor lps22hbSensor; SHT31Sensor sht31Sensor; @@ -83,15 +80,10 @@ int32_t EnvironmentTelemetryModule::runOnce() result = bme680Sensor.runOnce(); if (mcp9808Sensor.hasSensor()) result = mcp9808Sensor.runOnce(); - if (ina260Sensor.hasSensor()) - result = ina260Sensor.runOnce(); - if (ina219Sensor.hasSensor()) - result = ina219Sensor.runOnce(); if (shtc3Sensor.hasSensor()) result = shtc3Sensor.runOnce(); - if (lps22hbSensor.hasSensor()) { + if (lps22hbSensor.hasSensor()) result = lps22hbSensor.runOnce(); - } if (sht31Sensor.hasSensor()) result = sht31Sensor.runOnce(); } diff --git a/src/modules/Telemetry/Sensor/INA219Sensor.cpp b/src/modules/Telemetry/Sensor/INA219Sensor.cpp index bffa1e367..1dd7f7f2c 100644 --- a/src/modules/Telemetry/Sensor/INA219Sensor.cpp +++ b/src/modules/Telemetry/Sensor/INA219Sensor.cpp @@ -12,8 +12,12 @@ int32_t INA219Sensor::runOnce() if (!hasSensor()) { return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; } - ina219 = Adafruit_INA219(nodeTelemetrySensorsMap[sensorType]); - status = ina219.begin(); + if (!ina219.success()) { + ina219 = Adafruit_INA219(nodeTelemetrySensorsMap[sensorType]); + status = ina219.begin(); + } else { + status = ina219.success(); + } return initI2CSensor(); } @@ -24,4 +28,9 @@ bool INA219Sensor::getMetrics(meshtastic_Telemetry *measurement) measurement->variant.environment_metrics.voltage = ina219.getBusVoltage_V(); measurement->variant.environment_metrics.current = ina219.getCurrent_mA(); return true; +} + +uint16_t INA219Sensor::getBusVoltageMv() +{ + return lround(ina219.getBusVoltage_V() * 1000); } \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/INA219Sensor.h b/src/modules/Telemetry/Sensor/INA219Sensor.h index dc6c0a5af..f11a571cc 100644 --- a/src/modules/Telemetry/Sensor/INA219Sensor.h +++ b/src/modules/Telemetry/Sensor/INA219Sensor.h @@ -1,8 +1,9 @@ #include "../mesh/generated/meshtastic/telemetry.pb.h" #include "TelemetrySensor.h" +#include "VoltageSensor.h" #include -class INA219Sensor : virtual public TelemetrySensor +class INA219Sensor : virtual public TelemetrySensor, VoltageSensor { private: Adafruit_INA219 ina219; @@ -14,4 +15,5 @@ class INA219Sensor : virtual public TelemetrySensor INA219Sensor(); virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual uint16_t getBusVoltageMv() override; }; \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/INA260Sensor.cpp b/src/modules/Telemetry/Sensor/INA260Sensor.cpp index ee0256e62..034fecca0 100644 --- a/src/modules/Telemetry/Sensor/INA260Sensor.cpp +++ b/src/modules/Telemetry/Sensor/INA260Sensor.cpp @@ -12,7 +12,10 @@ int32_t INA260Sensor::runOnce() if (!hasSensor()) { return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; } - status = ina260.begin(nodeTelemetrySensorsMap[sensorType]); + + if (!status) { + status = ina260.begin(nodeTelemetrySensorsMap[sensorType]); + } return initI2CSensor(); } @@ -24,4 +27,9 @@ bool INA260Sensor::getMetrics(meshtastic_Telemetry *measurement) measurement->variant.environment_metrics.voltage = ina260.readBusVoltage() / 1000; measurement->variant.environment_metrics.current = ina260.readCurrent(); return true; +} + +uint16_t INA260Sensor::getBusVoltageMv() +{ + return lround(ina260.readBusVoltage()); } \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/INA260Sensor.h b/src/modules/Telemetry/Sensor/INA260Sensor.h index 1dcb596e6..8ea532697 100644 --- a/src/modules/Telemetry/Sensor/INA260Sensor.h +++ b/src/modules/Telemetry/Sensor/INA260Sensor.h @@ -1,8 +1,9 @@ #include "../mesh/generated/meshtastic/telemetry.pb.h" #include "TelemetrySensor.h" +#include "VoltageSensor.h" #include -class INA260Sensor : virtual public TelemetrySensor +class INA260Sensor : virtual public TelemetrySensor, VoltageSensor { private: Adafruit_INA260 ina260 = Adafruit_INA260(); @@ -14,4 +15,5 @@ class INA260Sensor : virtual public TelemetrySensor INA260Sensor(); virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual uint16_t getBusVoltageMv() override; }; \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/TelemetrySensor.h b/src/modules/Telemetry/Sensor/TelemetrySensor.h index 7a579ef5c..dec81e061 100644 --- a/src/modules/Telemetry/Sensor/TelemetrySensor.h +++ b/src/modules/Telemetry/Sensor/TelemetrySensor.h @@ -1,9 +1,9 @@ #pragma once #include "../mesh/generated/meshtastic/telemetry.pb.h" #include "NodeDB.h" -#include "main.h" #define DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000 +extern uint8_t nodeTelemetrySensorsMap[_meshtastic_TelemetrySensorType_MAX + 1]; class TelemetrySensor { @@ -18,6 +18,7 @@ class TelemetrySensor const char *sensorName; meshtastic_TelemetrySensorType sensorType; unsigned status; + bool initialized = false; int32_t initI2CSensor() { @@ -28,6 +29,7 @@ class TelemetrySensor LOG_INFO("Opened %s sensor on default i2c bus\n", sensorName); setup(); } + initialized = true; return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; } virtual void setup(); @@ -36,5 +38,8 @@ class TelemetrySensor bool hasSensor() { return sensorType < sizeof(nodeTelemetrySensorsMap) && nodeTelemetrySensorsMap[sensorType] > 0; } virtual int32_t runOnce() = 0; + virtual bool isInitialized() { return initialized; } + virtual bool isRunning() { return status > 0; } + virtual bool getMetrics(meshtastic_Telemetry *measurement) = 0; -}; +}; \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/VoltageSensor.h b/src/modules/Telemetry/Sensor/VoltageSensor.h new file mode 100644 index 000000000..f2f28fb06 --- /dev/null +++ b/src/modules/Telemetry/Sensor/VoltageSensor.h @@ -0,0 +1,7 @@ +#pragma once + +class VoltageSensor +{ + public: + virtual uint16_t getBusVoltageMv() = 0; +}; \ No newline at end of file diff --git a/src/power.h b/src/power.h index c47e78466..e90e3f21b 100644 --- a/src/power.h +++ b/src/power.h @@ -22,6 +22,13 @@ extern RTC_NOINIT_ATTR uint64_t RTC_reg_b; #include "soc/sens_reg.h" // needed for adc pin reset #endif +#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) +#include "modules/Telemetry/Sensor/INA219Sensor.h" +#include "modules/Telemetry/Sensor/INA260Sensor.h" +extern INA260Sensor ina260Sensor; +extern INA219Sensor ina219Sensor; +#endif + class Power : private concurrency::OSThread { @@ -41,7 +48,6 @@ class Power : private concurrency::OSThread /// Setup a xpowers chip axp192/axp2101, return true if found bool axpChipInit(); - /// Setup a simple ADC input based battery sensor bool analogInit();