2 Commits

Author SHA1 Message Date
  Thomas Buck 2efc8917a9 add ArduinoOTA to ESP32 builds. although neither it nor the old SimpleUpdater work on the Heltec Lora32 devices. TODO. 2 months ago
  Thomas Buck 8174d78158 add checksum and xor to lora payload 2 months ago
9 changed files with 184 additions and 104 deletions
  1. 6
    5
      include/SimpleUpdater.h
  2. 4
    0
      include/config.h
  3. 6
    0
      include/lora.h
  4. 3
    0
      platformio.ini
  5. 43
    0
      src/SimpleUpdater.cpp
  6. 10
    1
      src/influx.cpp
  7. 102
    97
      src/lora.cpp
  8. 8
    0
      src/main.cpp
  9. 2
    1
      src/servers.cpp

+ 6
- 5
include/SimpleUpdater.h View File

29
 public:
29
 public:
30
     SimpleUpdater(String _uri = String("/update"));
30
     SimpleUpdater(String _uri = String("/update"));
31
     void setup(UPDATE_WEB_SERVER *_server);
31
     void setup(UPDATE_WEB_SERVER *_server);
32
-    
32
+    void run(void);
33
+
33
 private:
34
 private:
34
 
35
 
35
 #if defined(ARDUINO_ARCH_ESP8266)
36
 #if defined(ARDUINO_ARCH_ESP8266)
36
-    
37
+
37
     ESP8266HTTPUpdateServer updateServer;
38
     ESP8266HTTPUpdateServer updateServer;
38
 
39
 
39
 #elif defined(ARDUINO_ARCH_ESP32)
40
 #elif defined(ARDUINO_ARCH_ESP32)
40
-    
41
+
41
     void get(void);
42
     void get(void);
42
     void postResult(void);
43
     void postResult(void);
43
     void postUpload(void);
44
     void postUpload(void);
44
-    
45
+
45
 #endif
46
 #endif
46
-    
47
+
47
     String uri;
48
     String uri;
48
     UPDATE_WEB_SERVER *server;
49
     UPDATE_WEB_SERVER *server;
49
 };
50
 };

+ 4
- 0
include/config.h View File

42
 #define INFLUXDB_DATABASE "roomsensorsdiy"
42
 #define INFLUXDB_DATABASE "roomsensorsdiy"
43
 //#define INFLUX_MAX_ERRORS_RESET 10
43
 //#define INFLUX_MAX_ERRORS_RESET 10
44
 
44
 
45
+// LoRa SML Bridge "Crypto"
46
+// needs to be sizeof(struct lora_sml_msg) bytes long
47
+#define LORA_XOR_KEY "_SUPER_SECRET_KEY_HERE_"
48
+
45
 // all given in milliseconds
49
 // all given in milliseconds
46
 #define SERVER_HANDLE_INTERVAL 10
50
 #define SERVER_HANDLE_INTERVAL 10
47
 #define SENSOR_HANDLE_INTERVAL (5 * 1000)
51
 #define SENSOR_HANDLE_INTERVAL (5 * 1000)

+ 6
- 0
include/lora.h View File

36
     LORA_SML_NUM_MESSAGES
36
     LORA_SML_NUM_MESSAGES
37
 };
37
 };
38
 
38
 
39
+struct lora_sml_msg {
40
+    uint8_t type; // enum lora_sml_type
41
+    double value;
42
+    uint32_t checksum;
43
+} __attribute__ ((packed));
44
+
39
 #ifdef FEATURE_SML
45
 #ifdef FEATURE_SML
40
 void lora_sml_send(enum lora_sml_type msg, double value, unsigned long counter);
46
 void lora_sml_send(enum lora_sml_type msg, double value, unsigned long counter);
41
 #endif // FEATURE_SML
47
 #endif // FEATURE_SML

+ 3
- 0
platformio.ini View File

67
 framework = arduino
67
 framework = arduino
68
 upload_protocol = esptool
68
 upload_protocol = esptool
69
 upload_port = /dev/ttyUSB2
69
 upload_port = /dev/ttyUSB2
