Browse Source

283 Add support of INA3221 to Promicro telemetry

Normunds Gavars 1 year ago
parent
commit
b035487101

+ 2 - 0
.gitignore

@@ -6,3 +6,5 @@
 .vscode/ipch
 out/
 .direnv/
+.DS_Store
+.vscode/settings.json

+ 6 - 0
src/helpers/SensorManager.h

@@ -7,6 +7,12 @@
 
 #define TELEM_CHANNEL_SELF   1   // LPP data channel for 'self' device
 
+#define TELEM_INA3221_ADDRESS 0x40      // INA3221 3 channel current, voltage, power 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 Channel 1"
+#define TELEM_INA3221_SETTING_CH2 "INA3221 Channel 2"
+#define TELEM_INA3221_SETTING_CH3 "INA3221 Channel 3"
+
 class SensorManager {
 public:
   double node_lat, node_lon;  // modify these, if you want to affect Advert location

+ 72 - 0
src/helpers/sensors/SensorSettingsManager.h

@@ -0,0 +1,72 @@
+#include <vector>
+#include <string>
+
+class SensorSettingsManager {
+  private:
+    std::vector<std::pair<std::string, bool>> settings;
+
+  public:
+
+    int getSettingCount() const {
+        return static_cast<int>(settings.size());
+    };
+
+    bool addSetting(const std::string& name, bool defaultValue = false){
+        for (const auto& setting : settings) {
+            if (setting.first == name) {
+                return false;
+            }
+        }
+        settings.emplace_back(name, defaultValue);
+        return true; 
+    };
+
+    bool removeSetting(const std::string& name) {
+        for (auto it = settings.begin(); it != settings.end(); ++it) {
+            if (it->first == name) {
+                settings.erase(it);
+                return true;
+            }
+        }
+        return false;
+    };
+
+    const char* getSettingValue(const std::string& name) const{
+        for (const auto& setting : settings) {
+            if (setting.first == name) {
+                return setting.second ? "true" : "false";
+            }
+        }
+        return NULL;
+    };
+    
+    const char* getSettingValue(int index) const {
+        if (index >= 0 && index < getSettingCount()) {
+            return settings[index].second ? "true" : "false";
+        }
+        return NULL;
+    };
+
+    bool setSettingValue(const std::string& name, const std::string& value) {
+        for (auto& setting : settings) {
+            if (setting.first == name) {
+                // Convert value to boolean
+                if (value == "1" || value == "true") {
+                    setting.second = true;
+                } else {
+                    setting.second = false;
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    const char* getSettingName(int index) const {
+        if (index >= 0 && index < getSettingCount()){
+            return settings[index].first.c_str();
+        }
+        return NULL;
+    };
+
+};

+ 2 - 1
variants/promicro/platformio.ini

@@ -36,7 +36,8 @@ build_flags =
 ;  -D MESH_DEBUG=1
 lib_deps = ${Faketec.lib_deps}
   adafruit/RTClib @ ^2.1.3
-
+  robtillaart/INA3221 @ ^0.4.1
+  
 [env:Faketec_room_server]
 extends = Faketec
 build_src_filter = ${Faketec.build_src_filter}

+ 105 - 1
variants/promicro/target.cpp

@@ -10,7 +10,7 @@ WRAPPER_CLASS radio_driver(radio, board);
 
 VolatileRTCClock fallback_clock;
 AutoDiscoverRTCClock rtc_clock(fallback_clock);
-SensorManager sensors;
+PromicroSensorManager sensors;
 
 #ifndef LORA_CR
   #define LORA_CR      5
@@ -74,3 +74,107 @@ mesh::LocalIdentity radio_new_identity() {
   RadioNoiseListener rng(radio);
   return mesh::LocalIdentity(&rng);  // create new random identity
 }
+
+PromicroSensorManager::PromicroSensorManager(){
+  INA_3221 = new INA3221(TELEM_INA3221_ADDRESS, &Wire);
+}
+
+PromicroSensorManager::~PromicroSensorManager(){
+  if (INA_3221) {
+    delete INA_3221;
+    INA_3221 = nullptr;
+  }
+}
+
+bool PromicroSensorManager::begin() {
+  if (INA_3221->begin() ) {
+    Serial.print("Found INA3221 at address ");
+    Serial.print(INA_3221->getAddress());
+    Serial.println();
+    Serial.print(INA_3221->getDieID(), HEX);
+    Serial.print(INA_3221->getManufacturerID(), HEX);
+    Serial.print(INA_3221->getConfiguration(), HEX);
+    Serial.println();
+
+    for(int i = 0; i < 3; i++) {
+      INA_3221->setShuntR(i, TELEM_INA3221_SHUNT_VALUE);
+    }
+    // add INA3221 settings to settings manager
+    settingsManager.addSetting(TELEM_INA3221_SETTING_CH1, true);
+    settingsManager.addSetting(TELEM_INA3221_SETTING_CH2, true);
+    settingsManager.addSetting(TELEM_INA3221_SETTING_CH3, true);
+    INA3221initialized = true;
+  }
+  else {
+    INA3221initialized = false;
+    Serial.print("INA3221 was not found at I2C address ");
+    Serial.print(TELEM_INA3221_ADDRESS, HEX);
+    Serial.println();
+  }
+  return true;
+}
+
+bool PromicroSensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) {
+  // TODO: what is the correct permission here?
+  if (requester_permissions && TELEM_PERM_BASE) {
+    if (INA3221initialized) {
+      for(int i = 0; i < 3; i++) {
+        // add only enabled INA3221 channels to telemetry
+        if (settingsManager.getSettingValue(INA3221_CHANNEL_NAMES[i]) == "true") {
+          
+          // TODO: remove when telemetry support gets properly added
+          // Serial.print("CH");
+          // Serial.print(i);
+          // Serial.print(" Voltage: ");
+          // Serial.print(INA_3221->getBusVoltage(i));
+          // Serial.print("V Current: ");
+          // Serial.print(INA_3221->getCurrent(i));
+          // Serial.print("A Power: ");
+          // Serial.print(INA_3221->getPower(i));
+          // Serial.println();
+
+          telemetry.addVoltage(INA3221_CHANNELS[i], INA_3221->getBusVoltage(i));
+          telemetry.addCurrent(INA3221_CHANNELS[i], INA_3221->getCurrent(i));
+          telemetry.addPower(INA3221_CHANNELS[i], INA_3221->getPower(i));
+        }
+      }
+    }
+  }
+
+  return true;
+}
+
+int PromicroSensorManager::getNumSettings() const {
+  return settingsManager.getSettingCount();
+}
+
+const char* PromicroSensorManager::getSettingName(int i) const {
+  return settingsManager.getSettingName(i);
+}
+
+const char* PromicroSensorManager::getSettingValue(int i) const {
+  return settingsManager.getSettingValue(i);
+}
+
+bool PromicroSensorManager::setSettingValue(const char* name, const char* value) {
+  if (settingsManager.setSettingValue(name, value)) {
+    onSettingsChanged();
+    return true;
+  }
+  return false;
+}
+
+void PromicroSensorManager::onSettingsChanged() {
+  if (INA3221initialized) {
+    for(int i = 0; i < 3; i++) {
+      int channelEnabled = INA_3221->getEnableChannel(i);
+      bool settingEnabled = settingsManager.getSettingValue(INA3221_CHANNEL_NAMES[i]) == "true";
+      if (!settingEnabled && channelEnabled) {
+        INA_3221->disableChannel(i);
+      }
+      if (settingEnabled && !channelEnabled) {
+        INA_3221->enableChannel(i);
+      }
+    }
+  }
+}

+ 27 - 1
variants/promicro/target.h

@@ -8,14 +8,40 @@
 #include <helpers/CustomLLCC68Wrapper.h>
 #include <helpers/AutoDiscoverRTCClock.h>
 #include <helpers/SensorManager.h>
+#include <helpers/sensors/SensorSettingsManager.h>
+#include <INA3221.h>
 
 extern PromicroBoard board;
 extern WRAPPER_CLASS radio_driver;
 extern AutoDiscoverRTCClock rtc_clock;
-extern SensorManager sensors;
+
 
 bool radio_init();
 uint32_t radio_get_rng_seed();
 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();
+
+class PromicroSensorManager: public SensorManager {
+  INA3221 * INA_3221;
+  bool INA3221initialized = false;
+  SensorSettingsManager settingsManager;
+
+  // INA3221 channels in telemetry
+  int INA3221_CHANNELS[3] = {TELEM_CHANNEL_SELF + 1, TELEM_CHANNEL_SELF + 2, TELEM_CHANNEL_SELF+ 3};
+  char * INA3221_CHANNEL_NAMES[3] = { TELEM_INA3221_SETTING_CH1, TELEM_INA3221_SETTING_CH2, TELEM_INA3221_SETTING_CH3};
+  void onSettingsChanged();
+
+public:
+  PromicroSensorManager();
+  ~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;