2 コミット

作成者 SHA1 メッセージ 日付
  Thomas Buck 2efc8917a9 add ArduinoOTA to ESP32 builds. although neither it nor the old SimpleUpdater work on the Heltec Lora32 devices. TODO. 2ヶ月前
  Thomas Buck 8174d78158 add checksum and xor to lora payload 2ヶ月前
9個のファイルの変更184行の追加104行の削除
  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 ファイルの表示

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

+ 4
- 0
include/config.h ファイルの表示

@@ -42,6 +42,10 @@
42 42
 #define INFLUXDB_DATABASE "roomsensorsdiy"
43 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 49
 // all given in milliseconds
46 50
 #define SERVER_HANDLE_INTERVAL 10
47 51
 #define SENSOR_HANDLE_INTERVAL (5 * 1000)

+ 6
- 0
include/lora.h ファイルの表示

@@ -36,6 +36,12 @@ enum lora_sml_type {
36 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 45
 #ifdef FEATURE_SML
40 46
 void lora_sml_send(enum lora_sml_type msg, double value, unsigned long counter);
41 47
 #endif // FEATURE_SML

+ 3
- 0
platformio.ini ファイルの表示

@@ -67,6 +67,9 @@ board = heltec_wifi_lora_32_V3
67 67
 framework = arduino
68 68
 upload_protocol = esptool
69 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 73
 monitor_port = /dev/ttyUSB2
71 74
 monitor_speed = 115200
72 75
 extra_scripts = pre:extra_script.py

+ 43
- 0
src/SimpleUpdater.cpp ファイルの表示

@@ -15,6 +15,7 @@
15 15
 #include <ESP8266HTTPUpdateServer.h>
16 16
 #elif defined(ARDUINO_ARCH_ESP32)
17 17
 #include <Update.h>
18
+#include <ArduinoOTA.h>
18 19
 #endif
19 20
 
20 21
 #include "config.h"
@@ -148,6 +149,42 @@ void SimpleUpdater::setup(UPDATE_WEB_SERVER *_server) {
148 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 188
 #endif
152 189
 }
153 190
 
@@ -156,4 +193,10 @@ SimpleUpdater::SimpleUpdater(String _uri) {
156 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 202
 #endif

+ 10
- 1
src/influx.cpp ファイルの表示

@@ -118,7 +118,16 @@ void writeSensorDatum(String measurement, String sensor, String placement, Strin
118 118
 
119 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 131
     writeMeasurement(ms);
123 132
     debug.println(F("Done!"));
124 133
 }

+ 102
- 97
src/lora.cpp ファイルの表示

@@ -25,9 +25,6 @@
25 25
 #include "influx.h"
26 26
 #include "lora.h"
27 27
 
28
-// define LORA_TEST_TX to periodically transmit a test message
29
-//#define LORA_TEST_TX
30
-
31 28
 //#define DEBUG_LORA_RX_HEXDUMP
32 29
 
33 30
 #ifdef FEATURE_SML
@@ -38,13 +35,6 @@
38 35
 #define LORA_LED_BRIGHTNESS 25 // in percent, 50% brightness is plenty for this LED
39 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 38
 // Frequency in MHz. Keep the decimal point to designate float.
49 39
 // Check your own rules and regulations to see what is legal where you are.
50 40
 #define FREQUENCY           866.3       // for Europe
@@ -100,10 +90,6 @@ static struct sml_cache cache[LORA_SML_NUM_MESSAGES];
100 90
 
101 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 93
 void lora_oled_init(void) {
108 94
     heltec_setup();
109 95
 }
@@ -126,17 +112,45 @@ double lora_get_mangled_bat(void) {
126 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 129
 static void lora_rx(void) {
130 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 134
     bool tx_legal = millis() > (last_tx + minimum_pause);
135 135
     if (!tx_legal) {
136 136
         //debug.printf("Legal limit, wait %i sec.\n", (int)((minimum_pause - (millis() - last_tx)) / 1000) + 1);
137 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 154
     debug.printf("TX [%d] (%lu) ", data[0], len);
141 155
     radio.clearDio1Action();
142 156
 
@@ -174,11 +188,7 @@ static bool lora_tx(uint8_t *data, size_t len) {
174 188
 
175 189
 #ifdef FEATURE_SML
176 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 194
 static void lora_sml_handle_cache(void) {
@@ -313,16 +323,22 @@ void lora_run(void) {
313 323
         rx_flag = false;
314 324
 
315 325
         bool success = true;
316
-        uint8_t data[sizeof(double) + 1];
326
+        uint8_t data[sizeof(struct lora_sml_msg)];
317 327
         RADIOLIB_CHECK(radio.readData(data, sizeof(data)));
318 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 335
             debug.printf("RX [%i]\n", data[0]);
320 336
             debug.printf("  RSSI: %.2f dBm\n", radio.getRSSI());
321 337
             debug.printf("  SNR: %.2f dB\n", radio.getSNR());
322 338
 
323 339
 #if defined(DEBUG_LORA_RX_HEXDUMP) || (!defined(ENABLE_INFLUXDB_LOGGING))
324 340
             for (int i = 0; i < sizeof(data); i++) {
325
-                debug.printf("%02X", data[i]);
341
+                debug.printf("  %02X", data[i]);
326 342
                 if (i < (sizeof(data) - 1)) {
327 343
                     debug.print(" ");
328 344
                 } else {
@@ -331,63 +347,70 @@ void lora_run(void) {
331 347
             }
332 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 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 412
 #endif // ENABLE_INFLUXDB_LOGGING
413
+            }
391 414
         }
392 415
 
393 416
         success = true;
@@ -402,39 +425,21 @@ void lora_run(void) {
402 425
     lora_sml_handle_cache();
403 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 428
     if (button.isSingleClick()) {
421 429
         // In case of button click, tell user to wait
430
+        bool tx_legal = millis() > last_tx + minimum_pause;
422 431
         if (!tx_legal) {
423 432
             debug.printf("Legal limit, wait %i sec.\n", (int)((minimum_pause - (millis() - last_tx)) / 1000) + 1);
424 433
             return;
425 434
         }
426 435
 
436
+        // send test hello message on lorarx target, or battery state on loratx target
427 437
 #ifdef FEATURE_SML
428 438
         lora_sml_send(LORA_SML_BAT_V, lora_get_mangled_bat(), 0);
429 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 441
 #endif // FEATURE_SML
436 442
     }
437
-#endif // LORA_TEST_TX
438 443
 }
439 444
 
440 445
 #endif // FEATURE_LORA

+ 8
- 0
src/main.cpp ファイルの表示

@@ -133,6 +133,10 @@ void setup() {
133 133
 #endif // FEATURE_UI
134 134
     }
135 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 140
 #ifdef FEATURE_UI
137 141
     ui_progress(UI_WIFI_CONNECTED);
138 142
 #endif // FEATURE_UI
@@ -183,6 +187,10 @@ void setup() {
183 187
 #endif // FEATURE_UI
184 188
     }
185 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 194
 #ifdef FEATURE_UI
187 195
     ui_progress(UI_WIFI_CONNECTED);
188 196
 #endif // FEATURE_UI

+ 2
- 1
src/servers.cpp ファイルの表示

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

読み込み中…
キャンセル
保存