Data Gator
Hardware and software documentation for the Data Gator project.
Loading...
Searching...
No Matches
scheduler.hpp
Go to the documentation of this file.
1
14#ifndef SCHEDULER_HPP
15#define SCHEDULER_HPP
16
17//#include <setup_util.hpp>
18#include <NimBLEDevice.h>
19#include <Adafruit_MAX1704X.h>
20#include <OWMAdafruit_ADS1015.h>
21#include <ble_util.hpp>
22#include <VWCSensor.hpp>
23#include <Teros10.hpp>
24#include <Atlas_EZO-pH.hpp>
25#include <Atlas_Gravity_pH.hpp>
26
27extern bool maxlipo_attached;
28extern Adafruit_MAX17048 maxlipo;
30
31int reset_count = -1; // times reset by WDT, one tick roughly equivalent to one minute
32
44struct planner{
46 int analog_t0 = -1;
48 int ht_t0 = -1;
50 int ota_t0 = -1;
52 int tlm_t0 = -1;
53}planner;
54
58void init_nvs(){
59
60 // NVS Setup
61 gator_prefs.begin("GatorState", RW_MODE);
62
63 if(gator_prefs.isKey("reset_count")){ // if key exists
64 reset_count = gator_prefs.getInt("reset_count");
66 if(DEBUG) Serial.printf("Reset Count = %d\n", reset_count);
67 gator_prefs.putInt("reset_count", reset_count);
68
69 planner.analog_t0 = gator_prefs.getInt("analog_t0");
70 planner.ht_t0 = gator_prefs.getInt("ht_t0");
71 planner.ota_t0 = gator_prefs.getInt("ota_t0");
72 planner.tlm_t0 = gator_prefs.getInt("tlm_t0");
73
74 }else{ // create the keys
76 if(DEBUG) Serial.printf("Reset Count = %d\n", reset_count);
77 gator_prefs.putInt("reset_count", reset_count);
78 gator_prefs.putInt("analog_t0", planner.analog_t0);
79 gator_prefs.putInt("ht_t0", planner.ht_t0);
80 gator_prefs.putInt("ota_t0", planner.ota_t0);
81 gator_prefs.putInt("tlm_t0", planner.tlm_t0);
82
83 }
84
85}
86
95 bool run_vwc = reset_count - planner.analog_t0 >= VWC_FREQ;
96 bool run_ht = reset_count - planner.ht_t0 >= HT_FREQ;
97 bool run_ota_update = reset_count - planner.ota_t0 >= OTA_FREQ;
98 bool run_tlm = reset_count - planner.tlm_t0 >= TLM_FREQ;
99
100 if( run_vwc || run_ht || run_ota_update || run_tlm){
101 // start WIFI
102 return true;
103 }else return false;
104
105}
106
110void ReadHT(){
111 if(DEBUG) Serial.println("[HT]");
112 NimBLEScan* scanner = NimBLEDevice::getScan();
113 scanner->setAdvertisedDeviceCallbacks(new ScanCallbacks());
114 scanner->setActiveScan(true); // retrieve results from all scanned devices
115 scanner->setInterval(100); // time between scans??
116 scanner->setWindow(99); // less than or equal to setInterval, is how long to scan for
117 //scanner->start(5, true);
118
119 int scanTime = 10; // in seconds
120
121 BLEScanResults res = scanner->start(scanTime, false);
122 scanner->clearResults();
123}
124
129
130 if(DEBUG) Serial.println("[VWC/WIRED SENSORS] queueing data");
131
132 // turn on power to sensors
133 digitalWrite(PWR_EN, HIGH);
134 delay(10000);
135
136 // initialize sensor readers
137 VWCSensor* vwc_converter = new Teros10();
138 pHSensor* pH_converter = new AtlasGravitypH();
139 AtlasEZOpH* ezopH_converter = new AtlasEZOpH();
140
141 MQTTMailer instance = MQTTMailer::getInstance();
142 // get the MAC address
143 std::string mac_str(WiFi.macAddress().c_str());
144
145
146 int raw_analog[4];
147 double voltage[4];
148
149 // read voltage at analog ports
150 // SHALLOW
151 raw_analog[0] = ads.readADC_SingleEnded(1);
152 voltage[0] = raw_analog[0] * 0.0001875;
153 // MIDDLE
154 raw_analog[1] = ads.readADC_SingleEnded(2);
155 voltage[1] = raw_analog[1] * 0.0001875;
156 // DEEP
157 raw_analog[2] = ads.readADC_SingleEnded(3);
158 voltage[2] = raw_analog[2] * 0.0001875;
159 // ANALOG/pH
160 raw_analog[3] = ads.readADC_SingleEnded(0);
161 voltage[3] = raw_analog[3] * 0.0001875;
162
163 // read I2C sensors
164 char pH_normal[32];
165 char pH_shallow[32];
166 char pH_middle[32];
167 char pH_deep[32];
168 // NORMAL
169 if(ezopH_converter->sensor_at_address(EZO_I2C_ADDR)){
170 strcpy(pH_normal, ezopH_converter->getpH_str(EZO_I2C_ADDR));
171 ezopH_converter->clear_pH_str();
172 // build pH mqtt message
173 std::string topic = ezopH_converter->getSensorType() + "/pH/normal/" + mac_str;
174 //std::string msg = "{\"MAC\": \"" + mac_str + "\"," + pH_converter->toJSON(voltage[3]) + "}";
175 std::string msg = "{\"MAC\": \"" + mac_str + "\", \"PH\":" + pH_normal + "}";
176 //instance.mailMessage(&mqtt_client, topic, msg);
177 log_data(topic, msg);
178
179 }else if(DEBUG){
180 Serial.println("\tno pH at addr 99");
181 }
182 // SHALLOW
183 if(ezopH_converter->sensor_at_address(EZO_I2C_SHALLOW_ADDR)){
184 strcpy(pH_shallow, ezopH_converter->getpH_str(EZO_I2C_SHALLOW_ADDR));
185 ezopH_converter->clear_pH_str();
186 // build pH mqtt message
187 std::string topic = ezopH_converter->getSensorType() + "/pH/shallow/" + mac_str;
188 //std::string msg = "{\"MAC\": \"" + mac_str + "\"," + pH_converter->toJSON(voltage[3]) + "}";
189 std::string msg = "{\"MAC\": \"" + mac_str + "\", \"PH\":" + pH_shallow + "}";
190 //instance.mailMessage(&mqtt_client, topic, msg);
191 log_data(topic, msg);
192
193 }else if(DEBUG){
194 Serial.println("\tno pH at addr shallow");
195 }
196 // MIDDLE
197 if(ezopH_converter->sensor_at_address(EZO_I2C_MIDDLE_ADDR)){
198 strcpy(pH_middle, ezopH_converter->getpH_str(EZO_I2C_MIDDLE_ADDR));
199 ezopH_converter->clear_pH_str();
200 std::string topic = ezopH_converter->getSensorType() + "/pH/middle/" + mac_str;
201 //std::string msg = "{\"MAC\": \"" + mac_str + "\"," + pH_converter->toJSON(voltage[3]) + "}";
202 std::string msg = "{\"MAC\": \"" + mac_str + "\", \"PH\":" + pH_middle + "}";
203 //instance.mailMessage(&mqtt_client, topic, msg);
204 log_data(topic, msg);
205
206 }else if(DEBUG){
207 Serial.println("\tno pH at addr middle");
208 }
209 // DEEP
210 if(ezopH_converter->sensor_at_address(EZO_I2C_DEEP_ADDR)){
211 strcpy(pH_deep, ezopH_converter->getpH_str(EZO_I2C_DEEP_ADDR));
212 ezopH_converter->clear_pH_str();
213 std::string topic = ezopH_converter->getSensorType() + "/pH/deep/" + mac_str;
214 //std::string msg = "{\"MAC\": \"" + mac_str + "\"," + pH_converter->toJSON(voltage[3]) + "}";
215 std::string msg = "{\"MAC\": \"" + mac_str + "\", \"PH\":" + pH_deep + "}";
216 //instance.mailMessage(&mqtt_client, topic, msg);
217 log_data(topic, msg);
218
219 }else if(DEBUG){
220 Serial.println("\tno pH at addr deep");
221 }
222
223 free(pH_converter);
224
225 // turn off power to sensors
226 digitalWrite(PWR_EN, LOW);
227
228 // build VWC mqtt message
229 std::string brand = vwc_converter->getSensorType();
230
231 if(WiFi.status() == WL_CONNECTED && !mqtt_client.connected()){
232 if(DEBUG) Serial.println("\t-> not connected");
233 instance.reconnect(mqtt_client);
234 }
235
236 for(int i = 0; i < 3; i++){
237
238 std::string depth = "";
239 switch(i){
240 case 0:
241 depth = "shallow";
242 break;
243 case 1:
244 depth = "middle";
245 break;
246 case 2:
247 depth = "deep";
248 break;
249 }
250
251 std::string topic = brand + "/" + std::to_string(i) + std::string("_") + depth + std::string("/") + mac_str;
252 std::string msg = "{\"MAC\": \"" + mac_str + "\", \"DEPTH\": \"" + depth + "\", " + vwc_converter->toJSON(voltage[i]) + "}";
253 //instance.mailMessage(&mqtt_client, topic, msg);
254 log_data(topic, msg);
255 }
256 free(vwc_converter);
257}
258
263 if(USB_DEBUG) Serial.println("[OTA] ran");
265}
266
270void PatWDT(){
271 if(USB_DEBUG) Serial.println("[WDT] ran");
272 digitalWrite(DONE, HIGH);
273 vTaskDelay(pdMS_TO_TICKS(10));
274 digitalWrite(DONE, LOW);
275}
276
280void SendTLM(){
281 if(DEBUG){
282 Serial.println("[TLM] queueing data");
283 }
284
285 digitalWrite(PWR_EN, HIGH);
286
287 MQTTMailer instance = MQTTMailer::getInstance();
288
289 if(WiFi.status() == WL_CONNECTED && !mqtt_client.connected()){
290 if(USB_DEBUG) Serial.println("\t-> not connected");
291 instance.reconnect(mqtt_client);
292 }
293
294 std::string fw_version = "V" + std::to_string(VERSION_MAJOR) + "." + std::to_string(VERSION_MINOR) + "." + std::to_string(VERSION_PATCH);
295 std::string topic = "datagator/tlm/" + std::string(WiFi.macAddress().c_str());
296 std::string msg = "{ \"MAC\": \"" + std::string(WiFi.macAddress().c_str()) +
297 "\", \"FIRMWARE_VERSION\": \"" + fw_version +
298 "\", \"RSSI\": " + std::to_string(WiFi.RSSI()) +
299 ", \"BSSID\": \"" + WiFi.BSSIDstr().c_str() + "\"";
300
302 msg = msg + ", \"BATT_VOLTAGE\": " + std::to_string(maxlipo.cellVoltage()) +
303 ", \"BATT_PERCENTAGE\": " + std::to_string(maxlipo.cellPercent()) + "}";
304 }else{
305 msg = msg + ", \"BATT_VOLTAGE\": -1" +
306 ", \"BATT_PERCENTAGE\": -1}";
307 }
308
309 digitalWrite(PWR_EN, LOW);
310 //instance.mailMessage(&mqtt_client, topic, msg);
311 log_data(topic, msg);
312}
313
314
321
322 // bounds checking -> error msgs
324 if(DEBUG) Serial.println("[ERROR] over ran max reset count without reseting count, check if variable is being reset or if tasks are not completing");
325 //Serial.printf("\tPlanner { read analog [%d], read ht [%d], published MQTT [%d] }\n", planner.readAnalog, planner.readHT, planner.publishedMQTT);
327 gator_prefs.putInt("reset_count", reset_count);
328 gator_prefs.putInt("analog_t0", planner.analog_t0);
329 gator_prefs.putInt("ht_t0", planner.ht_t0);
330 gator_prefs.putInt("ota_t0", planner.ota_t0);
331 gator_prefs.putInt("tlm_t0", planner.tlm_t0);
332 }
333
338
339 if(run_vwc){
340 ReadWired();
342 gator_prefs.putInt("analog_t0", planner.analog_t0);
343 mqtt_client.loop();
344 }
345
346 if(run_ht){
347 ReadHT();
349 gator_prefs.putInt("ht_t0", planner.ht_t0);
350 // Publish happens in callback function
351 mqtt_client.loop();
352 }
353
354 if(run_ota_update){
356 gator_prefs.putInt("ota_t0", planner.ota_t0);
357 OTAUpdate();
358 mqtt_client.loop();
359 }
360
361 if(run_tlm){
362 SendTLM();
364 gator_prefs.putInt("tlm_t0", planner.tlm_t0);
365 mqtt_client.loop();
366 }
367
368}
369
376 gator_prefs.putInt("ota_t0", reset_count);
377 gator_prefs.putInt("tlm_t0", reset_count);
378 gator_prefs.putInt("analog_t0", reset_count);
379 gator_prefs.putInt("ht_t0", reset_count);
380}
381
382#endif
Implements I2C pH sensor which inherits from pHSensor.hpp.
#define EZO_I2C_SHALLOW_ADDR
I2C address assigned to sensors buried at shallow depth (~1ft)
Definition Atlas_EZO-pH.hpp:19
#define EZO_I2C_MIDDLE_ADDR
I2C address assigned to sensors buried at medium depth (~2ft)
Definition Atlas_EZO-pH.hpp:20
#define EZO_I2C_ADDR
Default I2C address for sensor.
Definition Atlas_EZO-pH.hpp:18
#define EZO_I2C_DEEP_ADDR
I2C address assigned to deepest sensors (~3ft)
Definition Atlas_EZO-pH.hpp:21
This file implements an analog pH sensor which inherits from pHSensor.hpp.
Interface for VWC sensors.
Utilities such as callbacks for parsing bluetooth packets.
uint16_t readADC_SingleEnded(uint8_t channel)
Gets a single-ended ADC reading from the specified channel.
Definition OWMAdafruit_ADS1015.cpp:141
Definition OWMAdafruit_ADS1015.h:150
Defines an I2C pH sensor which inherits from pHSensor.hpp.
Definition Atlas_EZO-pH.hpp:34
bool sensor_at_address(int address)
Check if sensor present at address.
Definition Atlas_EZO-pH.hpp:64
char * getpH_str(int address)
Get the pH reading as a string.
Definition Atlas_EZO-pH.hpp:158
std::string getSensorType(void)
Get the string identifier for the Atlas EZO pH sensor. For use in MQTT topics and debugging.
Definition Atlas_EZO-pH.hpp:174
Defineds an analog pH sensor interface for the Atlas Gravity pH.
Definition Atlas_Gravity_pH.hpp:18
Converts MQTTMail objects into viable MQTT messages so that they can be published.
Definition MQTTMailer.hpp:60
void reconnect(PubSubClient mqtt_client)
Attempt to reconnect to MQTT broker every 5 seconds until successful.
Definition MQTTMailer.cpp:48
Callbacks for BLE packets.
Definition ble_util.hpp:35
Definition Teros10.hpp:15
Interface for converting a voltage measurement from an analog sensor into a double,...
Definition VWCSensor.hpp:23
virtual std::string toJSON(double voltage)
Convert data to JSON key value pairs.
virtual std::string getSensorType()
Return brand+sensor model string for topic.
Interface for pH sensors.
Definition pHSensor.hpp:19
#define TLM_FREQ
Definition config.hpp:29
#define OTA_FREQ
Definition config.hpp:23
#define VWC_FREQ
Definition config.hpp:25
#define HT_FREQ
Definition config.hpp:27
#define DEBUG
Definition config.hpp:17
#define MAX_COUNT
Definition config.hpp:21
void log_data(std::string topic, std::string message)
Definition logger.hpp:32
#define PWR_EN
Power enable pin for sensors.
Definition pinout.hpp:48
#define DONE
Done pin, for watchdog timer.
Definition pinout.hpp:50
Adafruit_MAX17048 maxlipo
MAX17048 battery Fuel Gauge.
Definition setup_util.hpp:28
void OTAUpdate()
Checks and updates from new code published at HTTPS address.
Definition scheduler.hpp:262
void ReadHT()
Reads temperature and humidity sensors via BLE and then sends complete data to the database.
Definition scheduler.hpp:110
int reset_count
number of resets retrieved for NVS
Definition scheduler.hpp:31
void Scheduler(int reset_count)
Perform a state transition based on the number of reset counts.
Definition scheduler.hpp:320
void PatWDT()
Pat the watchdog by raising watchdog done pin high, and then setting it low.
Definition scheduler.hpp:270
Adafruit_ADS1115 ads
Analog to digital converter object (I2C)
Definition setup_util.hpp:26
void init_nvs()
Open NVS, check if it is initialized with data, if not, initialize it.
Definition scheduler.hpp:58
bool maxlipo_attached
Fuel Gauge successfully initialized?
Definition setup_util.hpp:29
bool task_is_scheduled(int reset_count)
Check if a task will run this time, NVS must be initialized first!
Definition scheduler.hpp:94
void ReadWired()
Reads all wired sensors attached to the aggregator.
Definition scheduler.hpp:128
void SchedulerClearAll(int reset_count)
Clear all tasks so that none are scheduled to run.
Definition scheduler.hpp:375
void SendTLM()
Send a telemetry message to the MQTT broker.
Definition scheduler.hpp:280
#define RW_MODE
define read/write access mode for SD card files
Definition setup_util.hpp:12
const bool USB_DEBUG
USB serial debugging enabled.
Definition main.cpp:62
Preferences gator_prefs
NVS memory object.
Definition main.cpp:67
Data structure for task scheduling stored in NVS.
Definition scheduler.hpp:44
int ota_t0
Definition scheduler.hpp:50
int ht_t0
Definition scheduler.hpp:48
int tlm_t0
Definition scheduler.hpp:52
int analog_t0
Definition scheduler.hpp:46
PubSubClient mqtt_client
MQTT client object for logging.
void attempt_update()
Attempts OTA firmware update from server.
Definition update.cpp:178