70
+# TODO neither web ota nor arduino ota work on heltec esp32?!
71
+#upload_protocol = espota
72
+#upload_port = lora-testing
70
 monitor_port = /dev/ttyUSB2
73
 monitor_port = /dev/ttyUSB2
71
 monitor_speed = 115200
74
 monitor_speed = 115200
72
 extra_scripts = pre:extra_script.py
75
 extra_scripts = pre:extra_script.py

+ 43
- 0
src/SimpleUpdater.cpp View File

15
 #include <ESP8266HTTPUpdateServer.h>
15
 #include <ESP8266HTTPUpdateServer.h>
16
 #elif defined(ARDUINO_ARCH_ESP32)
16
 #elif defined(ARDUINO_ARCH_ESP32)
17
 #include <Update.h>
17
 #include <Update.h>
18
+#include <ArduinoOTA.h>
18
 #endif
19
 #endif
19
 
20
 
20
 #include "config.h"
21
 #include "config.h"
148
         get();
149
         get();
149
     });
150
     });
150
 
151
 
152
+    ArduinoOTA.setMdnsEnabled(false);
153
+
154
+    ArduinoOTA.onStart([]() {
155
+        String type;
156
+        if (ArduinoOTA.getCommand() == U_FLASH) {
157
+            type = "sketch";
158
+        } else {  // U_SPIFFS
159
+            type = "filesystem";
160
+        }
161
+
162
+        // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
163
+        Serial.println("Start updating " + type);
164
+    })
165
+    .onEnd([]() {
166
+        Serial.println("\nEnd");
167
+    })
168
+    .onProgress([](unsigned int progress, unsigned int total) {
169
+        Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
170
+    })
171
+    .onError([](ota_error_t error) {
172
+        Serial.printf("Error[%u]: ", error);
173
+        if (error == OTA_AUTH_ERROR) {
174
+            Serial.println("Auth Failed");
175
+        } else if (error == OTA_BEGIN_ERROR) {
176
+            Serial.println("Begin Failed");
177
+        } else if (error == OTA_CONNECT_ERROR) {
178
+            Serial.println("Connect Failed");
179
+        } else if (error == OTA_RECEIVE_ERROR) {
180
+            Serial.println("Receive Failed");
181
+        } else if (error == OTA_END_ERROR) {
182
+            Serial.println("End Failed");
183
+        }
184
+    });
185
+
186
+    ArduinoOTA.begin();
187
+
151
 #endif
188
 #endif
152
 }
189
 }
153
 
190
 
156
     server = NULL;
193
     server = NULL;
157
 }
194
 }
158
 
195
 
196
+void SimpleUpdater::run(void) {
197
+#ifdef ARDUINO_ARCH_ESP32
198
+    ArduinoOTA.handle();
199
+#endif
200
+}
201
+
159
 #endif
202
 #endif

+ 10
- 1
src/influx.cpp View File

118
 
118
 
119
     ms.addValue(key, value);
119
     ms.addValue(key, value);
120
 
120
 
121
-    debug.printf("Writing %s %s %s %s %.2lf\n", measurement.c_str(), sensor.c_str(), placement.c_str(), key.c_str(), value);
121
+    debug.print("Writing ");
122
+    debug.print(measurement);
123
+    debug.print(" ");
124
+    debug.print(sensor);
125
+    debug.print(" ");
126
+    debug.print(placement);
127
+    debug.print(" ");
128
+    debug.print(key);
129
+    debug.print(" ");
130
+    debug.printf("%.2lf\n", value);
122
     writeMeasurement(ms);
131
     writeMeasurement(ms);
123
     debug.println(F("Done!"));
132
     debug.println(F("Done!"));
124
 }
133
 }

+ 102
- 97
src/lora.cpp View File

25
 #include "influx.h"
25
 #include "influx.h"
26
 #include "lora.h"
26
 #include "lora.h"
27
 
27
 
28
-// define LORA_TEST_TX to periodically transmit a test message
29
-//#define LORA_TEST_TX
30
-
31
 //#define DEBUG_LORA_RX_HEXDUMP
28
 //#define DEBUG_LORA_RX_HEXDUMP
32
 
29
 
33
 #ifdef FEATURE_SML
30
 #ifdef FEATURE_SML
38
 #define LORA_LED_BRIGHTNESS 25 // in percent, 50% brightness is plenty for this LED
35
 #define LORA_LED_BRIGHTNESS 25 // in percent, 50% brightness is plenty for this LED
39
 #endif // FEATURE_SML
36
 #endif // FEATURE_SML
40
 
37
 
41
-#ifdef LORA_TEST_TX
42
-// Pause between transmited packets in seconds.
43
-// Set to zero to only transmit a packet when pressing the user button
44
-// Will not exceed 1% duty cycle, even if you set a lower value.
45
-#define PAUSE               10
46
-#endif // LORA_TEST_TX
47
-
48
 // Frequency in MHz. Keep the decimal point to designate float.
38
 // Frequency in MHz. Keep the decimal point to designate float.
49
 // Check your own rules and regulations to see what is legal where you are.
39
 // Check your own rules and regulations to see what is legal where you are.
50
 #define FREQUENCY           866.3       // for Europe
40
 #define FREQUENCY           866.3       // for Europe
100
 
90
 
101
 #endif // FEATURE_SML
91
 #endif // FEATURE_SML
102
 
92
 
103
-#ifdef LORA_TEST_TX
104
-static unsigned long test_counter = 0;
105
-#endif // LORA_TEST_TX
106
-
107
 void lora_oled_init(void) {
93
 void lora_oled_init(void) {
108
     heltec_setup();
94
     heltec_setup();
109
 }
95
 }
126
     return *((double *)data);
112
     return *((double *)data);
127
 }
113
 }
128
 
114
 
115
+// adapted from "Hacker's Delight"
116
+static uint32_t calc_checksum(const uint8_t *data, size_t len) {
117
+    uint32_t c = 0xFFFFFFFF;
118
+    for (size_t i = 0; i < len; i++) {
119
+        c ^= data[i];
120
+        for (size_t j = 0; j < 8; j++) {
121
+            uint32_t mask = -(c & 1);
122
+            c = (c >> 1) ^ (0xEDB88320 & mask);
123
+        }
124
+    }
125
+
126
+    return ~c;
127
+}
128
+
129
 static void lora_rx(void) {
129
 static void lora_rx(void) {
130
     rx_flag = true;
130
     rx_flag = true;
131
 }
131
 }
132
 
132
 
