Scan for i2c sensors in environmental telemetry if enabled (#1492)

* Scan for i2c sensors in environmental telemetry if enabled

* Update TelemetrySensor.h

* Added surpression.

* Remove suppression and fix real bug

* Interrogate BME sensor id registers
raytac-diy
Ben Meadors 2022-06-05 09:50:06 -05:00 zatwierdzone przez GitHub
rodzic 4ab831c103
commit eafbef0c2f
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
17 zmienionych plików z 133 dodań i 98 usunięć

Wyświetl plik

@ -51,7 +51,8 @@
"iterator": "cpp",
"shared_mutex": "cpp",
"iostream": "cpp",
"esp_nimble_hci.h": "c"
"esp_nimble_hci.h": "c",
"map": "cpp"
},
"cSpell.words": [
"Blox",

Wyświetl plik

@ -25,6 +25,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <Arduino.h>
#ifdef RV3028_RTC
#include "Melopero_RV3028.h"
#endif
@ -170,6 +171,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// The older M5 Faces I2C Keyboard
#define FACESKB_ADDR 0x88
// -----------------------------------------------------------------------------
// SENSOR
// -----------------------------------------------------------------------------
#define BME_ADDR 0x76
#define BME_ADDR_ALTERNATE 0x77
#define MCP9808_ADDR 0x18
// -----------------------------------------------------------------------------
// GPS
// -----------------------------------------------------------------------------

Wyświetl plik

@ -1,6 +1,7 @@
#include "../configuration.h"
#include "../main.h"
#include <Wire.h>
#include "mesh/generated/telemetry.pb.h"
#ifndef NO_WIRE
uint8_t oled_probe(byte addr)
@ -104,6 +105,27 @@ void scanI2Cdevice(void)
DEBUG_MSG("axp192 PMU found\n");
}
#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) {
DEBUG_MSG("BME-680 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[TelemetrySensorType_BME680] = addr;
} else if (r == 0x60) {
DEBUG_MSG("BME-280 sensor found at address 0x%x\n", (uint8_t)addr);
nodeTelemetrySensorsMap[TelemetrySensorType_BME280] = addr;
}
}
if (addr == MCP9808_ADDR) {
nodeTelemetrySensorsMap[TelemetrySensorType_MCP9808] = addr;
DEBUG_MSG("MCP9808 sensor found at address 0x%x\n", (uint8_t)addr);
}
} else if (err == 4) {
DEBUG_MSG("Unknow error at address 0x%x\n", addr);
}

Wyświetl plik

@ -89,6 +89,8 @@ 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 };
Router *router = NULL; // Users of router don't care what sort of subclass implements that API

Wyświetl plik

@ -1,9 +1,11 @@
#pragma once
#include <map>
#include "GPSStatus.h"
#include "NodeStatus.h"
#include "PowerStatus.h"
#include "graphics/Screen.h"
#include "mesh/generated/telemetry.pb.h"
extern uint8_t screen_found;
extern uint8_t screen_model;
@ -17,6 +19,8 @@ extern bool axp192_found;
extern bool isCharging;
extern bool isUSBPowered;
extern uint8_t nodeTelemetrySensorsMap[10];
// Global Screen singleton.
extern graphics::Screen *screen;
// extern Observable<meshtastic::PowerStatus> newPowerStatus; //TODO: move this to main-esp32.cpp somehow or a helper class

Wyświetl plik

