diff --git a/src/helpers/sensors/AHTX0Sensor.h b/src/helpers/sensors/AHTX0Sensor.h new file mode 100644 index 00000000..04af3057 --- /dev/null +++ b/src/helpers/sensors/AHTX0Sensor.h @@ -0,0 +1,39 @@ +#pragma once +#include +#include + +#define TELEM_AHTX_ADDRESS 0x38 // AHT10, AHT20 temperature and humidity sensor I2C address + +static Adafruit_AHTX0 AHTX0; + +class AHTX0Sensor { + bool initialized = false; +public: + void begin() { + if (AHTX0.begin(&Wire, 0, TELEM_AHTX_ADDRESS)) { + MESH_DEBUG_PRINTLN("Found AHT10/AHT20 at address: %02X", TELEM_AHTX_ADDRESS); + initialized = true; + } else { + initialized = false; + MESH_DEBUG_PRINTLN("AHT10/AHT20 was not found at I2C address %02X", TELEM_AHTX_ADDRESS); + } + } + + bool isInitialized() const { return initialized; }; + + float getRelativeHumidity() const { + if (initialized) { + sensors_event_t humidity, temp; + AHTX0.getEvent(&humidity, &temp); + return humidity.relative_humidity; + } + } + + float getTemperature() const { + if (initialized) { + sensors_event_t humidity, temp; + AHTX0.getEvent(&humidity, &temp); + return temp.temperature; + } + } +}; diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp new file mode 100644 index 00000000..b0497471 --- /dev/null +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -0,0 +1,67 @@ +#include "EnvironmentSensorManager.h" + +bool EnvironmentSensorManager::begin() { + INA3221_sensor.begin(); + INA219_sensor.begin(); + AHTX0_sensor.begin(); + + return true; +} + +bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { + next_available_channel = TELEM_CHANNEL_SELF + 1; + if (requester_permissions & TELEM_PERM_ENVIRONMENT) { + if (INA3221_sensor.isInitialized()) { + for(int i = 0; i < 3; i++) { + // add only enabled INA3221 channels to telemetry + if (INA3221_sensor.getChannelEnabled(i)) { + telemetry.addVoltage(next_available_channel, INA3221_sensor.getVoltage(i)); + telemetry.addCurrent(next_available_channel, INA3221_sensor.getCurrent(i)); + telemetry.addPower(next_available_channel, INA3221_sensor.getPower(i)); + next_available_channel++; + } + } + } + if (INA219_sensor.isInitialized()) { + telemetry.addVoltage(next_available_channel, INA219_sensor.getVoltage()); + telemetry.addCurrent(next_available_channel, INA219_sensor.getCurrent()); + telemetry.addPower(next_available_channel, INA219_sensor.getPower()); + next_available_channel++; + } + if (AHTX0_sensor.isInitialized()) { + telemetry.addTemperature(TELEM_CHANNEL_SELF, AHTX0_sensor.getTemperature()); + telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, AHTX0_sensor.getRelativeHumidity()); + } + } + + return true; +} + +int EnvironmentSensorManager::getNumSettings() const { + return NUM_SENSOR_SETTINGS; +} + +const char* EnvironmentSensorManager::getSettingName(int i) const { + if (i >= 0 && i < NUM_SENSOR_SETTINGS) { + return INA3221_CHANNEL_NAMES[i]; + } + return NULL; +} + +const char* EnvironmentSensorManager::getSettingValue(int i) const { + if (i >= 0 && i < NUM_SENSOR_SETTINGS) { + return INA3221_sensor.getChannelEnabled(i) == true ? "1" : "0"; + } + return NULL; +} + +bool EnvironmentSensorManager::setSettingValue(const char* name, const char* value) { + for (int i = 0; i < NUM_SENSOR_SETTINGS; i++) { + if (strcmp(name, INA3221_CHANNEL_NAMES[i]) == 0) { + bool channel_enabled = strcmp(value, "1") == 0 ? true : false; + INA3221_sensor.setChannelEnabled(i, channel_enabled); + return true; + } + } + return false; +} \ No newline at end of file diff --git a/src/helpers/sensors/EnvironmentSensorManager.h b/src/helpers/sensors/EnvironmentSensorManager.h new file mode 100644 index 00000000..95a7476b --- /dev/null +++ b/src/helpers/sensors/EnvironmentSensorManager.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include "INA3221Sensor.h" +#include "INA219Sensor.h" +#include "AHTX0Sensor.h" + +#define NUM_SENSOR_SETTINGS 3 +#define TELEM_INA3221_SETTING_CH1 "INA3221-1" +#define TELEM_INA3221_SETTING_CH2 "INA3221-2" +#define TELEM_INA3221_SETTING_CH3 "INA3221-3" + +class EnvironmentSensorManager : public SensorManager { +// INA3221 channels in telemetry +const char * INA3221_CHANNEL_NAMES[NUM_SENSOR_SETTINGS] = { TELEM_INA3221_SETTING_CH1, TELEM_INA3221_SETTING_CH2, TELEM_INA3221_SETTING_CH3}; + +protected: + int next_available_channel = TELEM_CHANNEL_SELF + 1; + INA3221Sensor INA3221_sensor; + AHTX0Sensor AHTX0_sensor; + INA219Sensor INA219_sensor; +public: + EnvironmentSensorManager(){}; + bool begin() override; + bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override; + int getNumSettings() const override; + const char* getSettingName(int i) const override; + const char* getSettingValue(int i) const override; + bool setSettingValue(const char* name, const char* value) override; +}; diff --git a/src/helpers/sensors/INA219Sensor.h b/src/helpers/sensors/INA219Sensor.h new file mode 100644 index 00000000..1f641ab2 --- /dev/null +++ b/src/helpers/sensors/INA219Sensor.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include + +#define TELEM_INA219_ADDRESS 0x40 // INA219 single channel current sensor I2C address +#define TELEM_INA219_SHUNT_VALUE 0.100 // shunt value in ohms (may differ between manufacturers) +#define TELEM_INA219_MAX_CURRENT 5 + +static INA219 INA_219(TELEM_INA219_ADDRESS, &Wire); + +class INA219Sensor { + bool initialized = false; +public: + void begin() { + if (INA_219.begin()) { + MESH_DEBUG_PRINTLN("Found INA219 at address: %02X", INA_219.getAddress()); + INA_219.setMaxCurrentShunt(TELEM_INA219_MAX_CURRENT, TELEM_INA219_SHUNT_VALUE); + initialized = true; + } else { + initialized = false; + MESH_DEBUG_PRINTLN("INA219 was not found at I2C address %02X", TELEM_INA219_ADDRESS); + } + } + + bool isInitialized() const { return initialized; } + + float getVoltage() const { + if (initialized) { + return INA_219.getBusVoltage(); + } + return 0; + } + + float getCurrent() const { + if (initialized) { + return INA_219.getCurrent(); + } + return 0; + } + + float getPower() const { + if (initialized) { + return INA_219.getPower(); + } + return 0; + } +}; diff --git a/src/helpers/sensors/INA3221Sensor.h b/src/helpers/sensors/INA3221Sensor.h new file mode 100644 index 00000000..f3618a9f --- /dev/null +++ b/src/helpers/sensors/INA3221Sensor.h @@ -0,0 +1,71 @@ +#pragma once + +#include +#include + +#define TELEM_INA3221_ADDRESS 0x42 // INA3221 3 channel current sensor I2C address +#define TELEM_INA3221_SHUNT_VALUE 0.100 // most variants will have a 0.1 ohm shunts + +#define NUM_CHANNELS 3 + +static INA3221 INA_3221(TELEM_INA3221_ADDRESS, &Wire); + +class INA3221Sensor { + bool initialized = false; + +public: + void begin() { + if (INA_3221.begin()) { + MESH_DEBUG_PRINTLN("Found INA3221 at address: %02X", INA_3221.getAddress()); + MESH_DEBUG_PRINTLN("%04X %04X %04X", INA_3221.getDieID(), INA_3221.getManufacturerID(), INA_3221.getConfiguration()); + + for(int i = 0; i < 3; i++) { + INA_3221.setShuntR(i, TELEM_INA3221_SHUNT_VALUE); + } + initialized = true; + } else { + initialized = false; + MESH_DEBUG_PRINTLN("INA3221 was not found at I2C address %02X", TELEM_INA3221_ADDRESS); + } + } + + bool isInitialized() const { return initialized; } + + int numChannels() const { return NUM_CHANNELS; } + + float getVoltage(int channel) const { + if (initialized && channel >=0 && channel < NUM_CHANNELS) { + return INA_3221.getBusVoltage(channel); + } + return 0; + } + + float getCurrent(int channel) const { + if (initialized && channel >=0 && channel < NUM_CHANNELS) { + return INA_3221.getCurrent(channel); + } + return 0; + } + + float getPower (int channel) const { + if (initialized && channel >=0 && channel < NUM_CHANNELS) { + return INA_3221.getPower(channel); + } + return 0; + } + + bool setChannelEnabled(int channel, bool enabled) { + if (initialized && channel >=0 && channel < NUM_CHANNELS) { + INA_3221.enableChannel(channel); + return true; + } + return false; + } + + bool getChannelEnabled(int channel) const { + if (initialized && channel >=0 && channel < NUM_CHANNELS) { + return INA_3221.getEnableChannel(channel); + } + return false; + } +}; diff --git a/variants/promicro/platformio.ini b/variants/promicro/platformio.ini index 51fbc92f..8cabf6e6 100644 --- a/variants/promicro/platformio.ini +++ b/variants/promicro/platformio.ini @@ -15,6 +15,7 @@ build_flags = ${nrf52840_base.build_flags} -D PIN_USER_BTN=6 build_src_filter = ${nrf52840_base.build_src_filter} + + + +<../variants/promicro> lib_deps= ${nrf52840_base.lib_deps} adafruit/Adafruit SSD1306 @ ^2.5.13 diff --git a/variants/promicro/target.cpp b/variants/promicro/target.cpp index 6e3dc938..841bd1dc 100644 --- a/variants/promicro/target.cpp +++ b/variants/promicro/target.cpp @@ -10,7 +10,7 @@ WRAPPER_CLASS radio_driver(radio, board); VolatileRTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); -PromicroSensorManager sensors; +EnvironmentSensorManager sensors; #ifdef DISPLAY_CLASS DISPLAY_CLASS display; @@ -79,120 +79,3 @@ mesh::LocalIdentity radio_new_identity() { return mesh::LocalIdentity(&rng); // create new random identity } -static INA3221 INA_3221(TELEM_INA3221_ADDRESS, &Wire); -static INA219 INA_219(TELEM_INA219_ADDRESS, &Wire); -static Adafruit_AHTX0 AHTX; - -bool PromicroSensorManager::begin() { - initINA3221(); - initINA219(); - initAHTX(); - - return true; -} - -bool PromicroSensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { - int nextAvalableChannel = TELEM_CHANNEL_SELF + 1; - if (requester_permissions & TELEM_PERM_ENVIRONMENT) { - if (INA3221initialized) { - for(int i = 0; i < 3; i++) { - // add only enabled INA3221 channels to telemetry - if (INA3221_CHANNEL_ENABLED[i]) { - telemetry.addVoltage(nextAvalableChannel, INA_3221.getBusVoltage(i)); - telemetry.addCurrent(nextAvalableChannel, INA_3221.getCurrent(i)); - telemetry.addPower(nextAvalableChannel, INA_3221.getPower(i)); - nextAvalableChannel++; - } - } - } - if (INA219initialized) { - telemetry.addVoltage(nextAvalableChannel, INA_219.getBusVoltage()); - telemetry.addCurrent(nextAvalableChannel, INA_219.getCurrent()); - telemetry.addPower(nextAvalableChannel, INA_219.getPower()); - nextAvalableChannel++; - } - if (AHTXinitialized) { - sensors_event_t humidity, temp; - AHTX.getEvent(&humidity, &temp); - telemetry.addTemperature(TELEM_CHANNEL_SELF, temp.temperature); - telemetry.addRelativeHumidity(TELEM_CHANNEL_SELF, humidity.relative_humidity); - } - } - - return true; -} - -int PromicroSensorManager::getNumSettings() const { - return NUM_SENSOR_SETTINGS; -} - -const char* PromicroSensorManager::getSettingName(int i) const { - if (i >= 0 && i < NUM_SENSOR_SETTINGS) { - return INA3221_CHANNEL_NAMES[i]; - } - return NULL; -} - -const char* PromicroSensorManager::getSettingValue(int i) const { - if (i >= 0 && i < NUM_SENSOR_SETTINGS) { - return INA3221_CHANNEL_ENABLED[i] ? "1" : "0"; - } - return NULL; -} - -bool PromicroSensorManager::setSettingValue(const char* name, const char* value) { - for (int i = 0; i < NUM_SENSOR_SETTINGS; i++) { - if (strcmp(name, INA3221_CHANNEL_NAMES[i]) == 0) { - int channelEnabled = INA_3221.getEnableChannel(i); - if (strcmp(value, "1") == 0) { - INA3221_CHANNEL_ENABLED[i] = true; - if (!channelEnabled) { - INA_3221.enableChannel(i); - } - } else { - INA3221_CHANNEL_ENABLED[i] = false; - if (channelEnabled) { - INA_3221.disableChannel(i); - } - } - return true; - } - } - return false; -} - -void PromicroSensorManager::initINA3221() { - if (INA_3221.begin()) { - MESH_DEBUG_PRINTLN("Found INA3221 at address: %02X", INA_3221.getAddress()); - MESH_DEBUG_PRINTLN("%04X %04X %04X", INA_3221.getDieID(), INA_3221.getManufacturerID(), INA_3221.getConfiguration()); - - for(int i = 0; i < 3; i++) { - INA_3221.setShuntR(i, TELEM_INA3221_SHUNT_VALUE); - } - INA3221initialized = true; - } else { - INA3221initialized = false; - MESH_DEBUG_PRINTLN("INA3221 was not found at I2C address %02X", TELEM_INA3221_ADDRESS); - } -} - -void PromicroSensorManager::initINA219() { - if (INA_219.begin()) { - MESH_DEBUG_PRINTLN("Found INA219 at address: %02X", INA_219.getAddress()); - INA_219.setMaxCurrentShunt(TELEM_INA219_MAX_CURRENT, TELEM_INA219_SHUNT_VALUE); - INA219initialized = true; - } else { - INA219initialized = false; - MESH_DEBUG_PRINTLN("INA219 was not found at I2C address %02X", TELEM_INA219_ADDRESS); - } -} - -void PromicroSensorManager::initAHTX() { - if (AHTX.begin(&Wire, 0, TELEM_AHTX_ADDRESS)) { - MESH_DEBUG_PRINTLN("Found AHT10/AHT20 at address: %02X", TELEM_AHTX_ADDRESS); - AHTXinitialized = true; - } else { - AHTXinitialized = false; - MESH_DEBUG_PRINTLN("AHT10/AHT20 was not found at I2C address %02X", TELEM_AHTX_ADDRESS); - } -} diff --git a/variants/promicro/target.h b/variants/promicro/target.h index b7475b4a..c289d744 100644 --- a/variants/promicro/target.h +++ b/variants/promicro/target.h @@ -8,14 +8,12 @@ #include #include #include -#include -#include -#include #ifdef DISPLAY_CLASS #include #endif #define NUM_SENSOR_SETTINGS 3 +#include extern PromicroBoard board; extern WRAPPER_CLASS radio_driver; @@ -31,39 +29,4 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); void radio_set_tx_power(uint8_t dbm); mesh::LocalIdentity radio_new_identity(); -#define TELEM_INA3221_ADDRESS 0x42 // INA3221 3 channel current sensor I2C address -#define TELEM_INA219_ADDRESS 0x40 // INA219 single channel current sensor I2C address -#define TELEM_AHTX_ADDRESS 0x38 // AHT10, AHT20 temperature and humidity sensor I2C address - -#define TELEM_INA3221_SHUNT_VALUE 0.100 // most variants will have a 0.1 ohm shunts -#define TELEM_INA3221_SETTING_CH1 "INA3221-1" -#define TELEM_INA3221_SETTING_CH2 "INA3221-2" -#define TELEM_INA3221_SETTING_CH3 "INA3221-3" - -#define TELEM_INA219_SHUNT_VALUE 0.100 // shunt value in ohms (may differ between manufacturers) -#define TELEM_INA219_MAX_CURRENT 5 - -class PromicroSensorManager: public SensorManager { - bool INA3221initialized = false; - bool INA219initialized = false; - bool AHTXinitialized = false; - - // INA3221 channels in telemetry - const char * INA3221_CHANNEL_NAMES[NUM_SENSOR_SETTINGS] = { TELEM_INA3221_SETTING_CH1, TELEM_INA3221_SETTING_CH2, TELEM_INA3221_SETTING_CH3}; - bool INA3221_CHANNEL_ENABLED[NUM_SENSOR_SETTINGS] = {true, true, true}; - - void initINA3221(); - void initINA219(); - void initAHTX(); -public: - PromicroSensorManager(){}; - bool begin() override; - bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override; - int getNumSettings() const override; - const char* getSettingName(int i) const override; - const char* getSettingValue(int i) const override; - bool setSettingValue(const char* name, const char* value) override; -}; - - -extern PromicroSensorManager sensors; \ No newline at end of file +extern EnvironmentSensorManager sensors; \ No newline at end of file