diff --git a/platformio.ini b/platformio.ini
index c0eb6fedb..c01a41b76 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -202,3 +202,5 @@ lib_deps =
sensirion/Sensirion Core@0.7.1
# renovate: datasource=custom.pio depName=Sensirion I2C SCD4x packageName=sensirion/library/Sensirion I2C SCD4x
sensirion/Sensirion I2C SCD4x@1.1.0
+ # renovate: datasource=custom.pio depName=Adafruit ADS1X15 packageName=adafruit/library/Adafruit ADS1X15 Library
+ adafruit/Adafruit ADS1X15@2.5.0
diff --git a/src/configuration.h b/src/configuration.h
index cddc7ba7a..92df118d7 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -195,6 +195,10 @@ along with this program. If not, see .
#define LTR390UV_ADDR 0x53
#define XPOWERS_AXP192_AXP2101_ADDRESS 0x34 // same adress as TCA8418
#define PCT2075_ADDR 0x37
+#define ADS1X15_ADDR 0x48 // same address as FT6336U
+#define ADS1X15_ADDR_ALT1 0x49
+#define ADS1X15_ADDR_ALT2 0x4A
+#define ADS1X15_ADDR_ALT3 0x4B
// -----------------------------------------------------------------------------
// ACCELEROMETER
diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h
index dd290db98..232c43c34 100644
--- a/src/detect/ScanI2C.h
+++ b/src/detect/ScanI2C.h
@@ -75,6 +75,7 @@ class ScanI2C
TCA8418KB,
PCT2075,
BMM150,
+ ADS1X15,
} DeviceType;
// typedef uint8_t DeviceAddress;
diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp
index 5734fc200..6c8851fc7 100644
--- a/src/detect/ScanI2CTwoWire.cpp
+++ b/src/detect/ScanI2CTwoWire.cpp
@@ -564,7 +564,16 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
}
break;
- case 0x48: {
+ case 0x48: { // same as ADS1X15 main address
+
+ // ADS1X15 default config register is 8583h
+ registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x01), 2);
+ if (registerValue == 0x8583) {
+ type = ADS1X15;
+ logFoundDevice("ADS1X15", (uint8_t)addr.address);
+ break;
+ }
+
i2cBus->beginTransmission(addr.address);
uint8_t getInfo[] = {0x5A, 0xC0, 0x00, 0xFF, 0xFC};
uint8_t expectedInfo[] = {0xa5, 0xE0, 0x00, 0x3F, 0x19};
@@ -584,6 +593,17 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
break;
}
+ case ADS1X15_ADDR_ALT1:
+ case ADS1X15_ADDR_ALT2:
+ case ADS1X15_ADDR_ALT3:
+ // ADS1X15 default config register is 8583h
+ registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x01), 2);
+ if (registerValue == 0x8583) {
+ type = ADS1X15;
+ logFoundDevice("ADS1X15", (uint8_t)addr.address);
+ break;
+ }
+
default:
LOG_INFO("Device found at address 0x%x was not able to be enumerated", (uint8_t)addr.address);
}
diff --git a/src/main.cpp b/src/main.cpp
index 9f3e4fe6a..be64f2a64 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -703,6 +703,7 @@ void setup()
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::RAK12035, meshtastic_TelemetrySensorType_RAK12035);
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::PCT2075, meshtastic_TelemetrySensorType_PCT2075);
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SCD4X, meshtastic_TelemetrySensorType_SCD4X);
+ scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::ADS1X15, meshtastic_TelemetrySensorType_ADS1X15);
i2cScanner.reset();
#endif
diff --git a/src/modules/Telemetry/PowerTelemetry.cpp b/src/modules/Telemetry/PowerTelemetry.cpp
index a92013d01..435859c91 100644
--- a/src/modules/Telemetry/PowerTelemetry.cpp
+++ b/src/modules/Telemetry/PowerTelemetry.cpp
@@ -22,6 +22,13 @@
#include "graphics/ScreenFonts.h"
#include
+#if __has_include()
+#include "Sensor/ADS1X15Sensor.h"
+ADS1X15Sensor ads1x15Sensor;
+#else
+NullSensor ads1x15Sensor;
+#endif
+
namespace graphics
{
extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *titleStr, bool battery_only);
@@ -74,6 +81,8 @@ int32_t PowerTelemetryModule::runOnce()
result = ina3221Sensor.isInitialized() ? 0 : ina3221Sensor.runOnce();
if (max17048Sensor.hasSensor())
result = max17048Sensor.isInitialized() ? 0 : max17048Sensor.runOnce();
+ if (ads1x15Sensor.hasSensor())
+ result = ads1x15Sensor.isInitialized() ? 0 : ads1x15Sensor.runOnce();
}
// it's possible to have this module enabled, only for displaying values on the screen.
@@ -205,6 +214,8 @@ bool PowerTelemetryModule::getPowerTelemetry(meshtastic_Telemetry *m)
valid = ina3221Sensor.getMetrics(m);
if (max17048Sensor.hasSensor())
valid = max17048Sensor.getMetrics(m);
+ if (ads1x15Sensor.hasSensor())
+ valid = ads1x15Sensor.getMetrics(m);
#endif
return valid;
@@ -246,9 +257,10 @@ bool PowerTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
m.time = getTime();
if (getPowerTelemetry(&m)) {
LOG_INFO("Send: ch1_voltage=%f, ch1_current=%f, ch2_voltage=%f, ch2_current=%f, "
- "ch3_voltage=%f, ch3_current=%f",
+ "ch3_voltage=%f, ch3_current=%f, ch4_voltage=%f",
m.variant.power_metrics.ch1_voltage, m.variant.power_metrics.ch1_current, m.variant.power_metrics.ch2_voltage,
- m.variant.power_metrics.ch2_current, m.variant.power_metrics.ch3_voltage, m.variant.power_metrics.ch3_current);
+ m.variant.power_metrics.ch2_current, m.variant.power_metrics.ch3_voltage, m.variant.power_metrics.ch3_current,
+ m.variant.power_metrics.ch4_voltage);
sensor_read_error_count = 0;
diff --git a/src/modules/Telemetry/Sensor/ADS1X15Sensor.cpp b/src/modules/Telemetry/Sensor/ADS1X15Sensor.cpp
new file mode 100644
index 000000000..deaf22619
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/ADS1X15Sensor.cpp
@@ -0,0 +1,111 @@
+#include "configuration.h"
+
+#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include()
+
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "ADS1X15Sensor.h"
+#include "TelemetrySensor.h"
+#include
+
+ADS1X15Sensor::ADS1X15Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_ADS1X15, "ADS1X15") {}
+
+int32_t ADS1X15Sensor::runOnce()
+{
+ LOG_INFO("Init sensor: %s", sensorName);
+ if (!hasSensor()) {
+ return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
+ }
+
+ status = ads1x15.begin(nodeTelemetrySensorsMap[sensorType].first);
+
+ return initI2CSensor();
+}
+
+void ADS1X15Sensor::setup() {}
+
+struct _ADS1X15Measurement ADS1X15Sensor::getMeasurement(ads1x15_ch_t ch)
+{
+ struct _ADS1X15Measurement measurement;
+
+ // Reset gain
+ ads1x15.setGain(GAIN_TWOTHIRDS);
+ double voltage_range = 6.144;
+
+ // Get value with full range
+ uint16_t value = ads.readADC_SingleEnded(ch);
+
+ // Dynamic gain, to increase resolution of low voltage values
+ // If value is under 4.096v increase the gain depending on voltage
+ if (value < 21845) {
+ if (value > 10922) {
+
+ // 1x gain, 4.096V
+ ads1x15.setGain(GAIN_ONE);
+ voltage_range = 4.096;
+
+ } else if (value > 5461) {
+
+ // 2x gain, 2.048V
+ ads1x15.setGain(GAIN_TWO);
+ voltage_range = 2.048;
+
+ } else if (value > 2730) {
+
+ // 4x gain, 1.024V
+ ads1x15.setGain(GAIN_FOUR);
+ voltage_range = 1.024;
+
+ } else if (value > 1365) {
+
+ // 8x gain, 0.25V
+ ads1x15.setGain(GAIN_EIGHT);
+ voltage_range = 0.512;
+
+ } else {
+
+ // 16x gain, 0.125V
+ ads1x15.setGain(GAIN_SIXTEEN);
+ voltage_range = 0.256;
+ }
+
+ // Get the value again
+ value = ads1x15.readADC_SingleEnded(ch);
+ }
+
+ reading = (float)value / 32768 * voltage_range;
+ measurement.voltage = reading;
+
+ return measurement;
+}
+
+struct _ADS1X15Measurements ADS1X15Sensor::getMeasurements()
+{
+ struct _ADS1X15Measurements measurements;
+
+ // ADS1X15 has 4 channels starting from 0
+ for (int i = 0; i < 4; i++) {
+ measurements.measurements[i] = getMeasurement((ads1x15_ch_t)i);
+ }
+
+ return measurements;
+}
+
+bool ADS1X15Sensor::getMetrics(meshtastic_Telemetry *measurement)
+{
+
+ struct _ADS1X15Measurements m = getMeasurements();
+
+ measurement->variant.power_metrics.has_ch1_voltage = true;
+ measurement->variant.power_metrics.has_ch2_voltage = true;
+ measurement->variant.power_metrics.has_ch3_voltage = true;
+ measurement->variant.power_metrics.has_ch4_voltage = true;
+
+ measurement->variant.power_metrics.ch1_voltage = m.measurements[0].voltage;
+ measurement->variant.power_metrics.ch2_voltage = m.measurements[1].voltage;
+ measurement->variant.power_metrics.ch3_voltage = m.measurements[2].voltage;
+ measurement->variant.power_metrics.ch4_voltage = m.measurements[3].voltage;
+
+ return true;
+}
+
+#endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/ADS1X15Sensor.h b/src/modules/Telemetry/Sensor/ADS1X15Sensor.h
new file mode 100644
index 000000000..ca3422736
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/ADS1X15Sensor.h
@@ -0,0 +1,24 @@
+#include "configuration.h"
+
+#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include()
+
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "TelemetrySensor.h"
+#include "VoltageSensor.h"
+#include
+
+class ADS1X15Sensor : public TelemetrySensor, VoltageSensor
+{
+ private:
+ Adafruit_ADS1015 ads1x15;
+
+ protected:
+ virtual void setup() override;
+
+ public:
+ ADS1X15Sensor();
+ virtual int32_t runOnce() override;
+ virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
+};
+
+#endif
\ No newline at end of file