@ -45,10 +45,12 @@ MCP9808Sensor mcp9808Sensor;
int32_t EnvironmentTelemetryModule::runOnce()
{
#ifndef PORTDUINO
int32_t result = INT32_MAX;
/*
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_screen_enabled = 1;
@ -62,7 +64,7 @@ int32_t EnvironmentTelemetryModule::runOnce()
if (!(moduleConfig.telemetry.environment_measurement_enabled ||
moduleConfig.telemetry.environment_screen_enabled)) {
// If this module is not enabled, and the user doesn't want the display screen don't waste any OSThread time on it
return (INT32_MAX);
return result;
}
if (firstTime) {
@ -73,32 +75,33 @@ int32_t EnvironmentTelemetryModule::runOnce()
DEBUG_MSG("Environment Telemetry: Initializing\n");
// it's possible to have this module enabled, only for displaying values on the screen.
// therefore, we should only enable the sensor loop if measurement is also enabled
switch (moduleConfig.telemetry.environment_sensor_type) {
case TelemetrySensorType_DHT11:
case TelemetrySensorType_DHT12:
case TelemetrySensorType_DHT21:
case TelemetrySensorType_DHT22:
return dhtSensor.runOnce();
case TelemetrySensorType_DS18B20:
return dallasSensor.runOnce();
case TelemetrySensorType_BME280:
return bme280Sensor.runOnce();
case TelemetrySensorType_BME680:
return bme680Sensor.runOnce();
case TelemetrySensorType_MCP9808:
return mcp9808Sensor.runOnce();
default:
DEBUG_MSG("Environment Telemetry: Invalid sensor type selected; Disabling module");
return (INT32_MAX);
case TelemetrySensorType_DHT11:
case TelemetrySensorType_DHT12:
case TelemetrySensorType_DHT21:
case TelemetrySensorType_DHT22:
result = dhtSensor.runOnce();
break;
case TelemetrySensorType_DS18B20:
result = dallasSensor.runOnce();
break;
default:
DEBUG_MSG("Environment Telemetry: No sensor type specified; Checking for detected i2c sensors\n");
break;
}
if (hasSensor(TelemetrySensorType_BME680))
result = bme680Sensor.runOnce();
if (hasSensor(TelemetrySensorType_BME280))
result = bme280Sensor.runOnce();
if (hasSensor(TelemetrySensorType_MCP9808))
result = mcp9808Sensor.runOnce();
}
return (INT32_MAX);
return result;
} else {
// if we somehow got to a second run of this module with measurement disabled, then just wait forever
if (!moduleConfig.telemetry.environment_measurement_enabled)
return (INT32_MAX);
return result;
// this is not the first time OSThread library has called this function
// so just do what we intend to do on the interval
if (sensor_read_error_count > moduleConfig.telemetry.environment_read_error_count_threshold) {
@ -114,7 +117,7 @@ int32_t EnvironmentTelemetryModule::runOnce()
DEBUG_MSG("Environment Telemetry: DISABLED; The telemetry_module_environment_read_error_count_threshold has "
"been exceed: %d. Reads will not be retried until after device reset\n",
moduleConfig.telemetry.environment_read_error_count_threshold);
return (INT32_MAX);
return result;
} else if (sensor_read_error_count > 0) {
DEBUG_MSG("Environment Telemetry: There have been %d sensor read failures. Will retry %d more times\n",
@ -124,23 +127,7 @@ int32_t EnvironmentTelemetryModule::runOnce()
if (!sendOurTelemetry()) {
// if we failed to read the sensor, then try again
// as soon as we can according to the maximum polling frequency
switch (moduleConfig.telemetry.environment_sensor_type) {
case TelemetrySensorType_DHT11:
case TelemetrySensorType_DHT12:
case TelemetrySensorType_DHT21:
case TelemetrySensorType_DHT22:
return (DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
case TelemetrySensorType_DS18B20:
return (DS18B20_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
case TelemetrySensorType_BME280:
case TelemetrySensorType_BME680:
return (BME_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
case TelemetrySensorType_MCP9808:
return (MCP_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
default:
return (DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
}
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
}
}
return getIntervalOrDefaultMs(moduleConfig.telemetry.environment_update_interval);
@ -245,29 +232,26 @@ bool EnvironmentTelemetryModule::sendOurTelemetry(NodeNum dest, bool wantReplies
DEBUG_MSG("Environment Telemetry: Read data\n");
switch (moduleConfig.telemetry.environment_sensor_type) {
case TelemetrySensorType_DS18B20:
if (!dallasSensor.getMeasurement(&m))
sensor_read_error_count++;
break;
case TelemetrySensorType_DHT11:
case TelemetrySensorType_DHT12:
case TelemetrySensorType_DHT21:
case TelemetrySensorType_DHT22:
if (!dhtSensor.getMeasurement(&m))
sensor_read_error_count++;
break;
case TelemetrySensorType_BME280:
bme280Sensor.getMeasurement(&m);
break;
case TelemetrySensorType_BME680:
bme680Sensor.getMeasurement(&m);
break;
case TelemetrySensorType_MCP9808:
mcp9808Sensor.getMeasurement(&m);
break;
default:
DEBUG_MSG("Environment Telemetry: No external sensor type selected; Only sending internal metrics\n");
case TelemetrySensorType_DS18B20:
if (!dallasSensor.getMeasurement(&m))
sensor_read_error_count++;
break;
case TelemetrySensorType_DHT11:
case TelemetrySensorType_DHT12:
case TelemetrySensorType_DHT21:
case TelemetrySensorType_DHT22:
if (!dhtSensor.getMeasurement(&m))
sensor_read_error_count++;
break;
default:
DEBUG_MSG("Environment Telemetry: No specified sensor type; Trying any detected i2c sensors\n");
}
if (hasSensor(TelemetrySensorType_BME280))
bme280Sensor.getMeasurement(&m);
if (hasSensor(TelemetrySensorType_BME680))
bme680Sensor.getMeasurement(&m);
if (hasSensor(TelemetrySensorType_MCP9808))
mcp9808Sensor.getMeasurement(&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

@ -4,23 +4,28 @@
#include "BME280Sensor.h"
#include <Adafruit_BME280.h>
BME280Sensor::BME280Sensor() : TelemetrySensor {} {
BME280Sensor::BME280Sensor() : TelemetrySensor {}
{
}
int32_t BME280Sensor::runOnce() {
unsigned bme280Status;
// Default i2c address for BME280
bme280Status = bme280.begin(0x76);
if (!bme280Status) {
DEBUG_MSG("Could not find a valid BME280 sensor, check wiring, address, sensor ID!");
// TODO more verbose diagnostics
} else {
DEBUG_MSG("Telemetry: Opened BME280 on default i2c bus");
DEBUG_MSG("Init sensor: TelemetrySensorType_BME280\n");
if (!hasSensor(TelemetrySensorType_BME280)) {
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
}
return BME_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
bme280Status = bme280.begin(nodeTelemetrySensorsMap[TelemetrySensorType_BME280]);
if (!bme280Status) {
DEBUG_MSG("Could not connect to any detected BME-280 sensor.\nRemoving from nodeTelemetrySensorsMap.\n");
nodeTelemetrySensorsMap[TelemetrySensorType_BME280] = 0;
} else {
DEBUG_MSG("Opened BME280 on default i2c bus\n");
}
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
}
bool BME280Sensor::getMeasurement(Telemetry *measurement) {
DEBUG_MSG("BME280Sensor::getMeasurement\n");
measurement->variant.environment_metrics.temperature = bme280.readTemperature();
measurement->variant.environment_metrics.relative_humidity = bme280.readHumidity();
measurement->variant.environment_metrics.barometric_pressure = bme280.readPressure() / 100.0F;

Wyświetl plik

@ -2,8 +2,6 @@
#include "TelemetrySensor.h"
#include <Adafruit_BME280.h>
#define BME_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000
class BME280Sensor : virtual public TelemetrySensor {
private:
Adafruit_BME280 bme280;

Wyświetl plik

@ -4,18 +4,22 @@
#include "BME680Sensor.h"
#include <Adafruit_BME680.h>
BME680Sensor::BME680Sensor() : TelemetrySensor {} {
BME680Sensor::BME680Sensor() : TelemetrySensor {}
{
}
int32_t BME680Sensor::runOnce() {
unsigned bme680Status;
// Default i2c address for BME680
bme680Status = bme680.begin(0x76);
DEBUG_MSG("Init sensor: TelemetrySensorType_BME680\n");
if (!hasSensor(TelemetrySensorType_BME680)) {
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
}
bme680Status = bme680.begin(nodeTelemetrySensorsMap[TelemetrySensorType_BME680]);
if (!bme680Status) {
DEBUG_MSG("Could not find a valid BME680 sensor, check wiring, address, sensor ID!");
// TODO more verbose TelemetrySensor
DEBUG_MSG("Could not connect to any detected BME-680 sensor.\nRemoving from nodeTelemetrySensorsMap.\n");
nodeTelemetrySensorsMap[TelemetrySensorType_BME680] = 0;
} else {
DEBUG_MSG("Telemetry: Opened BME680 on default i2c bus");
DEBUG_MSG("Opened BME680 on default i2c bus\n");
// Set up oversampling and filter initialization
bme680.setTemperatureOversampling(BME680_OS_8X);
bme680.setHumidityOversampling(BME680_OS_2X);
@ -23,10 +27,11 @@ int32_t BME680Sensor::runOnce() {
bme680.setIIRFilterSize(BME680_FILTER_SIZE_3);
bme680.setGasHeater(320, 150); // 320*C for 150 ms
}
return (BME_680_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
}
bool BME680Sensor::getMeasurement(Telemetry *measurement) {
DEBUG_MSG("BME680Sensor::getMeasurement\n");
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

@ -2,8 +2,6 @@
#include "TelemetrySensor.h"
#include <Adafruit_BME680.h>
#define BME_680_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000
class BME680Sensor : virtual public TelemetrySensor {
private:
Adafruit_BME680 bme680;

Wyświetl plik

@ -18,13 +18,14 @@ int32_t DHTSensor::runOnce()
dht->begin();
dht->read();
DEBUG_MSG("Telemetry: Opened DHT11/DHT12 on pin: %d\n", moduleConfig.telemetry.environment_sensor_pin);
DEBUG_MSG("Opened DHT11/DHT12 on pin: %d\n", moduleConfig.telemetry.environment_sensor_pin);
return (DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
}
bool DHTSensor::getMeasurement(Telemetry *measurement)
{
DEBUG_MSG("DHTSensor::getMeasurement\n");
if (!dht->read(true)) {
DEBUG_MSG("Telemetry: FAILED TO READ DATA\n");
return false;

Wyświetl plik

@ -2,8 +2,6 @@
#include "TelemetrySensor.h"
#include <DHT.h>
#define DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000
class DHTSensor : virtual public TelemetrySensor {
private:
DHT *dht = NULL;

Wyświetl plik

@ -15,12 +15,13 @@ int32_t DallasSensor::runOnce()
ds18b20->begin();
ds18b20->setResolution(12);
ds18b20->requestTemperatures();
DEBUG_MSG("Telemetry: Opened DS18B20 on pin: %d\n", moduleConfig.telemetry.environment_sensor_pin);
return (DS18B20_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
DEBUG_MSG("Opened DS18B20 on pin: %d\n", moduleConfig.telemetry.environment_sensor_pin);
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
}
bool DallasSensor::getMeasurement(Telemetry *measurement)
{
DEBUG_MSG("DallasSensor::getMeasurement\n");
if (ds18b20->isConversionComplete()) {
measurement->variant.environment_metrics.temperature = ds18b20->getTempC();
measurement->variant.environment_metrics.relative_humidity = 0;

Wyświetl plik

@ -3,8 +3,6 @@
#include <DS18B20.h>
#include <OneWire.h>
#define DS18B20_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000
class DallasSensor : virtual public TelemetrySensor {
private:
OneWire *oneWire = NULL;

Wyświetl plik

@ -4,25 +4,31 @@
#include "MCP9808Sensor.h"
#include <Adafruit_MCP9808.h>
MCP9808Sensor::MCP9808Sensor() : TelemetrySensor {} {
MCP9808Sensor::MCP9808Sensor() : TelemetrySensor {}
{
}
int32_t MCP9808Sensor::runOnce() {
unsigned mcp9808Status;
// Default i2c address for MCP9808
mcp9808Status = mcp9808.begin(0x18);
DEBUG_MSG("Init sensor: TelemetrySensorType_MCP9808\n");
if (!hasSensor(TelemetrySensorType_MCP9808)) {
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
}
mcp9808Status = mcp9808.begin(nodeTelemetrySensorsMap[TelemetrySensorType_MCP9808]);
if (!mcp9808Status) {
DEBUG_MSG("Could not find a valid MCP9808 sensor, check wiring, address, sensor ID!");
DEBUG_MSG("Could not connect to detected MCP9808 sensor.\n Removing from nodeTelemetrySensorsMap.\n");
nodeTelemetrySensorsMap[TelemetrySensorType_MCP9808] = 0;
} else {
DEBUG_MSG("TelemetrySensor: Opened MCP9808 on default i2c bus");
DEBUG_MSG("TelemetrySensor: Opened MCP9808 on default i2c bus\n");
// Reduce resolution from 0.0625 degrees (precision) to 0.125 degrees (high).
mcp9808.setResolution(2);
}
return (MCP_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
return (DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
}
bool MCP9808Sensor::getMeasurement(Telemetry *measurement) {
DEBUG_MSG("MCP9808Sensor::getMeasurement\n");
measurement->variant.environment_metrics.temperature = mcp9808.readTempC();
return true;
}

Wyświetl plik

@ -2,8 +2,6 @@
#include "TelemetrySensor.h"
#include <Adafruit_MCP9808.h>
#define MCP_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000
class MCP9808Sensor : virtual public TelemetrySensor {
private:
Adafruit_MCP9808 mcp9808;

Wyświetl plik

@ -1,8 +1,14 @@
#pragma once
#include "../mesh/generated/telemetry.pb.h"
#include "NodeDB.h"
#include "main.h"
#define DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000
inline bool hasSensor(TelemetrySensorType sensorType) {
return sensorType < sizeof(nodeTelemetrySensorsMap) && nodeTelemetrySensorsMap[sensorType] > 0;
}
class TelemetrySensor
{
protected: