diff --git a/.vscode/settings.json b/.vscode/settings.json index c2bc7b28..21bf462e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -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", diff --git a/src/configuration.h b/src/configuration.h index aae49d98..35d226e2 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -25,6 +25,7 @@ along with this program. If not, see . #pragma once #include + #ifdef RV3028_RTC #include "Melopero_RV3028.h" #endif @@ -170,6 +171,13 @@ along with this program. If not, see . // 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 // ----------------------------------------------------------------------------- diff --git a/src/debug/i2cScan.h b/src/debug/i2cScan.h index ba5636ea..206cdbfe 100644 --- a/src/debug/i2cScan.h +++ b/src/debug/i2cScan.h @@ -1,6 +1,7 @@ #include "../configuration.h" #include "../main.h" #include +#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); } diff --git a/src/main.cpp b/src/main.cpp index 8068a9fc..4dd16c89 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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 diff --git a/src/main.h b/src/main.h index bb262a58..0f7a7779 100644 --- a/src/main.h +++ b/src/main.h @@ -1,9 +1,11 @@ #pragma once +#include #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 newPowerStatus; //TODO: move this to main-esp32.cpp somehow or a helper class diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index 534819d8..a0f1f146 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -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); diff --git a/src/modules/Telemetry/Sensor/BME280Sensor.cpp b/src/modules/Telemetry/Sensor/BME280Sensor.cpp index fee3e266..9ffcd29f 100644 --- a/src/modules/Telemetry/Sensor/BME280Sensor.cpp +++ b/src/modules/Telemetry/Sensor/BME280Sensor.cpp @@ -4,23 +4,28 @@ #include "BME280Sensor.h" #include -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; diff --git a/src/modules/Telemetry/Sensor/BME280Sensor.h b/src/modules/Telemetry/Sensor/BME280Sensor.h index 420c859c..661903fd 100644 --- a/src/modules/Telemetry/Sensor/BME280Sensor.h +++ b/src/modules/Telemetry/Sensor/BME280Sensor.h @@ -2,8 +2,6 @@ #include "TelemetrySensor.h" #include -#define BME_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000 - class BME280Sensor : virtual public TelemetrySensor { private: Adafruit_BME280 bme280; diff --git a/src/modules/Telemetry/Sensor/BME680Sensor.cpp b/src/modules/Telemetry/Sensor/BME680Sensor.cpp index 1e57302b..ae7641f7 100644 --- a/src/modules/Telemetry/Sensor/BME680Sensor.cpp +++ b/src/modules/Telemetry/Sensor/BME680Sensor.cpp @@ -4,18 +4,22 @@ #include "BME680Sensor.h" #include -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; diff --git a/src/modules/Telemetry/Sensor/BME680Sensor.h b/src/modules/Telemetry/Sensor/BME680Sensor.h index d502cd69..0f546a47 100644 --- a/src/modules/Telemetry/Sensor/BME680Sensor.h +++ b/src/modules/Telemetry/Sensor/BME680Sensor.h @@ -2,8 +2,6 @@ #include "TelemetrySensor.h" #include -#define BME_680_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000 - class BME680Sensor : virtual public TelemetrySensor { private: Adafruit_BME680 bme680; diff --git a/src/modules/Telemetry/Sensor/DHTSensor.cpp b/src/modules/Telemetry/Sensor/DHTSensor.cpp index e10a46bf..9e65bf06 100644 --- a/src/modules/Telemetry/Sensor/DHTSensor.cpp +++ b/src/modules/Telemetry/Sensor/DHTSensor.cpp @@ -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; diff --git a/src/modules/Telemetry/Sensor/DHTSensor.h b/src/modules/Telemetry/Sensor/DHTSensor.h index 4e062d1d..d0410778 100644 --- a/src/modules/Telemetry/Sensor/DHTSensor.h +++ b/src/modules/Telemetry/Sensor/DHTSensor.h @@ -2,8 +2,6 @@ #include "TelemetrySensor.h" #include -#define DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000 - class DHTSensor : virtual public TelemetrySensor { private: DHT *dht = NULL; diff --git a/src/modules/Telemetry/Sensor/DallasSensor.cpp b/src/modules/Telemetry/Sensor/DallasSensor.cpp index 23fc57cf..ab91ef1c 100644 --- a/src/modules/Telemetry/Sensor/DallasSensor.cpp +++ b/src/modules/Telemetry/Sensor/DallasSensor.cpp @@ -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; diff --git a/src/modules/Telemetry/Sensor/DallasSensor.h b/src/modules/Telemetry/Sensor/DallasSensor.h index c07825b0..0ee165f7 100644 --- a/src/modules/Telemetry/Sensor/DallasSensor.h +++ b/src/modules/Telemetry/Sensor/DallasSensor.h @@ -3,8 +3,6 @@ #include #include -#define DS18B20_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000 - class DallasSensor : virtual public TelemetrySensor { private: OneWire *oneWire = NULL; diff --git a/src/modules/Telemetry/Sensor/MCP9808Sensor.cpp b/src/modules/Telemetry/Sensor/MCP9808Sensor.cpp index eaeaba34..25392b46 100644 --- a/src/modules/Telemetry/Sensor/MCP9808Sensor.cpp +++ b/src/modules/Telemetry/Sensor/MCP9808Sensor.cpp @@ -4,25 +4,31 @@ #include "MCP9808Sensor.h" #include -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; } \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/MCP9808Sensor.h b/src/modules/Telemetry/Sensor/MCP9808Sensor.h index f7190e95..8991477a 100644 --- a/src/modules/Telemetry/Sensor/MCP9808Sensor.h +++ b/src/modules/Telemetry/Sensor/MCP9808Sensor.h @@ -2,8 +2,6 @@ #include "TelemetrySensor.h" #include -#define MCP_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000 - class MCP9808Sensor : virtual public TelemetrySensor { private: Adafruit_MCP9808 mcp9808; diff --git a/src/modules/Telemetry/Sensor/TelemetrySensor.h b/src/modules/Telemetry/Sensor/TelemetrySensor.h index d2f38cf6..c9146cc8 100644 --- a/src/modules/Telemetry/Sensor/TelemetrySensor.h +++ b/src/modules/Telemetry/Sensor/TelemetrySensor.h @@ -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: