INA260 + INA219 sensor support (#1501)

* INA219 + INA260 support in telemetry

* Protobuf update

* Fixes + debug statement

* Fix size

* Fix conversion from mv

* Added getRegisterValue for i2cscan
raytac-diy
Ben Meadors 2022-06-11 16:44:56 -05:00 zatwierdzone przez GitHub
rodzic 3fd756900a
commit 90957e6994
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
17 zmienionych plików z 182 dodań i 58 usunięć

Wyświetl plik

@ -84,7 +84,8 @@ lib_deps =
adafruit/Adafruit BME280 Library@^2.2.2
adafruit/Adafruit BME680 Library@^2.0.1
adafruit/Adafruit MCP9808 Library@^2.0.0
adafruit/Adafruit INA260 Library@^1.5.0
adafruit/Adafruit INA219@^1.2.0
; Common settings for ESP targes, mixin with extends = esp32_base
[esp32_base]
extends = arduino_base

@ -1 +1 @@
Subproject commit 33b3ab5fde6b6ef158e3b111bf240d1d59c152ef
Subproject commit dbd4219a862b26b5c6fa6569bd8faa42ab8852a5

Wyświetl plik

@ -177,6 +177,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define BME_ADDR 0x76
#define BME_ADDR_ALTERNATE 0x77
#define MCP9808_ADDR 0x18
#define INA_ADDR 0x40
#define INA_ADDR_ALTERNATE 0x41
// -----------------------------------------------------------------------------
// GPS

Wyświetl plik

@ -4,6 +4,24 @@
#include "mesh/generated/telemetry.pb.h"
#ifndef NO_WIRE
uint16_t getRegisterValue(uint8_t address, uint8_t reg, uint8_t length) {
uint16_t value = 0x00;
Wire.beginTransmission(address);
Wire.write(reg);
Wire.endTransmission();
delay(20);
Wire.requestFrom((int)address, length);
DEBUG_MSG("Wire.available() = %d\n", Wire.available());
if (Wire.available() == 2) {
// Read MSB, then LSB
value = (uint16_t)Wire.read() << 8;
value |= Wire.read();
} else if (Wire.available()) {
value = Wire.read();
}
return value;
}
uint8_t oled_probe(byte addr)
{
uint8_t r = 0;
@ -35,7 +53,7 @@ uint8_t oled_probe(byte addr)
void scanI2Cdevice(void)
{
byte err, addr;
uint8_t r = 0x00;
uint16_t registerValue = 0x00;
int nDevices = 0;
for (addr = 1; addr < 127; addr++) {
Wire.beginTransmission(addr);
@ -75,15 +93,8 @@ void scanI2Cdevice(void)
if (addr == CARDKB_ADDR) {
cardkb_found = addr;
// Do we have the RAK14006 instead?
Wire.beginTransmission(addr);
Wire.write(0x04); // SENSOR_GET_VERSION
Wire.endTransmission();
delay(20);
Wire.requestFrom((int)addr, 1);
if (Wire.available()) {
r = Wire.read();
}
if (r == 0x02) { // KEYPAD_VERSION
registerValue = getRegisterValue(addr, 0x04, 1);
if (registerValue == 0x02) { // KEYPAD_VERSION
DEBUG_MSG("RAK14004 found\n");
kb_model = 0x02;
} else {
@ -106,22 +117,26 @@ void scanI2Cdevice(void)
}
#endif
if (addr == BME_ADDR || addr == BME_ADDR_ALTERNATE) {
Wire.beginTransmission(addr);
Wire.write(0xD0); // GET_ID
Wire.endTransmission();
delay(20);
Wire.requestFrom((int)addr, 1);
if (Wire.available()) {
r = Wire.read();
}
if (r == 0x61) {
registerValue = getRegisterValue(addr, 0xD0, 1); // GET_ID
if (registerValue == 0x61) {
DEBUG_MSG("BME-680 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[TelemetrySensorType_BME680] = addr;
} else if (r == 0x60) {
} else if (registerValue == 0x60) {
DEBUG_MSG("BME-280 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[TelemetrySensorType_BME280] = addr;
}
}
if (addr == INA_ADDR || addr == INA_ADDR_ALTERNATE) {
registerValue = getRegisterValue(addr, 0xFE, 2);
DEBUG_MSG("Register MFG_UID: 0x%x\n", registerValue);
if (registerValue == 0x5449) {
DEBUG_MSG("INA260 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[TelemetrySensorType_INA260] = addr;
} else { // Assume INA219 if INA260 ID is not found
DEBUG_MSG("INA219 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[TelemetrySensorType_INA219] = addr;
}
}
if (addr == MCP9808_ADDR) {
nodeTelemetrySensorsMap[TelemetrySensorType_MCP9808] = addr;
DEBUG_MSG("MCP9808 sensor found at address 0x%x\n", (uint8_t)addr);

Wyświetl plik

@ -89,8 +89,9 @@ bool eink_found = true;
uint32_t serialSinceMsec;
bool axp192_found;
// Array map of sensor types (as array index) and i2c address as value we'll find in the i2c scan
uint8_t nodeTelemetrySensorsMap[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
uint8_t nodeTelemetrySensorsMap[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Router *router = NULL; // Users of router don't care what sort of subclass implements that API

Wyświetl plik

@ -19,7 +19,7 @@ extern bool axp192_found;
extern bool isCharging;
extern bool isUSBPowered;
extern uint8_t nodeTelemetrySensorsMap[10];
extern uint8_t nodeTelemetrySensorsMap[12];
// Global Screen singleton.
extern graphics::Screen *screen;

Wyświetl plik

@ -120,8 +120,6 @@ typedef struct _Config_PositionConfig {
bool gps_disabled;
uint32_t gps_update_interval;
uint32_t gps_attempt_time;
bool gps_accept_2d;
uint32_t gps_max_dop;
uint32_t position_flags;
} Config_PositionConfig;
@ -194,14 +192,14 @@ extern "C" {
/* Initializer values for message structs */
#define Config_init_default {0, {Config_DeviceConfig_init_default}}
#define Config_DeviceConfig_init_default {_Config_DeviceConfig_Role_MIN, 0, 0, 0, ""}
#define Config_PositionConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0}
#define Config_PositionConfig_init_default {0, 0, 0, 0, 0, 0, 0}
#define Config_PowerConfig_init_default {_Config_PowerConfig_ChargeCurrent_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define Config_WiFiConfig_init_default {"", "", 0, 0}
#define Config_DisplayConfig_init_default {0, _Config_DisplayConfig_GpsCoordinateFormat_MIN, 0}
#define Config_LoRaConfig_init_default {0, _Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, {0, 0, 0}}
#define Config_init_zero {0, {Config_DeviceConfig_init_zero}}
#define Config_DeviceConfig_init_zero {_Config_DeviceConfig_Role_MIN, 0, 0, 0, ""}
#define Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0}
#define Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0}
#define Config_PowerConfig_init_zero {_Config_PowerConfig_ChargeCurrent_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define Config_WiFiConfig_init_zero {"", "", 0, 0}
#define Config_DisplayConfig_init_zero {0, _Config_DisplayConfig_GpsCoordinateFormat_MIN, 0}
@ -232,8 +230,6 @@ extern "C" {
#define Config_PositionConfig_gps_disabled_tag 5
#define Config_PositionConfig_gps_update_interval_tag 6
#define Config_PositionConfig_gps_attempt_time_tag 7
#define Config_PositionConfig_gps_accept_2d_tag 8
#define Config_PositionConfig_gps_max_dop_tag 9
#define Config_PositionConfig_position_flags_tag 10
#define Config_PowerConfig_charge_current_tag 1
#define Config_PowerConfig_is_low_power_tag 2
@ -291,8 +287,6 @@ X(a, STATIC, SINGULAR, BOOL, fixed_position, 3) \
X(a, STATIC, SINGULAR, BOOL, gps_disabled, 5) \
X(a, STATIC, SINGULAR, UINT32, gps_update_interval, 6) \
X(a, STATIC, SINGULAR, UINT32, gps_attempt_time, 7) \
X(a, STATIC, SINGULAR, BOOL, gps_accept_2d, 8) \
X(a, STATIC, SINGULAR, UINT32, gps_max_dop, 9) \
X(a, STATIC, SINGULAR, UINT32, position_flags, 10)
#define Config_PositionConfig_CALLBACK NULL
#define Config_PositionConfig_DEFAULT NULL
@ -363,7 +357,7 @@ extern const pb_msgdesc_t Config_LoRaConfig_msg;
#define Config_DeviceConfig_size 42
#define Config_DisplayConfig_size 14
#define Config_LoRaConfig_size 67
#define Config_PositionConfig_size 38
#define Config_PositionConfig_size 30
#define Config_PowerConfig_size 55
#define Config_WiFiConfig_size 103
#define Config_size 105

Wyświetl plik

@ -126,7 +126,7 @@ extern const pb_msgdesc_t LocalModuleConfig_msg;
#define LocalModuleConfig_fields &LocalModuleConfig_msg
/* Maximum encoded size of messages (where known) */
#define LocalConfig_size 331
#define LocalConfig_size 323
#define LocalModuleConfig_size 282
#ifdef __cplusplus

Wyświetl plik

@ -12,26 +12,30 @@
/* Enum definitions */
/* TODO: REPLACE */
typedef enum _TelemetrySensorType {
/* No external telemetry sensor */
/* No external telemetry sensor explicitly set */
TelemetrySensorType_NotSet = 0,
/* TODO: REPLACE */
/* Moderate accuracy temperature */
TelemetrySensorType_DHT11 = 1,
/* TODO: REPLACE */
/* High accuracy temperature */
TelemetrySensorType_DS18B20 = 2,
/* TODO: REPLACE */
/* Moderate accuracy temperature and humidity */
TelemetrySensorType_DHT12 = 3,
/* TODO: REPLACE */
/* Moderate accuracy temperature and humidity */
TelemetrySensorType_DHT21 = 4,
/* TODO: REPLACE */
/* Moderate accuracy temperature and humidity */
TelemetrySensorType_DHT22 = 5,
/* TODO: REPLACE */
/* High accuracy temperature, pressure, humidity */
TelemetrySensorType_BME280 = 6,
/* TODO: REPLACE */
/* High accuracy temperature, pressure, humidity, and air resistance */
TelemetrySensorType_BME680 = 7,
/* TODO: REPLACE */
/* Very high accuracy temperature */
TelemetrySensorType_MCP9808 = 8,
/* TODO: REPLACE */
TelemetrySensorType_SHTC3 = 9
/* Moderate accuracy temperature and humidity */
TelemetrySensorType_SHTC3 = 9,
/* Moderate accuracy current and voltage */
TelemetrySensorType_INA260 = 10,
/* Moderate accuracy current and voltage */
TelemetrySensorType_INA219 = 11
} TelemetrySensorType;
/* Struct definitions */
@ -65,10 +69,10 @@ typedef struct _EnvironmentMetrics {
/* Types of Measurements the telemetry module is equipped to handle */
typedef struct _Telemetry {
/* This is usually not sent over the mesh (to save space), but it is sent
from the phone so that the local device can set its RTC If it is sent over
the mesh (because there are devices on the mesh without GPS), it will only
be sent by devices which has a hardware GPS clock (IE Mobile Phone).
/* This is usually not sent over the mesh (to save space), but it is sent
from the phone so that the local device can set its RTC If it is sent over
the mesh (because there are devices on the mesh without GPS), it will only
be sent by devices which has a hardware GPS clock (IE Mobile Phone).
seconds since 1970 */
uint32_t time;
/* Key native device metrics such as battery level */
@ -82,8 +86,8 @@ typedef struct _Telemetry {
/* Helper constants for enums */
#define _TelemetrySensorType_MIN TelemetrySensorType_NotSet
#define _TelemetrySensorType_MAX TelemetrySensorType_SHTC3
#define _TelemetrySensorType_ARRAYSIZE ((TelemetrySensorType)(TelemetrySensorType_SHTC3+1))
#define _TelemetrySensorType_MAX TelemetrySensorType_INA219
#define _TelemetrySensorType_ARRAYSIZE ((TelemetrySensorType)(TelemetrySensorType_INA219+1))
#ifdef __cplusplus

Wyświetl plik

@ -16,12 +16,17 @@
#include "Sensor/DHTSensor.h"
#include "Sensor/DallasSensor.h"
#include "Sensor/MCP9808Sensor.h"
#include "Sensor/INA260Sensor.h"
#include "Sensor/INA219Sensor.h"
BME280Sensor bme280Sensor;
BME680Sensor bme680Sensor;
DHTSensor dhtSensor;
DallasSensor dallasSensor;
MCP9808Sensor mcp9808Sensor;
INA260Sensor ina260Sensor;
INA219Sensor ina219Sensor;
#define FAILED_STATE_SENSOR_READ_MULTIPLIER 10
#define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true
@ -50,6 +55,7 @@ int32_t EnvironmentTelemetryModule::runOnce()
Uncomment the preferences below if you want to use the module
without having to configure it from the PythonAPI or WebUI.
*/
moduleConfig.telemetry.environment_measurement_enabled = 1;
/*
moduleConfig.telemetry.environment_measurement_enabled = 1;
@ -96,6 +102,10 @@ int32_t EnvironmentTelemetryModule::runOnce()
result = bme280Sensor.runOnce();
if (mcp9808Sensor.hasSensor())
result = mcp9808Sensor.runOnce();
if (ina260Sensor.hasSensor())
result = ina260Sensor.runOnce();
if (ina219Sensor.hasSensor())
result = ina219Sensor.runOnce();
}
return result;
} else {
@ -252,6 +262,10 @@ bool EnvironmentTelemetryModule::sendOurTelemetry(NodeNum dest, bool wantReplies
bme680Sensor.getMetrics(&m);
if (mcp9808Sensor.hasSensor())
mcp9808Sensor.getMetrics(&m);
if (ina219Sensor.hasSensor())
ina219Sensor.getMetrics(&m);
if (ina260Sensor.hasSensor())
ina260Sensor.getMetrics(&m);
DEBUG_MSG("Telemetry->time: %i\n", m.time);
DEBUG_MSG("Telemetry->barometric_pressure: %f\n", m.variant.environment_metrics.barometric_pressure);

Wyświetl plik

@ -11,11 +11,11 @@ BME280Sensor::BME280Sensor() :
}
int32_t BME280Sensor::runOnce() {
DEBUG_MSG("Init sensor: TelemetrySensorType_BME280\n");
DEBUG_MSG("Init sensor: %s\n", sensorName);
if (!hasSensor()) {
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
}
status = bme280.begin(nodeTelemetrySensorsMap[TelemetrySensorType_BME280]);
status = bme280.begin(nodeTelemetrySensorsMap[sensorType]);
return initI2CSensor();
}

Wyświetl plik

@ -10,11 +10,11 @@ BME680Sensor::BME680Sensor() :
}
int32_t BME680Sensor::runOnce() {
DEBUG_MSG("runOnce: TelemetrySensorType_BME680\n");
DEBUG_MSG("Init sensor: %s\n", sensorName);
if (!hasSensor()) {
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
}
status = bme680.begin(nodeTelemetrySensorsMap[TelemetrySensorType_BME680]);
status = bme680.begin(nodeTelemetrySensorsMap[sensorType]);
return initI2CSensor();
}
@ -29,7 +29,6 @@ void BME680Sensor::setup()
}
bool BME680Sensor::getMetrics(Telemetry *measurement) {
measurement->variant.environment_metrics.temperature = bme680.readTemperature();
measurement->variant.environment_metrics.relative_humidity = bme680.readHumidity();
measurement->variant.environment_metrics.barometric_pressure = bme680.readPressure() / 100.0F;

Wyświetl plik

@ -0,0 +1,30 @@
#include "../mesh/generated/telemetry.pb.h"
#include "configuration.h"
#include "TelemetrySensor.h"
#include "INA219Sensor.h"
#include <Adafruit_INA219.h>
INA219Sensor::INA219Sensor() :
TelemetrySensor(TelemetrySensorType_INA219, "INA219")
{
}
int32_t INA219Sensor::runOnce() {
DEBUG_MSG("Init sensor: %s\n", sensorName);
if (!hasSensor()) {
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
}
ina219 = Adafruit_INA219(nodeTelemetrySensorsMap[sensorType]);
status = ina219.begin();
return initI2CSensor();
}
void INA219Sensor::setup()
{
}
bool INA219Sensor::getMetrics(Telemetry *measurement) {
measurement->variant.environment_metrics.voltage = ina219.getBusVoltage_V();
measurement->variant.environment_metrics.current = ina219.getCurrent_mA();
return true;
}

Wyświetl plik

@ -0,0 +1,17 @@
#include "../mesh/generated/telemetry.pb.h"
#include "TelemetrySensor.h"
#include <Adafruit_INA219.h>
class INA219Sensor : virtual public TelemetrySensor {
private:
Adafruit_INA219 ina219;
protected:
virtual void setup() override;
public:
INA219Sensor();
virtual int32_t runOnce() override;
virtual bool getMetrics(Telemetry *measurement) override;
};

Wyświetl plik

@ -0,0 +1,30 @@
#include "../mesh/generated/telemetry.pb.h"
#include "configuration.h"
#include "TelemetrySensor.h"
#include "INA260Sensor.h"
#include <Adafruit_INA260.h>
INA260Sensor::INA260Sensor() :
TelemetrySensor(TelemetrySensorType_INA260, "INA260")
{
}
int32_t INA260Sensor::runOnce() {
DEBUG_MSG("Init sensor: %s\n", sensorName);
if (!hasSensor()) {
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
}
status = ina260.begin(nodeTelemetrySensorsMap[sensorType]);
return initI2CSensor();
}
void INA260Sensor::setup()
{
}
bool INA260Sensor::getMetrics(Telemetry *measurement) {
// mV conversion to V
measurement->variant.environment_metrics.voltage = ina260.readBusVoltage() / 1000;
measurement->variant.environment_metrics.current = ina260.readCurrent();
return true;
}

Wyświetl plik

@ -0,0 +1,17 @@
#include "../mesh/generated/telemetry.pb.h"
#include "TelemetrySensor.h"
#include <Adafruit_INA260.h>
class INA260Sensor : virtual public TelemetrySensor {
private:
Adafruit_INA260 ina260 = Adafruit_INA260();
protected:
virtual void setup() override;
public:
INA260Sensor();
virtual int32_t runOnce() override;
virtual bool getMetrics(Telemetry *measurement) override;
};

Wyświetl plik

@ -10,11 +10,11 @@ MCP9808Sensor::MCP9808Sensor() :
}
int32_t MCP9808Sensor::runOnce() {
DEBUG_MSG("Init sensor: TelemetrySensorType_MCP9808\n");
DEBUG_MSG("Init sensor: %s\n", sensorName);
if (!hasSensor()) {
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
}
status = mcp9808.begin(nodeTelemetrySensorsMap[TelemetrySensorType_MCP9808]);
status = mcp9808.begin(nodeTelemetrySensorsMap[sensorType]);
return initI2CSensor();
}