Przeglądaj źródła

* simplified alertIf()
* refactored TimeSeriesData to top-level class

Scott Powell 1 rok temu
rodzic
commit
ac834922de

+ 2 - 61
examples/simple_sensor/SensorMesh.cpp

@@ -237,8 +237,8 @@ void SensorMesh::sendAlert(const char* text) {
   }
 }
 
-void SensorMesh::alertIfLow(Trigger& t, float value, float threshold, const char* text) {
-  if (value < threshold) {
+void SensorMesh::alertIf(bool condition, Trigger& t, const char* text) {
+  if (condition) {
     if (!t.triggered) {
       t.triggered = true;
       t.time = getRTCClock()->getCurrentTime();
@@ -252,65 +252,6 @@ void SensorMesh::alertIfLow(Trigger& t, float value, float threshold, const char
   }
 }
 
-void SensorMesh::alertIfHigh(Trigger& t, float value, float threshold, const char* text) {
-  if (value > threshold) {
-    if (!t.triggered) {
-      t.triggered = true;
-      t.time = getRTCClock()->getCurrentTime();
-      sendAlert(text);
-    }
-  } else {
-    if (t.triggered) {
-      t.triggered = false;
-      // TODO: apply debounce logic
-    }
-  }
-}
-
-void SensorMesh::recordData(TimeSeriesData& data, float value) {
-  uint32_t now = getRTCClock()->getCurrentTime();
-  if (now >= data.last_timestamp + data.interval_secs) {
-    data.last_timestamp = now;
-
-    data.data[data.next] = value;   // append to cycle table
-    data.next = (data.next + 1) % data.num_slots;
-  }
-}
-
-void SensorMesh::calcDataMinMaxAvg(const TimeSeriesData& data, uint32_t start_secs_ago, uint32_t end_secs_ago, MinMaxAvg* dest, uint8_t channel, uint8_t lpp_type) {
-  int i = data.next, n = data.num_slots;
-  uint32_t ago = data.interval_secs * data.num_slots;
-  int num_values = 0;
-  float total = 0.0f;
-
-  dest->_channel = channel;
-  dest->_lpp_type = lpp_type;
-
-  // start at earliest recording, through to most recent
-  while (n > 0) {
-    n--;
-    i = (i + 1) % data.num_slots;
-    if (ago >= end_secs_ago && ago < start_secs_ago) {
-      float v = data.data[i];
-      num_values++;
-      total += v;
-      if (num_values == 1) {
-        dest->_max = dest->_min = v;
-      } else {
-        if (v < dest->_min) dest->_min = v;
-        if (v > dest->_max) dest->_max = v;
-      }
-    }
-    ago -= data.interval_secs;
-  }
-  // calc average
-  if (num_values > 0) {
-    dest->_avg = total / num_values;
-  } else {
-    dest->_avg = NAN;
-  }
-}
-
 float SensorMesh::getAirtimeBudgetFactor() const {
   return _prefs.airtime_factor;
 }

+ 3 - 27
examples/simple_sensor/SensorMesh.h

@@ -3,6 +3,8 @@
 #include <Arduino.h>   // needed for PlatformIO
 #include <Mesh.h>
 
+#include "TimeSeriesData.h"
+
 #if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
 #include <InternalFileSystem.h>
 #elif defined(RP2040_PLATFORM)
@@ -90,33 +92,7 @@ protected:
     Trigger() { triggered = false; time = 0; }
   };
 
-  void alertIfLow(Trigger& t, float value, float threshold, const char* text);
-  void alertIfHigh(Trigger& t, float value, float threshold, const char* text);
-
-  class TimeSeriesData {
-    public:
-      float* data;
-      int num_slots, next;
-      uint32_t last_timestamp;
-      uint32_t interval_secs;
-
-      TimeSeriesData(float* array, int num, uint32_t secs) : num_slots(num), data(array), last_timestamp(0), next(0), interval_secs(secs) { 
-        memset(data, 0, sizeof(float)*num);
-      }
-      TimeSeriesData(int num, uint32_t secs) : num_slots(num), last_timestamp(0), next(0), interval_secs(secs) {
-        data = new float[num];
-        memset(data, 0, sizeof(float)*num);
-      }
-  };
-
-  void recordData(TimeSeriesData& data, float value);
-
-  struct MinMaxAvg {
-    float _min, _max, _avg;
-    uint8_t _lpp_type, _channel;
-  };
-
-  void calcDataMinMaxAvg(const TimeSeriesData& data, uint32_t start_secs_ago, uint32_t end_secs_ago, MinMaxAvg* dest, uint8_t channel, uint8_t lpp_type);
+  void alertIf(bool condition, Trigger& t, const char* text);
 
   virtual void onSensorDataRead() = 0;   // for app to implement
   virtual int querySeriesData(uint32_t start_secs_ago, uint32_t end_secs_ago, MinMaxAvg dest[], int max_num) = 0;  // for app to implement

+ 45 - 0
examples/simple_sensor/TimeSeriesData.cpp

@@ -0,0 +1,45 @@
+#include "TimeSeriesData.h"
+
+void TimeSeriesData::recordData(mesh::RTCClock* clock, float value) {
+  uint32_t now = clock->getCurrentTime();
+  if (now >= last_timestamp + interval_secs) {
+    last_timestamp = now;
+
+    data[next] = value;   // append to cycle table
+    next = (next + 1) % num_slots;
+  }
+}
+
+void TimeSeriesData::calcDataMinMaxAvg(mesh::RTCClock* clock, uint32_t start_secs_ago, uint32_t end_secs_ago, MinMaxAvg* dest, uint8_t channel, uint8_t lpp_type) const {
+  int i = next, n = num_slots;
+  uint32_t ago = clock->getCurrentTime() - last_timestamp;
+  int num_values = 0;
+  float total = 0.0f;
+
+  dest->_channel = channel;
+  dest->_lpp_type = lpp_type;
+
+  // start at most recet recording, back-track through to oldest
+  while (n > 0) {
+    n--;
+    i = (i + num_slots - 1) % num_slots;  // go back by one
+    if (ago >= end_secs_ago && ago < start_secs_ago) {   // filter by the desired time range
+      float v = data[i];
+      num_values++;
+      total += v;
+      if (num_values == 1) {
+        dest->_max = dest->_min = v;
+      } else {
+        if (v < dest->_min) dest->_min = v;
+        if (v > dest->_max) dest->_max = v;
+      }
+    }
+    ago += interval_secs;
+  }
+  // calc average
+  if (num_values > 0) {
+    dest->_avg = total / num_values;
+  } else {
+    dest->_avg = NAN;
+  }
+}

+ 29 - 0
examples/simple_sensor/TimeSeriesData.h

@@ -0,0 +1,29 @@
+#pragma once
+
+#include <Arduino.h>
+#include <Mesh.h>
+
+struct MinMaxAvg {
+  float _min, _max, _avg;
+  uint8_t _lpp_type, _channel;
+};
+
+class TimeSeriesData {
+  float* data;
+  int num_slots, next;
+  uint32_t last_timestamp;
+  uint32_t interval_secs;
+
+public:
+  TimeSeriesData(float* array, int num, uint32_t secs) : num_slots(num), data(array), last_timestamp(0), next(0), interval_secs(secs) { 
+    memset(data, 0, sizeof(float)*num);
+  }
+  TimeSeriesData(int num, uint32_t secs) : num_slots(num), last_timestamp(0), next(0), interval_secs(secs) {
+    data = new float[num];
+    memset(data, 0, sizeof(float)*num);
+  }
+
+  void recordData(mesh::RTCClock* clock, float value);
+  void calcDataMinMaxAvg(mesh::RTCClock* clock, uint32_t start_secs_ago, uint32_t end_secs_ago, MinMaxAvg* dest, uint8_t channel, uint8_t lpp_type) const;
+};
+

+ 3 - 3
examples/simple_sensor/main.cpp

@@ -21,12 +21,12 @@ protected:
   void onSensorDataRead() override {
     float batt_voltage = getVoltage(TELEM_CHANNEL_SELF);
 
-    recordData(battery_data, batt_voltage);   // record battery
-    alertIfLow(low_batt, batt_voltage, 3.4f, "Battery low!");
+    battery_data.recordData(getRTCClock(), batt_voltage);   // record battery
+    alertIf(batt_voltage < 3.4f, low_batt, "Battery low!");
   }
 
   int querySeriesData(uint32_t start_secs_ago, uint32_t end_secs_ago, MinMaxAvg dest[], int max_num) override {
-    calcDataMinMaxAvg(battery_data, start_secs_ago, end_secs_ago, &dest[0], TELEM_CHANNEL_SELF, LPP_VOLTAGE);
+    battery_data.calcDataMinMaxAvg(getRTCClock(), start_secs_ago, end_secs_ago, &dest[0], TELEM_CHANNEL_SELF, LPP_VOLTAGE);
     return 1;
   }
   /* ======================================================================= */