hhs utility
hhsUtility.cpp
Go to the documentation of this file.
1 
6 // Version: 2022-01-09.
7 
8 #include "hhsUtility.h"
9 
10 /*----|| #DEFINES ||--------------------------------------------*/
11 #define DEBUG 1 // 0: No debug info. 1: Show debug info.
12 #define LWD_TIMEOUT 15*1000 // Reboot if loop watchdog timer reaches this time out value
13 
14 /* ----- lwTicker callback routine variables -------- */
15 Ticker lwdTicker;
16 unsigned long lwdTime = 0;
17 unsigned long lwdTimeout = LWD_TIMEOUT;
18 /* ----- lwTicker callback routine variables END ---- */
19 
20 String formatBytes(size_t bytes) // convert sizes in bytes to KB and MB
21 {
22  String ret;
23 
24  if (bytes < 1024)
25  {
26  ret = String(bytes) + "B";
27  }
28  else if (bytes < (1024 * 1024))
29  {
30  ret = String(bytes / 1024.0) + "KB";
31  }
32  else if (bytes < (1024 * 1024 * 1024))
33  {
34  ret= String(bytes / 1024.0 / 1024.0) + "MB";
35  }
36  return ret;
37 }
38 
39 void printFloat(float value, int places)
40 {
41  // this is used to cast digits
42  int digit;
43  float tens = 0.1;
44  int tenscount = 0;
45  int i;
46  float tempfloat = value;
47 
48  // make sure we round properly. this could use pow from <math.h>, but doesn't seem worth the import
49  // if this rounding step isn't here, the value 54.321 prints as 54.3209
50 
51  // calculate rounding term d: 0.5/pow(10,places)
52  float d = 0.5;
53  if (value < 0)
54  d *= -1.0;
55  // divide by ten for each decimal place
56  for (i = 0; i < places; i++)
57  d/= 10.0;
58  // this small addition, combined with truncation will round our values properly
59  tempfloat += d;
60 
61  // first get value tens to be the large power of ten less than value
62  // tenscount isn't necessary but it would be useful if you wanted to know after this how many chars the number will take
63 
64  if (value < 0)
65  tempfloat *= -1.0;
66  while ((tens * 10.0) <= tempfloat)
67  {
68  tens *= 10.0;
69  tenscount += 1;
70  }
71 
72  // write out the negative if needed
73  if (value < 0)
74  Serial.print('-');
75 
76  if (tenscount == 0)
77  Serial.print(0, DEC);
78 
79  for (i=0; i< tenscount; i++)
80  {
81  digit = (int) (tempfloat/tens);
82  Serial.print(digit, DEC);
83  tempfloat = tempfloat - ((float)digit * tens);
84  tens /= 10.0;
85  }
86 
87  // if no places after decimal, stop now and return
88  if (places <= 0)
89  return;
90 
91  // otherwise, write the point and continue on
92  Serial.print('.');
93 
94  // now write out each decimal place by shifting digits one by one into the ones place and writing the truncated value
95  for (i = 0; i < places; i++)
96  {
97  tempfloat *= 10.0;
98  digit = (int) tempfloat;
99  Serial.print(digit,DEC);
100  // once written, subtract off that digit
101  tempfloat = tempfloat - (float) digit;
102  }
103 }
104 
105 boolean isNumeric(String str)
106 {
107  unsigned int stringLength = str.length();
108 
109  if (stringLength == 0) return false;
110 
111  for(unsigned int i = 0; i < stringLength; ++i)
112  {
113  if (isDigit(str.charAt(i)))
114  {
115  continue;
116  }
117  return false;
118  }
119  return true;
120 }
121 
122 int errorState(int state, int ledRed, int ledGreen)
123 {
124  // Change to use std LED on Wemos board.
125 
126  int i = 0;
127  Serial.println("Entered error state.");
128  digitalWrite(ledRed, LOW);
129  digitalWrite(ledGreen, LOW);
130 
131  if( state == 1) // NO WiFi available
132  {
133  Serial.println("!! Entering error state - No WiFi.");
134  while(1)
135  {
136  i++;
137  digitalWrite(ledRed, HIGH);
138  digitalWrite(ledGreen, LOW);
139  delay(400);
140  digitalWrite(ledRed, LOW);
141  digitalWrite(ledGreen, LOW);
142  delay(400);
143  if( i > 20 )
144  {
145  i = 0;
146  Serial.println("Entered errorstate 1. Press reset");
147  ESP.restart();
148  }
149  }
150  }
151  if( state == 2 ) // Could not connect to MQTT broker.
152  {
153  while(1)
154  {
155  digitalWrite(ledRed, HIGH);
156  digitalWrite(ledGreen, LOW);
157  delay(200);
158  digitalWrite(ledRed, LOW);
159  digitalWrite(ledGreen, LOW);
160  delay(200);
161  digitalWrite(ledRed, HIGH);
162  digitalWrite(ledGreen, LOW);
163  delay(200);
164  digitalWrite(ledRed, LOW); // turn the LED off by making the voltage LOW
165  digitalWrite(ledGreen, LOW);
166  delay(600);
167  if( i++ > 60 )
168  {
169  i = 0;
170  Serial.println("Entered error state 2. Could not connect to MQTT broker. Press reset");
171  }
172  }
173  }
174  if( state == 3) // No One Wire temp sensor.
175  {
176  Serial.println("!! Entering error state - No One Wire temp sensor.");
177  while(1)
178  {
179  i++;
180  digitalWrite(ledRed, HIGH);
181  digitalWrite(ledGreen, LOW);
182  delay(200);
183  digitalWrite(ledRed, LOW);
184  digitalWrite(ledGreen, LOW);
185  delay(600);
186  if( i > 20 )
187  {
188  i = 0;
189  Serial.println("Entered errorstate 1. Press reset");
190  ESP.restart();
191  }
192  }
193  }
194  if( state == 4 ) // Not possible to start SPIFFS
195  {
196  while(1)
197  {
198  digitalWrite(ledRed, HIGH);
199  digitalWrite(ledGreen, LOW);
200  delay(600);
201  digitalWrite(ledRed, LOW); // turn the LED off by making the voltage LOW
202  digitalWrite(ledGreen, LOW);
203  delay(200);
204  if( i++ > 60 )
205  {
206  i = 0;
207  Serial.println("Entered error state 4. Not possible to start SPIFFS. Press reset");
208  }
209  }
210  }
211  if( state == 5) // Could not transmit data to emoncms.
212  {
213  Serial.println("!! Entering error state - Could not transmit data to emoncms, but we need to continue regulate.");
214  return true;
215  }
216  return false;
217 }
218 
219 void keypressWait(void)
220 {
221  Serial.println("** Hit a key to continue");
222  while(Serial.available() == 0){}
223  while(Serial.available()){Serial.read();}
224 }
225 
226 void ICACHE_RAM_ATTR lwdtcb(void)
227 {
228  if ((millis() - lwdTime > LWD_TIMEOUT) || (lwdTimeout - lwdTime != LWD_TIMEOUT))
229  /*
230  * DO not try to simplify to
231  *
232  * if ((millis() > lwdTimeout) || (lwdTimeout - lwdTime != LWD_TIMEOUT))
233  *
234  * It will not work when roll over occurs when lwdTime > 0xFFFFFFFF - LWD_TIMEOUT
235  * and lwdTimeout (which would be > 0xFFFFFFFF) becomes a small value < LWD_TIMEOUT
236  */
237  {
238  // could perform other actions before restarting the ESP
239  Serial.println("WARNING loop Blocked! check for deadlock!");
240  //ESP.restart();
241  }
242 }
243 
244 void lwdtFeedInit(void)
245 {
246  lwdtFeed();
247  lwdTicker.attach_ms(LWD_TIMEOUT, lwdtcb); // attach lwdt callback routine to Ticker object
248 }
249 
250 void lwdtFeed(void)
251 {
252  lwdTime = millis();
254 }
255 
256 int getBootDevice(void)
257 {
258  int bootmode;
259  asm (
260  "movi %0, 0x60000200\n\t"
261  "l32i %0, %0, 0x118\n\t"
262  : "+r" (bootmode) /* Output */
263  : /* Inputs (none) */
264  : "memory" /* Clobbered */
265  );
266  return ((bootmode >> 0x10) & 0x7);
267 }
268 
269 int startWiFi(IPAddress _ip, IPAddress _dns, IPAddress _gateway, IPAddress _subnet, char *_ssid, char *_password, char *_host)
270 {
271  int c = 0;
272 
273  Serial.println();
274  Serial.print("** Connecting to ");
275  Serial.println(_ssid);
276 
277  WiFi.enableSTA(true);
278  WiFi.setAutoConnect (true); // Configure module to automatically connect on power on to the last used access point.
279  WiFi.setAutoReconnect (true); // Set whether module will attempt to reconnect to an access point in case it is disconnected.
280 
281  WiFi.config(_ip, _gateway, _subnet, _dns);
282  WiFi.hostname(_host); // NEDD TO BE UNIQUE. Use id[].
283  WiFi.begin(_ssid, _password);
284 
285  while (WiFi.status() != WL_CONNECTED) // Wait for WiFi connection
286  {
287  delay(500);
288  Serial.print(".");
289  c++;
290  if( c > 40 ) // Adjust if it is waiting too long. Time = 500 * 40 usec.
291  {
292  // Waited to long, no WiFi available. This is serious.
293  Serial.println("\nNo WiFi available. Check configuration.\n");
294  // HHS enter error state where LED_POWER flashes.
295  return false;
296  }
297  }
298 
299  if( c < 40 )
300  {
301  Serial.println("");
302  Serial.print(" ** Connected to..: "); Serial.println(_ssid);
303  Serial.print(" ** IP address....: "); Serial.println(WiFi.localIP());
304  Serial.print(" ** Gateway.......: "); Serial.println(WiFi.gatewayIP());
305  Serial.print(" ** DNS...........: "); Serial.println(WiFi.dnsIP());
306  Serial.print(" ** RSSI..........: "); Serial.println(WiFi.RSSI());
307  Serial.print(" ** WiFi.status...: "); showWiFiStatus(WiFi.status());
308  }
309  return true;
310 }
311 
312 void showWiFiStatus( int i )
313 {
314  switch (i)
315  {
316  case 255:
317  Serial.println("WL_NO_SHIELD");
318  break;
319  case 0:
320  Serial.println("WL_IDLE_STATUS");
321  break;
322  case 1:
323  Serial.println("WL_NO_SSID_AVAIL");
324  break;
325  case 2:
326  Serial.println("WL_SCAN_COMPLETED");
327  break;
328  case 3:
329  Serial.println("WL_CONNECTED");
330  break;
331  case 4:
332  Serial.println("WL_CONNECT_FAILED");
333  break;
334  case 5:
335  Serial.println("WL_CONNECTION_LOST");
336  break;
337  case 6:
338  Serial.println("WL_DISCONNECTED");
339  break;
340  default:
341  Serial.println("_UNKNOWN");
342  break;
343  }
344 }
345 
346 bool doWifiConnect(char *_ssid, char *_password)
347 {
348  if( DEBUG ) Serial.println("** Reconnecting WLAN...");
349  Serial.print(" ** WiFi.status: "); showWiFiStatus( WiFi.status() );
350  //WiFi.disconnect(true);
351  WiFi.mode(WIFI_STA);
352  WiFi.begin(_ssid, _password);
353 
354  int waitCounter = 0;
355  while (WiFi.status() != WL_CONNECTED)
356  {
357  waitCounter++;
358  if (waitCounter == 30)
359  {
360  Serial.println("** ERROR: could not reconnect WiFi");
361  return false;
362  }
363  delay(500);
364  }
365  if( DEBUG )
366  {
367  Serial.print(" ** waitCounter: "); Serial.println(waitCounter);
368  }
369  Serial.print("** WiFi reconnected with status: "); showWiFiStatus( WiFi.status() );
370  return true;
371 }
372 
373 int MQTT_connect(Adafruit_MQTT_Client *_mqtt)
374 {
375  int8_t ret;
376  // Stop if already connected.
377  if (_mqtt->connected())
378  {
379  if( DEBUG ) Serial.println(" ** Connected to MQTT.");
380  return true;
381  }
382  //digitalWrite(LED_RED, HIGH);
383  //digitalWrite(LED_GREEN, LOW);
384  Serial.print("Connecting to MQTT... ");
385  uint8_t retries = 3;
386 
387  while ((ret = _mqtt->connect()) != 0)
388  { // connect will return 0 for connected
389  Serial.println(_mqtt->connectErrorString(ret));
390  Serial.println("Retrying MQTT connection in 5 seconds...");
391  _mqtt->disconnect();
392  delay(5000); // wait 5 seconds
393  retries--;
394  if (retries == 0)
395  {
396  // Enter error state
397  return false;
398  }
399  }
400  Serial.println("MQTT Connected!");
401  return true;
402 }
void showWiFiStatus(int i)
Utility function Display WiFi status in clear text.
Definition: hhsUtility.cpp:312
boolean isNumeric(String str)
Utility function Checks if a string is numeric. Original code found here: http://tripsintech....
Definition: hhsUtility.cpp:105
int getBootDevice(void)
Utility function See https://www.sigmdel.ca/michel/program/esp8266/arduino/watchdogs2_en....
Definition: hhsUtility.cpp:256
void lwdtFeedInit(void)
Utility function Initializes the loop watchdog interrupt routine. To be used in setup() at the end.
Definition: hhsUtility.cpp:244
void printFloat(float value, int places)
Utility function: Prints value with places of decimal places determine by precision.
Definition: hhsUtility.cpp:39
bool doWifiConnect(char *_ssid, char *_password)
Utility function Tries to reconnect the WiFi connection Software found here: https://github....
Definition: hhsUtility.cpp:346
void ICACHE_RAM_ATTR lwdtcb(void)
Utility function lwdTicker callback routine Code found here: https://www.sigmdel.ca/michel/program/es...
Definition: hhsUtility.cpp:226
String formatBytes(size_t bytes)
Utility function Original code found here: https://tttapa.github.io/ESP8266/Chap16%20-%20Data%20Loggi...
Definition: hhsUtility.cpp:20
unsigned long lwdTime
Definition: hhsUtility.cpp:16
unsigned long lwdTimeout
Definition: hhsUtility.cpp:17
int MQTT_connect(Adafruit_MQTT_Client *_mqtt)
Utility function Function to connect and reconnect as necessary to the MQTT server.
Definition: hhsUtility.cpp:373
void keypressWait(void)
Utility function Halt the program and wait for "key press" at the serial port. For DEBUG purpose only...
Definition: hhsUtility.cpp:219
#define LWD_TIMEOUT
Definition: hhsUtility.cpp:12
void lwdtFeed(void)
Utility function Resets the loop watchdog counter also known as "kicking the watchdog".
Definition: hhsUtility.cpp:250
#define DEBUG
Definition: hhsUtility.cpp:11
int errorState(int state, int ledRed, int ledGreen)
Utility function Visual error indication via LED at pin D2 This is a dead end. You will need to fix t...
Definition: hhsUtility.cpp:122
int startWiFi(IPAddress _ip, IPAddress _dns, IPAddress _gateway, IPAddress _subnet, char *_ssid, char *_password, char *_host)
Utility function Starts everything related to WiFi and Internet connections.
Definition: hhsUtility.cpp:269
Ticker lwdTicker
Definition: hhsUtility.cpp:15