133
-static bool lora_tx(uint8_t *data, size_t len) {
133
+static bool lora_tx(enum lora_sml_type type, double value) {
134
     bool tx_legal = millis() > (last_tx + minimum_pause);
134
     bool tx_legal = millis() > (last_tx + minimum_pause);
135
     if (!tx_legal) {
135
     if (!tx_legal) {
136
         //debug.printf("Legal limit, wait %i sec.\n", (int)((minimum_pause - (millis() - last_tx)) / 1000) + 1);
136
         //debug.printf("Legal limit, wait %i sec.\n", (int)((minimum_pause - (millis() - last_tx)) / 1000) + 1);
137
         return false;
137
         return false;
138
     }
138
     }
139
 
139
 
140
+    struct lora_sml_msg msg;
141
+    msg.type = type;
142
+    msg.value = value;
143
+    msg.checksum = calc_checksum((uint8_t *)&msg, offsetof(struct lora_sml_msg, checksum));
144
+
145
+    uint8_t *data = (uint8_t *)&msg;
146
+    const size_t len = sizeof(struct lora_sml_msg);
147
+
148
+#ifdef LORA_XOR_KEY
149
+    for (size_t i = 0; i < len; i++) {
150
+        data[i] ^= LORA_XOR_KEY[i];
151
+    }
152
+#endif
153
+
140
     debug.printf("TX [%d] (%lu) ", data[0], len);
154
     debug.printf("TX [%d] (%lu) ", data[0], len);
141
     radio.clearDio1Action();
155
     radio.clearDio1Action();
142
 
156
 
174
 
188
 
175
 #ifdef FEATURE_SML
189
 #ifdef FEATURE_SML
176
 static bool lora_sml_cache_send(enum lora_sml_type msg) {
190
 static bool lora_sml_cache_send(enum lora_sml_type msg) {
177
-    const size_t len = sizeof(double) + 1;
178
-    uint8_t data[len];
179
-    data[0] = (uint8_t)msg;
180
-    memcpy(data + 1, &cache[msg].value, sizeof(double));
181
-    return lora_tx(data, len);
191
+    return lora_tx(msg, cache[msg].value);
182
 }
192
 }
183
 
193
 
184
 static void lora_sml_handle_cache(void) {
194
 static void lora_sml_handle_cache(void) {
313
         rx_flag = false;
323
         rx_flag = false;
314
 
324
 
315
         bool success = true;
325
         bool success = true;
316
-        uint8_t data[sizeof(double) + 1];
326
+        uint8_t data[sizeof(struct lora_sml_msg)];
317
         RADIOLIB_CHECK(radio.readData(data, sizeof(data)));
327
         RADIOLIB_CHECK(radio.readData(data, sizeof(data)));
318
         if (success) {
328
         if (success) {
329
+#ifdef LORA_XOR_KEY
330
+            for (size_t i = 0; i < sizeof(data); i++) {
331
+                data[i] ^= LORA_XOR_KEY[i];
332
+            }
333
+#endif
334
+
319
             debug.printf("RX [%i]\n", data[0]);
335
             debug.printf("RX [%i]\n", data[0]);
320
             debug.printf("  RSSI: %.2f dBm\n", radio.getRSSI());
336
             debug.printf("  RSSI: %.2f dBm\n", radio.getRSSI());
321
             debug.printf("  SNR: %.2f dB\n", radio.getSNR());
337
             debug.printf("  SNR: %.2f dB\n", radio.getSNR());
322
 
338
 
323
 #if defined(DEBUG_LORA_RX_HEXDUMP) || (!defined(ENABLE_INFLUXDB_LOGGING))
339
 #if defined(DEBUG_LORA_RX_HEXDUMP) || (!defined(ENABLE_INFLUXDB_LOGGING))
324
             for (int i = 0; i < sizeof(data); i++) {
340
             for (int i = 0; i < sizeof(data); i++) {
325
-                debug.printf("%02X", data[i]);
341
+                debug.printf("  %02X", data[i]);
326
                 if (i < (sizeof(data) - 1)) {
342
                 if (i < (sizeof(data) - 1)) {
327
                     debug.print(" ");
343
                     debug.print(" ");
328
                 } else {
344
                 } else {
331
             }
347
             }
332
 #endif
348
 #endif
333
 
349
 
334
-#ifdef ENABLE_INFLUXDB_LOGGING
335
-            if (data[0] == LORA_SML_BAT_V) {
336
-                float vbat = NAN;
337
-                int percent = -1;
338
-                memcpy(&vbat, data + 1, sizeof(float));
339
-                memcpy(&percent, data + 1 + sizeof(float), sizeof(int));
340
-                debug.printf("  Vbat: %.2f (%d%%)\n", vbat, percent);
341
-
342
-                writeSensorDatum("environment", "sml", SENSOR_LOCATION, "vbat", vbat);
343
-                writeSensorDatum("environment", "sml", SENSOR_LOCATION, "percent", percent);
350
+            struct lora_sml_msg *msg = (struct lora_sml_msg *)data;
351
+            uint32_t checksum = calc_checksum(data, offsetof(struct lora_sml_msg, checksum));
352
+            if (checksum != msg->checksum) {
353
+                debug.printf("  CRC: 0x%08X != 0x%08X\n", msg->checksum, checksum);
344
             } else {
354
             } else {
345
-                double val = NAN;
346
-                memcpy(&val, data + 1, sizeof(double));
347
-                debug.printf("  Value: %.2f\n", val);
348
-
349
-                String key;
350
-                switch (data[0]) {
351
-                    case LORA_SML_HELLO:
352
-                        key = "hello";
353
-                        break;
354
-
355
-                    case LORA_SML_SUM_WH:
356
-                        key = "Sum_Wh";
357
-                        break;
358
-
359
-                    case LORA_SML_T1_WH:
360
-                        key = "T1_Wh";
361
-                        break;
362
-
363
-                    case LORA_SML_T2_WH:
364
-                        key = "T2_Wh";
365
-                        break;
366
-
367
-                    case LORA_SML_SUM_W:
368
-                        key = "Sum_W";
369
-                        break;
370
-
371
-                    case LORA_SML_L1_W:
372
-                        key = "L1_W";
373
-                        break;
374
-
375
-                    case LORA_SML_L2_W:
376
-                        key = "L2_W";
377
-                        break;
378
-
379
-                    case LORA_SML_L3_W:
380
-                        key = "L3_W";
381
-                        break;
382
-
383
-                    default:
384
-                        key = "unknown";
385
-                        break;
386
-                }
355
+                debug.printf("  CRC: OK 0x%08X\n", checksum);
387
 
356
 
388
-                writeSensorDatum("environment", "sml", SENSOR_LOCATION, key, val);
389
-            }
357
+#ifdef ENABLE_INFLUXDB_LOGGING
358
+                if (data[0] == LORA_SML_BAT_V) {
359
+                    // extract mangled float and int from double
360
+                    float vbat = NAN;
361
+                    int percent = -1;
362
+                    memcpy(&vbat, data + offsetof(struct lora_sml_msg, value), sizeof(float));
363
+                    memcpy(&percent, data + offsetof(struct lora_sml_msg, value) + sizeof(float), sizeof(int));
364
+                    debug.printf("  Vbat: %.2f (%d%%)\n", vbat, percent);
365
+
366
+                    writeSensorDatum("environment", "sml", SENSOR_LOCATION, "vbat", vbat);
367
+                    writeSensorDatum("environment", "sml", SENSOR_LOCATION, "percent", percent);
368
+                } else {
369
+                    debug.printf("  Value: %.2f\n", msg->value);
370
+
371
+                    String key;
372
+                    switch (data[0]) {
373
+                        case LORA_SML_HELLO:
374
+                            key = "hello";
375
+                            break;
376
+
377
+                        case LORA_SML_SUM_WH:
378
+                            key = "Sum_Wh";
379
+                            break;
380
+
381
+                        case LORA_SML_T1_WH:
382
+                            key = "T1_Wh";
383
+                            break;
384
+
385
+                        case LORA_SML_T2_WH:
386
+                            key = "T2_Wh";
387
+                            break;
388
+
389
+                        case LORA_SML_SUM_W:
390
+                            key = "Sum_W";
391
+                            break;
392
+
393
+                        case LORA_SML_L1_W:
394
+                            key = "L1_W";
395
+                            break;
396
+
397
+                        case LORA_SML_L2_W:
398
+                            key = "L2_W";
399
+                            break;
400
+
401
+                        case LORA_SML_L3_W:
402
+                            key = "L3_W";
403
+                            break;
404
+
405
+                        default:
406
+                            key = "unknown";
407
+                            break;
408
+                    }
409
+
410
+                    writeSensorDatum("environment", "sml", SENSOR_LOCATION, key, msg->value);
411
+                }
390
 #endif // ENABLE_INFLUXDB_LOGGING
412
 #endif // ENABLE_INFLUXDB_LOGGING
413
+            }
391
         }
414
         }
392
 
415
 
393
         success = true;
416
         success = true;
402
     lora_sml_handle_cache();
425
     lora_sml_handle_cache();
403
 #endif // FEATURE_SML
426
 #endif // FEATURE_SML
404
 
427
 
405
-    bool tx_legal = millis() > last_tx + minimum_pause;
406
-
407
-#ifdef LORA_TEST_TX
408
-    // Transmit a packet every PAUSE seconds or when the button is pressed
409
-    if ((PAUSE && tx_legal && millis() - last_tx > (PAUSE * 1000)) || button.isSingleClick()) {
410
-        // In case of button click, tell user to wait
411
-        if (!tx_legal) {
412
-            debug.printf("Legal limit, wait %i sec.\n", (int)((minimum_pause - (millis() - last_tx)) / 1000) + 1);
413
-            return;
414
-        }
415
-
416
-        String s = String(test_counter++);
417
-        lora_tx(s.c_str(), s.length());
418
-    }
419
-#else // LORA_TEST_TX
420
     if (button.isSingleClick()) {
428
     if (button.isSingleClick()) {
421
         // In case of button click, tell user to wait
429
         // In case of button click, tell user to wait
430
+        bool tx_legal = millis() > last_tx + minimum_pause;
422
         if (!tx_legal) {
431
         if (!tx_legal) {
423
             debug.printf("Legal limit, wait %i sec.\n", (int)((minimum_pause - (millis() - last_tx)) / 1000) + 1);
432
             debug.printf("Legal limit, wait %i sec.\n", (int)((minimum_pause - (millis() - last_tx)) / 1000) + 1);
424
             return;
433
             return;
425
         }
434
         }
426
 
435
 
436
+        // send test hello message on lorarx target, or battery state on loratx target
427
 #ifdef FEATURE_SML
437
 #ifdef FEATURE_SML
428
         lora_sml_send(LORA_SML_BAT_V, lora_get_mangled_bat(), 0);
438
         lora_sml_send(LORA_SML_BAT_V, lora_get_mangled_bat(), 0);
429
 #else // FEATURE_SML
439
 #else // FEATURE_SML
430
-        uint8_t data[sizeof(double) + 1];
431
-        data[0] = LORA_SML_HELLO;
432
-        double tmp = -23.42;
433
-        memcpy(data + 1, &tmp, sizeof(double));
434
-        lora_tx(data, sizeof(data));
440
+        lora_tx(LORA_SML_HELLO, -23.42);
435
 #endif // FEATURE_SML
441
 #endif // FEATURE_SML
436
     }
442
     }
437
-#endif // LORA_TEST_TX
438
 }
443
 }
439
 
444
 
440
 #endif // FEATURE_LORA
445
 #endif // FEATURE_LORA

+ 8
- 0
src/main.cpp View File

133
 #endif // FEATURE_UI
133
 #endif // FEATURE_UI
134
     }
134
     }
135
     debug.println(F("\nWiFi connected!"));
135
     debug.println(F("\nWiFi connected!"));
136
+
137
+    debug.printf("IP: %s\n", WiFi.localIP().toString().c_str());
138
+    debug.printf("Hostname: %s\n", hostname.c_str());
139
+
136
 #ifdef FEATURE_UI
140
 #ifdef FEATURE_UI
137
     ui_progress(UI_WIFI_CONNECTED);
141
     ui_progress(UI_WIFI_CONNECTED);
138
 #endif // FEATURE_UI
142
 #endif // FEATURE_UI
183
 #endif // FEATURE_UI
187
 #endif // FEATURE_UI
184
     }
188
     }
185
     debug.println(F("\nWiFi connected!"));
189
     debug.println(F("\nWiFi connected!"));
190
+
191
+    debug.printf("IP: %s\n", WiFi.localIP().toString().c_str());
192
+    debug.printf("Hostname: %s\n", hostname.c_str());
193
+
186
 #ifdef FEATURE_UI
194
 #ifdef FEATURE_UI
187
     ui_progress(UI_WIFI_CONNECTED);
195
     ui_progress(UI_WIFI_CONNECTED);
188
 #endif // FEATURE_UI
196
 #endif // FEATURE_UI

+ 2
- 1
src/servers.cpp View File

207
 static void handleServers() {
207
 static void handleServers() {
208
 #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
208
 #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
209
     server.handleClient();
209
     server.handleClient();
210
+    updater.run();
210
 #else
211
 #else
211
     http_server();
212
     http_server();
212
 #endif
213
 #endif
213
-    
214
+
214
 #if defined(ARDUINO_ARCH_ESP8266)
215
 #if defined(ARDUINO_ARCH_ESP8266)
215
     MDNS.update();
216
     MDNS.update();
216
 #endif
217
 #endif

Loading…
Cancel
Save