Skip to content

Commit

Permalink
INA3221 sensor: use for bus voltage & environment metrics (#4215)
Browse files Browse the repository at this point in the history
* use INA3221 for bus voltage; fixes for telemetry variants

- add to sensors available for environment telemetry
  (to report voltage/current)
- add vars to define channels to use for battery voltage
  (for getBusVoltage) and environment metrics (default
  to CH1 for both)
- write to the correct fields on the measurement struct
  depending on the measurement variant, and DRY up the
  sensor measurement collection code a bit
- this might be suitable for a common implementation for
  the INA* sensors in a future PR...

* formatting

* derp

---------

Co-authored-by: Ben Meadors <[email protected]>
  • Loading branch information
warrenguy and thebentern authored Jul 11, 2024
1 parent e79a7dc commit 974fc31
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 9 deletions.
5 changes: 5 additions & 0 deletions src/Power.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,11 @@ class AnalogBatteryLevel : public HasBatteryLevel
if (!ina260Sensor.isInitialized())
return ina260Sensor.runOnce() > 0;
return ina260Sensor.isRunning();
} else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA3221].first ==
config.power.device_battery_ina_address) {
if (!ina3221Sensor.isInitialized())
return ina3221Sensor.runOnce() > 0;
return ina3221Sensor.isRunning();
}
return false;
}
Expand Down
11 changes: 11 additions & 0 deletions src/modules/Telemetry/EnvironmentTelemetry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ int32_t EnvironmentTelemetryModule::runOnce()
result = ina219Sensor.runOnce();
if (ina260Sensor.hasSensor())
result = ina260Sensor.runOnce();
if (ina3221Sensor.hasSensor())
result = ina3221Sensor.runOnce();
if (veml7700Sensor.hasSensor())
result = veml7700Sensor.runOnce();
if (tsl2591Sensor.hasSensor())
Expand Down Expand Up @@ -325,6 +327,10 @@ bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m
valid = valid && ina260Sensor.getMetrics(m);
hasSensor = true;
}
if (ina3221Sensor.hasSensor()) {
valid = valid && ina3221Sensor.getMetrics(m);
hasSensor = true;
}
if (veml7700Sensor.hasSensor()) {
valid = valid && veml7700Sensor.getMetrics(m);
hasSensor = true;
Expand Down Expand Up @@ -499,6 +505,11 @@ AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule
if (result != AdminMessageHandleResult::NOT_HANDLED)
return result;
}
if (ina3221Sensor.hasSensor()) {
result = ina3221Sensor.handleAdminMessage(mp, request, response);
if (result != AdminMessageHandleResult::NOT_HANDLED)
return result;
}
if (veml7700Sensor.hasSensor()) {
result = veml7700Sensor.handleAdminMessage(mp, request, response);
if (result != AdminMessageHandleResult::NOT_HANDLED)
Expand Down
65 changes: 56 additions & 9 deletions src/modules/Telemetry/Sensor/INA3221Sensor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,69 @@ int32_t INA3221Sensor::runOnce()

void INA3221Sensor::setup() {}

struct _INA3221Measurement INA3221Sensor::getMeasurement(ina3221_ch_t ch)
{
struct _INA3221Measurement measurement;

measurement.voltage = ina3221.getVoltage(ch);
measurement.current = ina3221.getCurrent(ch);

return measurement;
}

struct _INA3221Measurements INA3221Sensor::getMeasurements()
{
struct _INA3221Measurements measurements;

// INA3221 has 3 channels starting from 0
for (int i = 0; i < 3; i++) {
measurements.measurements[i] = getMeasurement((ina3221_ch_t)i);
}

return measurements;
}

bool INA3221Sensor::getMetrics(meshtastic_Telemetry *measurement)
{
measurement->variant.environment_metrics.voltage = ina3221.getVoltage(INA3221_CH1);
measurement->variant.environment_metrics.current = ina3221.getCurrent(INA3221_CH1);
measurement->variant.power_metrics.ch1_voltage = ina3221.getVoltage(INA3221_CH1);
measurement->variant.power_metrics.ch1_current = ina3221.getCurrent(INA3221_CH1);
measurement->variant.power_metrics.ch2_voltage = ina3221.getVoltage(INA3221_CH2);
measurement->variant.power_metrics.ch2_current = ina3221.getCurrent(INA3221_CH2);
measurement->variant.power_metrics.ch3_voltage = ina3221.getVoltage(INA3221_CH3);
measurement->variant.power_metrics.ch3_current = ina3221.getCurrent(INA3221_CH3);
switch (measurement->which_variant) {
case meshtastic_Telemetry_environment_metrics_tag:
return getEnvironmentMetrics(measurement);

case meshtastic_Telemetry_power_metrics_tag:
return getPowerMetrics(measurement);
}

// unsupported metric
return false;
}

bool INA3221Sensor::getEnvironmentMetrics(meshtastic_Telemetry *measurement)
{
struct _INA3221Measurement m = getMeasurement(ENV_CH);

measurement->variant.environment_metrics.voltage = m.voltage;
measurement->variant.environment_metrics.current = m.current;

return true;
}

bool INA3221Sensor::getPowerMetrics(meshtastic_Telemetry *measurement)
{
struct _INA3221Measurements m = getMeasurements();

measurement->variant.power_metrics.ch1_voltage = m.measurements[INA3221_CH1].voltage;
measurement->variant.power_metrics.ch1_current = m.measurements[INA3221_CH1].current;
measurement->variant.power_metrics.ch2_voltage = m.measurements[INA3221_CH2].voltage;
measurement->variant.power_metrics.ch2_current = m.measurements[INA3221_CH2].current;
measurement->variant.power_metrics.ch3_voltage = m.measurements[INA3221_CH3].voltage;
measurement->variant.power_metrics.ch3_current = m.measurements[INA3221_CH3].current;

return true;
}

uint16_t INA3221Sensor::getBusVoltageMv()
{
return lround(ina3221.getVoltage(INA3221_CH1) * 1000);
return lround(ina3221.getVoltage(BAT_CH) * 1000);
}

#endif
25 changes: 25 additions & 0 deletions src/modules/Telemetry/Sensor/INA3221Sensor.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,21 @@ class INA3221Sensor : public TelemetrySensor, VoltageSensor
private:
INA3221 ina3221 = INA3221(INA3221_ADDR42_SDA);

// channel to report voltage/current for environment metrics
ina3221_ch_t ENV_CH = INA3221_CH1;

// channel to report battery voltage for device_battery_ina_address
ina3221_ch_t BAT_CH = INA3221_CH1;

// get a single measurement for a channel
struct _INA3221Measurement getMeasurement(ina3221_ch_t ch);

// get all measurements for all channels
struct _INA3221Measurements getMeasurements();

bool getEnvironmentMetrics(meshtastic_Telemetry *measurement);
bool getPowerMetrics(meshtastic_Telemetry *measurement);

protected:
void setup() override;

Expand All @@ -22,4 +37,14 @@ class INA3221Sensor : public TelemetrySensor, VoltageSensor
virtual uint16_t getBusVoltageMv() override;
};

struct _INA3221Measurement {
float voltage;
float current;
};

struct _INA3221Measurements {
// INA3221 has 3 channels
struct _INA3221Measurement measurements[3];
};

#endif

1 comment on commit 974fc31

@gretel
Copy link

@gretel gretel commented on 974fc31 Jul 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool, built a node with a ina219 on the solar power input just to realize i can not use it for power metrics. regards

Please sign in to comment.