Merge branch 'master' of https://github.com/cyberman54/ESP32-Paxcounter
This commit is contained in:
commit
b2931c148d
21
README.md
21
README.md
@ -13,6 +13,8 @@ Tutorial (in german language): https://www.heise.de/select/make/2019/1/155109923
|
||||
<img src="img/TTGO-curves.jpg">
|
||||
<img src="img/Paxcounter-LEDmatrix.jpg">
|
||||
<img src="img/Paxcounter-Clock.png">
|
||||
<img src="img/Paxcounter-ttgo-twristband.jpg">
|
||||
|
||||
|
||||
# Use case
|
||||
|
||||
@ -47,9 +49,13 @@ LoLin32lite + [LoraNode32-Lite shield](https://github.com/hallard/LoLin32-Lite-L
|
||||
- WeMos: LoLin32, LoLin32 Lite, WeMos D32, [Wemos32 Oled](https://www.instructables.com/id/ESP32-With-Integrated-OLED-WEMOSLolin-Getting-Star/)
|
||||
- Crowdsupply: [TinyPICO](https://www.crowdsupply.com/unexpected-maker/tinypico)
|
||||
- TTGO: [T-Display](https://www.aliexpress.com/item/33048962331.html)
|
||||
- TTGO: [T-Wristband](https://www.aliexpress.com/item/4000527495064.html)
|
||||
- Generic ESP32
|
||||
|
||||
Depending on board hardware following features are supported:
|
||||
- LoRaWAN communication, supporting various payload formats (see enclosed .js converters)
|
||||
- MQTT communication via TCP/IP and Ethernet interface (note: payload transmitted over MQTT will be base64 encoded)
|
||||
- SPI serial communication to a local host
|
||||
- LED (shows power & status)
|
||||
- OLED Display (shows detailed status)
|
||||
- RGB LED (shows colorized status)
|
||||
@ -62,7 +68,6 @@ Depending on board hardware following features are supported:
|
||||
- Switch external power / battery
|
||||
- LED Matrix display (similar to [this 64x16 model](https://www.instructables.com/id/64x16-RED-LED-Marquee/), can be ordered on [Aliexpress](https://www.aliexpress.com/item/P3-75-dot-matrix-led-module-3-75mm-high-clear-top1-for-text-display-304-60mm/32616683948.html))
|
||||
- SD-card (see section SD-card here) for logging pax data
|
||||
- Ethernet interface for MQTT communication via TCP/IP
|
||||
|
||||
Target platform must be selected in `platformio.ini`.<br>
|
||||
Hardware dependent settings (pinout etc.) are stored in board files in /hal directory. If you want to use a ESP32 board which is not yet supported, use hal file generic.h and tailor pin mappings to your needs. Pull requests for new boards welcome.<br>
|
||||
@ -198,7 +203,7 @@ Paxcounter supports a battery friendly power saving mode. In this mode the devic
|
||||
|
||||
# Time sync
|
||||
|
||||
Paxcounter can keep it's time-of-day synced with an external time source. Set *#define TIME_SYNC_INTERVAL* in paxcounter.conf to enable time sync. Supported external time sources are GPS, LORAWAN network time and LORAWAN application timeserver time. An on board DS3231 RTC is kept sycned as fallback time source. Time accuracy depends on board's time base which generates the pulse per second. Supported are GPS PPS, SQW output of RTC, and internal ESP32 hardware timer. Time base is selected by #defines in the board's hal file, see example in [**generic.h**](src/hal/generic.h). Bonus: If your LORAWAN network does not support network time, you can run a Node-Red timeserver application using the enclosed [**Timeserver code**](/src/Timeserver/Nodered-Timeserver.json). Configure MQTT nodes in Node-Red to the same LORAWAN application as paxocunter device is using.
|
||||
Paxcounter can keep it's time-of-day synced with an external time source. Set *#define TIME_SYNC_INTERVAL* in paxcounter.conf to enable time sync. Supported external time sources are GPS, LORAWAN network time and LORAWAN application timeserver time. An on board DS3231 RTC is kept sycned as fallback time source. Time accuracy depends on board's time base which generates the pulse per second. Supported are GPS PPS, SQW output of RTC, and internal ESP32 hardware timer. Time base is selected by #defines in the board's hal file, see example in [**generic.h**](src/hal/generic.h). Bonus: If your LORAWAN network does not support network time, you can run a Node-Red timeserver application using the enclosed [**Timeserver code**](/src/Node-RED/Timeserver.json). Configure MQTT nodes in Node-Red for the LORAWAN application used by paxocunter device.
|
||||
|
||||
# Wall clock controller
|
||||
|
||||
@ -362,9 +367,9 @@ Hereafter described is the default *plain* format, which uses MSB bit numbering.
|
||||
|
||||
# Remote control
|
||||
|
||||
The device listenes for remote control commands on LoRaWAN Port 2. Multiple commands per downlink are possible by concatenating them.
|
||||
The device listenes for remote control commands on LoRaWAN Port 2. Multiple commands per downlink are possible by concatenating them, but must not exceed a maximum of 10 bytes per downlink.
|
||||
|
||||
Note: all settings are stored in NVRAM and will be reloaded when device starts.
|
||||
Note: settings can be stored in NVRAM to make them persistant (reloaded during device startup / restart). To store settings, use command 0x20.
|
||||
|
||||
Send for example `8386` as Downlink on Port 2 to get battery status and time/date from the device.
|
||||
<img src="img/paxcounter_downlink_example.png">
|
||||
@ -523,6 +528,14 @@ Send for example `8386` as Downlink on Port 2 to get battery status and time/dat
|
||||
0 ... 255 device sleep cycle in seconds/2
|
||||
e.g. 120 -> device sleeps 240 seconds after each send cycle [default = 0]
|
||||
|
||||
0x20 store device configuration
|
||||
|
||||
Current device runtime configuration is stored in NVRAM, will be reloaded after restart
|
||||
|
||||
0x21 load device configuration
|
||||
|
||||
Current device runtime configuration will be loaded from NVRAM, replacing current settings immediately (use with care!)
|
||||
|
||||
0x80 get device configuration
|
||||
|
||||
Device answers with it's current configuration on Port 3.
|
||||
|
BIN
img/Paxcounter-ttgo-twristband.jpg
Normal file
BIN
img/Paxcounter-ttgo-twristband.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 229 KiB |
@ -10,6 +10,7 @@
|
||||
#include "display.h"
|
||||
#include "sds011read.h"
|
||||
#include "sdcard.h"
|
||||
#include "macsniff.h"
|
||||
|
||||
extern Ticker cyclicTimer;
|
||||
|
||||
|
@ -22,24 +22,14 @@
|
||||
#define _bitl(b) (1UL << (b))
|
||||
|
||||
// bits in payloadmask for filtering payload data
|
||||
#define COUNT_DATA _bit(1)
|
||||
#define ALARM_DATA _bit(2)
|
||||
#define MEMS_DATA _bit(3)
|
||||
#define GPS_DATA _bit(4)
|
||||
#define SENSOR1_DATA _bit(5)
|
||||
#define SENSOR2_DATA _bit(6)
|
||||
#define SENSOR3_DATA _bit(7)
|
||||
#define BATT_DATA _bit(8)
|
||||
|
||||
// bits in configmask for device runmode control
|
||||
#define GPS_MODE _bit(1)
|
||||
#define ALARM_MODE _bit(2)
|
||||
#define BEACON_MODE _bit(3)
|
||||
#define UPDATE_MODE _bit(4)
|
||||
#define FILTER_MODE _bit(5)
|
||||
#define ANTENNA_MODE _bit(6)
|
||||
#define BLE_MODE _bit(7)
|
||||
#define SCREEN_MODE _bit(8)
|
||||
#define COUNT_DATA _bit(0)
|
||||
#define ALARM_DATA _bit(1)
|
||||
#define MEMS_DATA _bit(2)
|
||||
#define GPS_DATA _bit(3)
|
||||
#define SENSOR1_DATA _bit(4)
|
||||
#define SENSOR2_DATA _bit(5)
|
||||
#define SENSOR3_DATA _bit(6)
|
||||
#define BATT_DATA _bit(7)
|
||||
|
||||
// length of display buffer for lmic event messages
|
||||
#define LMIC_EVENTMSG_LEN 17
|
||||
|
@ -2,8 +2,8 @@
|
||||
#define _HASH_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <inttypes.h>
|
||||
#include <RokkitHash.h>
|
||||
|
||||
uint32_t IRAM_ATTR rokkit(const char *data, int len);
|
||||
uint32_t IRAM_ATTR hash(const char *data, int len);
|
||||
|
||||
#endif
|
@ -24,7 +24,7 @@
|
||||
void i2c_init(void);
|
||||
void i2c_deinit(void);
|
||||
void i2c_scan(void);
|
||||
uint8_t i2c_readBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len);
|
||||
uint8_t i2c_writeBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len);
|
||||
int i2c_readBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len);
|
||||
int i2c_writeBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len);
|
||||
|
||||
#endif
|
@ -1,16 +1,16 @@
|
||||
#ifndef _IRQHANDLER_H
|
||||
#define _IRQHANDLER_H
|
||||
|
||||
#define DISPLAY_IRQ _bitl(1)
|
||||
#define BUTTON_IRQ _bitl(2)
|
||||
#define SENDCYCLE_IRQ _bitl(3)
|
||||
#define CYCLIC_IRQ _bitl(4)
|
||||
#define TIMESYNC_IRQ _bitl(5)
|
||||
#define MASK_IRQ _bitl(6)
|
||||
#define UNMASK_IRQ _bitl(7)
|
||||
#define BME_IRQ _bitl(8)
|
||||
#define MATRIX_DISPLAY_IRQ _bitl(9)
|
||||
#define PMU_IRQ _bitl(10)
|
||||
#define DISPLAY_IRQ _bitl(0)
|
||||
#define BUTTON_IRQ _bitl(1)
|
||||
#define SENDCYCLE_IRQ _bitl(2)
|
||||
#define CYCLIC_IRQ _bitl(3)
|
||||
#define TIMESYNC_IRQ _bitl(4)
|
||||
#define MASK_IRQ _bitl(5)
|
||||
#define UNMASK_IRQ _bitl(6)
|
||||
#define BME_IRQ _bitl(7)
|
||||
#define MATRIX_DISPLAY_IRQ _bitl(8)
|
||||
#define PMU_IRQ _bitl(9)
|
||||
|
||||
#include "globals.h"
|
||||
#include "button.h"
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include "corona.h"
|
||||
#endif
|
||||
|
||||
uint16_t get_salt(void);
|
||||
uint32_t renew_salt(void);
|
||||
uint64_t macConvert(uint8_t *paddr);
|
||||
esp_err_t macQueueInit(void);
|
||||
void mac_process(void *pvParameters);
|
||||
|
@ -5,19 +5,10 @@
|
||||
#include "rcommand.h"
|
||||
#include <MQTT.h>
|
||||
#include <ETH.h>
|
||||
|
||||
#define MQTT_ETHERNET 0 // select PHY: set 0 for Wifi, 1 for ethernet
|
||||
#define MQTT_INTOPIC "paxin"
|
||||
#define MQTT_OUTTOPIC "paxout"
|
||||
#define MQTT_PORT 1883
|
||||
#define MQTT_SERVER "paxcounter.cloud.shiftr.io"
|
||||
#define MQTT_USER "public"
|
||||
#define MQTT_PASSWD "public"
|
||||
#define MQTT_RETRYSEC 20 // retry reconnect every 20 seconds
|
||||
#define MQTT_KEEPALIVE 10 // keep alive interval in seconds
|
||||
#include <mbedtls/base64.h>
|
||||
|
||||
#ifndef MQTT_CLIENTNAME
|
||||
#define MQTT_CLIENTNAME clientId.c_str()
|
||||
#define MQTT_CLIENTNAME clientId
|
||||
#endif
|
||||
|
||||
extern TaskHandle_t mqttTask;
|
||||
@ -27,8 +18,7 @@ uint32_t mqtt_queuewaiting(void);
|
||||
void mqtt_queuereset(void);
|
||||
void mqtt_client_task(void *param);
|
||||
int mqtt_connect(const char *my_host, const uint16_t my_port);
|
||||
void mqtt_callback(MQTTClient *client, char topic[], char payload[],
|
||||
int length);
|
||||
void mqtt_callback(MQTTClient *client, char *topic, char *payload, int length);
|
||||
void NetworkEvent(WiFiEvent_t event);
|
||||
esp_err_t mqtt_init(void);
|
||||
void mqtt_deinit(void);
|
||||
|
@ -15,17 +15,28 @@
|
||||
#include "timesync.h"
|
||||
#include "blescan.h"
|
||||
|
||||
// maximum number of elements in rcommand interpreter queue
|
||||
#define RCMD_QUEUE_SIZE 5
|
||||
|
||||
extern TaskHandle_t rcmdTask;
|
||||
|
||||
// table of remote commands and assigned functions
|
||||
typedef struct {
|
||||
const uint8_t opcode;
|
||||
void (*func)(uint8_t[]);
|
||||
const uint8_t params;
|
||||
const bool store;
|
||||
} cmd_t;
|
||||
|
||||
extern bool rcmd_busy;
|
||||
// Struct for remote command processing queue
|
||||
typedef struct {
|
||||
uint8_t cmd[10];
|
||||
uint8_t cmdLen;
|
||||
} RcmdBuffer_t;
|
||||
|
||||
void rcommand(const uint8_t cmd[], const uint8_t cmdlength);
|
||||
void do_reset(bool warmstart);
|
||||
void IRAM_ATTR rcommand(const uint8_t *cmd, const size_t cmdlength);
|
||||
void rcmd_queuereset(void);
|
||||
uint32_t rcmd_queuewaiting(void);
|
||||
void rcmd_deinit(void);
|
||||
esp_err_t rcmd_init(void);
|
||||
|
||||
#endif
|
||||
|
@ -11,7 +11,8 @@
|
||||
|
||||
void do_reset(bool warmstart);
|
||||
void do_after_reset(void);
|
||||
void enter_deepsleep(const uint64_t wakeup_sec, const gpio_num_t wakeup_gpio);
|
||||
void enter_deepsleep(const uint64_t wakeup_sec = 60,
|
||||
const gpio_num_t wakeup_gpio = GPIO_NUM_MAX);
|
||||
unsigned long long uptime(void);
|
||||
|
||||
#endif // _RESET_H
|
@ -113,16 +113,17 @@ String BintrayClient::getLatestVersion() const
|
||||
ESP_LOGE(TAG, "Error: Firmware version data invalid.");
|
||||
return version;
|
||||
}
|
||||
StaticJsonBuffer<bufferSize> jsonBuffer;
|
||||
StaticJsonDocument<bufferSize> doc;
|
||||
|
||||
DeserializationError err = deserializeJson(doc, jsonResult.c_str());
|
||||
|
||||
JsonObject &root = jsonBuffer.parseObject(jsonResult.c_str());
|
||||
// Check for errors in parsing
|
||||
if (!root.success())
|
||||
if (err)
|
||||
{
|
||||
ESP_LOGE(TAG, "Error: Firmware version data not found.");
|
||||
return version;
|
||||
}
|
||||
return root.get<String>("name");
|
||||
return doc["name"].as<String>();
|
||||
}
|
||||
|
||||
String BintrayClient::getBinaryPath(const String &version) const
|
||||
@ -137,14 +138,15 @@ String BintrayClient::getBinaryPath(const String &version) const
|
||||
ESP_LOGE(TAG, "Error: Firmware download path data invalid.");
|
||||
return path;
|
||||
}
|
||||
StaticJsonBuffer<bufferSize> jsonBuffer;
|
||||
StaticJsonDocument<bufferSize> doc;
|
||||
|
||||
JsonArray &root = jsonBuffer.parseArray(jsonResult.c_str());
|
||||
JsonObject &firstItem = root[0];
|
||||
if (!root.success())
|
||||
DeserializationError err = deserializeJson(doc, jsonResult.c_str());
|
||||
|
||||
JsonObject firstItem = doc[0];
|
||||
if (err)
|
||||
{ //Check for errors in parsing
|
||||
ESP_LOGE(TAG, "Error: Firmware download path not found.");
|
||||
return path;
|
||||
}
|
||||
return "/" + getUser() + "/" + getRepository() + "/" + firstItem.get<String>("path");
|
||||
return "/" + getUser() + "/" + getRepository() + "/" + firstItem["path"].as<String>();
|
||||
}
|
||||
|
Binary file not shown.
@ -21,6 +21,7 @@
|
||||
;halfile = ttgobeam.h
|
||||
halfile = ttgobeam10.h
|
||||
;halfile = ttgotdisplay.h
|
||||
;halfile = ttgotwristband.h
|
||||
;halfile = fipy.h
|
||||
;halfile = lopy.h
|
||||
;halfile = lopy4.h
|
||||
@ -47,7 +48,7 @@ description = Paxcounter is a device for metering passenger flows in realtime. I
|
||||
|
||||
[common]
|
||||
; for release_version use max. 10 chars total, use any decimal format like "a.b.c"
|
||||
release_version = 2.1.0
|
||||
release_version = 2.3.0
|
||||
; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running!
|
||||
; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose
|
||||
debug_level = 3
|
||||
@ -55,7 +56,7 @@ extra_scripts = pre:build.py
|
||||
otakeyfile = ota.conf
|
||||
lorakeyfile = loraconf.h
|
||||
lmicconfigfile = lmic_config.h
|
||||
platform_espressif32 = espressif32@2.1.0
|
||||
platform_espressif32 = espressif32@3.0.0
|
||||
monitor_speed = 115200
|
||||
upload_speed = 115200 ; set by build.py and taken from hal file
|
||||
display_library = ; set by build.py and taken from hal file
|
||||
@ -79,11 +80,13 @@ lib_deps_sensors =
|
||||
boschsensortec/BSEC Software Library @ 1.6.1480
|
||||
https://github.com/ricki-z/SDS011.git
|
||||
lib_deps_basic =
|
||||
bblanchon/ArduinoJson @ <6
|
||||
https://github.com/SukkoPera/Arduino-Rokkit-Hash.git
|
||||
bblanchon/ArduinoJson @ ^6
|
||||
jchristensen/Timezone @ ^1.2.4
|
||||
makuna/RTC @ ^2.3.5
|
||||
spacehuhn/SimpleButton
|
||||
lewisxhe/AXP202X_Library @ ^1.1.2
|
||||
;lewisxhe/AXP202X_Library @ ^1.1.2
|
||||
https://github.com/lewisxhe/AXP202X_Library.git
|
||||
geeksville/esp32-micro-sdcard @ ^0.1.1
|
||||
256dpi/MQTT @ ^2.4.7
|
||||
lib_deps_all =
|
||||
@ -134,4 +137,4 @@ upload_protocol = esptool
|
||||
[env:dev]
|
||||
upload_protocol = esptool
|
||||
build_type = debug
|
||||
platform = https://github.com/platformio/platform-espressif32.git#develop
|
||||
platform = https://github.com/platformio/platform-espressif32.git#develop
|
||||
|
467
src/Node-RED/MQTT.json
Normal file
467
src/Node-RED/MQTT.json
Normal file
@ -0,0 +1,467 @@
|
||||
[
|
||||
{
|
||||
"id": "7bc3eb4f.fe4b64",
|
||||
"type": "mqtt in",
|
||||
"z": "c26229c6.2d1ae8",
|
||||
"name": "Olimex",
|
||||
"topic": "paxout/#",
|
||||
"qos": "2",
|
||||
"datatype": "utf8",
|
||||
"broker": "bd56b04d.db0ff",
|
||||
"x": 190,
|
||||
"y": 160,
|
||||
"wires": [
|
||||
[
|
||||
"d0276db6.83c46"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "4f59740b.296b7c",
|
||||
"type": "debug",
|
||||
"z": "c26229c6.2d1ae8",
|
||||
"name": "data",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
"console": false,
|
||||
"tostatus": false,
|
||||
"complete": "payload",
|
||||
"targetType": "msg",
|
||||
"statusVal": "",
|
||||
"statusType": "auto",
|
||||
"x": 1050,
|
||||
"y": 280,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "f10f8199.25183",
|
||||
"type": "binary",
|
||||
"z": "c26229c6.2d1ae8",
|
||||
"name": "wifi",
|
||||
"property": "payload",
|
||||
"pattern": "l16, x16",
|
||||
"x": 630,
|
||||
"y": 100,
|
||||
"wires": [
|
||||
[
|
||||
"800f5faa.15155"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "df4bdce5.dc219",
|
||||
"type": "switch",
|
||||
"z": "c26229c6.2d1ae8",
|
||||
"name": "Ports",
|
||||
"property": "topic",
|
||||
"propertyType": "msg",
|
||||
"rules": [
|
||||
{
|
||||
"t": "eq",
|
||||
"v": "paxout/1",
|
||||
"vt": "str"
|
||||
},
|
||||
{
|
||||
"t": "eq",
|
||||
"v": "paxout/2",
|
||||
"vt": "str"
|
||||
},
|
||||
{
|
||||
"t": "eq",
|
||||
"v": "paxout/3",
|
||||
"vt": "str"
|
||||
},
|
||||
{
|
||||
"t": "eq",
|
||||
"v": "paxout/4",
|
||||
"vt": "str"
|
||||
},
|
||||
{
|
||||
"t": "eq",
|
||||
"v": "paxout/5",
|
||||
"vt": "str"
|
||||
},
|
||||
{
|
||||
"t": "eq",
|
||||
"v": "paxout/6",
|
||||
"vt": "str"
|
||||
},
|
||||
{
|
||||
"t": "eq",
|
||||
"v": "paxout/7",
|
||||
"vt": "str"
|
||||
},
|
||||
{
|
||||
"t": "eq",
|
||||
"v": "paxout/8",
|
||||
"vt": "str"
|
||||
},
|
||||
{
|
||||
"t": "eq",
|
||||
"v": "paxout/9",
|
||||
"vt": "str"
|
||||
},
|
||||
{
|
||||
"t": "eq",
|
||||
"v": "paxout/10",
|
||||
"vt": "str"
|
||||
},
|
||||
{
|
||||
"t": "eq",
|
||||
"v": "status",
|
||||
"vt": "str"
|
||||
}
|
||||
],
|
||||
"checkall": "true",
|
||||
"repair": false,
|
||||
"outputs": 11,
|
||||
"x": 370,
|
||||
"y": 260,
|
||||
"wires": [
|
||||
[
|
||||
"f10f8199.25183"
|
||||
],
|
||||
[
|
||||
"e2974f79.55d5b"
|
||||
],
|
||||
[
|
||||
"5f6987dd.b89378"
|
||||
],
|
||||
[],
|
||||
[
|
||||
"eaca83c4.5fcaf"
|
||||
],
|
||||
[],
|
||||
[],
|
||||
[
|
||||
"7b6cbc9d.18fe44"
|
||||
],
|
||||
[
|
||||
"d269537.4738fb"
|
||||
],
|
||||
[
|
||||
"409e4762.71ff68"
|
||||
],
|
||||
[
|
||||
"13fbfc5d.40dcc4"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "eaca83c4.5fcaf",
|
||||
"type": "binary",
|
||||
"z": "c26229c6.2d1ae8",
|
||||
"name": "button",
|
||||
"property": "payload",
|
||||
"pattern": "b8 => button",
|
||||
"x": 630,
|
||||
"y": 280,
|
||||
"wires": [
|
||||
[
|
||||
"a6037445.eb8ac8"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "409e4762.71ff68",
|
||||
"type": "binary",
|
||||
"z": "c26229c6.2d1ae8",
|
||||
"name": "cwa",
|
||||
"property": "payload",
|
||||
"pattern": "l16 => cwa",
|
||||
"x": 630,
|
||||
"y": 140,
|
||||
"wires": [
|
||||
[
|
||||
"2966fd1c.0b33d2"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "d0276db6.83c46",
|
||||
"type": "base64",
|
||||
"z": "c26229c6.2d1ae8",
|
||||
"name": "Decode",
|
||||
"action": "",
|
||||
"property": "payload",
|
||||
"x": 200,
|
||||
"y": 260,
|
||||
"wires": [
|
||||
[
|
||||
"df4bdce5.dc219"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "13fbfc5d.40dcc4",
|
||||
"type": "binary",
|
||||
"z": "c26229c6.2d1ae8",
|
||||
"name": "Connection",
|
||||
"property": "payload",
|
||||
"pattern": "b8[19]|str(\"ascii\")",
|
||||
"x": 650,
|
||||
"y": 440,
|
||||
"wires": [
|
||||
[
|
||||
"4f59740b.296b7c"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "800f5faa.15155",
|
||||
"type": "ui_chart",
|
||||
"z": "c26229c6.2d1ae8",
|
||||
"name": "pax",
|
||||
"group": "6838565d.06bf08",
|
||||
"order": 1,
|
||||
"width": 0,
|
||||
"height": 0,
|
||||
"label": "Pax [Wifi]",
|
||||
"chartType": "line",
|
||||
"legend": "false",
|
||||
"xformat": "dd HH:mm",
|
||||
"interpolate": "linear",
|
||||
"nodata": "Noch keine Daten",
|
||||
"dot": false,
|
||||
"ymin": "",
|
||||
"ymax": "",
|
||||
"removeOlder": 1,
|
||||
"removeOlderPoints": "",
|
||||
"removeOlderUnit": "3600",
|
||||
"cutout": 0,
|
||||
"useOneColor": false,
|
||||
"useUTC": false,
|
||||
"colors": [
|
||||
"#1f77b4",
|
||||
"#aec7e8",
|
||||
"#ff7f0e",
|
||||
"#2ca02c",
|
||||
"#98df8a",
|
||||
"#d62728",
|
||||
"#ff9896",
|
||||
"#9467bd",
|
||||
"#c5b0d5"
|
||||
],
|
||||
"outputs": 1,
|
||||
"x": 810,
|
||||
"y": 100,
|
||||
"wires": [
|
||||
[]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2966fd1c.0b33d2",
|
||||
"type": "ui_chart",
|
||||
"z": "c26229c6.2d1ae8",
|
||||
"name": "cwa",
|
||||
"group": "6838565d.06bf08",
|
||||
"order": 1,
|
||||
"width": 0,
|
||||
"height": 0,
|
||||
"label": "CWA",
|
||||
"chartType": "line",
|
||||
"legend": "false",
|
||||
"xformat": "dd HH:mm",
|
||||
"interpolate": "linear",
|
||||
"nodata": "",
|
||||
"dot": false,
|
||||
"ymin": "",
|
||||
"ymax": "",
|
||||
"removeOlder": 1,
|
||||
"removeOlderPoints": "",
|
||||
"removeOlderUnit": "3600",
|
||||
"cutout": 0,
|
||||
"useOneColor": false,
|
||||
"useUTC": false,
|
||||
"colors": [
|
||||
"#1f77b4",
|
||||
"#aec7e8",
|
||||
"#ff7f0e",
|
||||
"#2ca02c",
|
||||
"#98df8a",
|
||||
"#d62728",
|
||||
"#ff9896",
|
||||
"#9467bd",
|
||||
"#c5b0d5"
|
||||
],
|
||||
"outputs": 1,
|
||||
"x": 810,
|
||||
"y": 140,
|
||||
"wires": [
|
||||
[]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "a6037445.eb8ac8",
|
||||
"type": "ui_toast",
|
||||
"z": "c26229c6.2d1ae8",
|
||||
"position": "top right",
|
||||
"displayTime": "3",
|
||||
"highlight": "",
|
||||
"sendall": true,
|
||||
"outputs": 0,
|
||||
"ok": "OK",
|
||||
"cancel": "",
|
||||
"raw": false,
|
||||
"topic": "Button",
|
||||
"name": "Popup",
|
||||
"x": 810,
|
||||
"y": 280,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "b4478f8.f8b747",
|
||||
"type": "mqtt out",
|
||||
"z": "c26229c6.2d1ae8",
|
||||
"name": "Olimex",
|
||||
"topic": "paxin",
|
||||
"qos": "",
|
||||
"retain": "",
|
||||
"broker": "bd56b04d.db0ff",
|
||||
"x": 190,
|
||||
"y": 480,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "e2974f79.55d5b",
|
||||
"type": "binary",
|
||||
"z": "c26229c6.2d1ae8",
|
||||
"name": "device status",
|
||||
"property": "payload",
|
||||
"pattern": "l16 => voltage,\nl64 => uptime,\nb8 => temperature,\nl32 => ram,\nb8 => reset0,\nb8 => reset1",
|
||||
"x": 650,
|
||||
"y": 200,
|
||||
"wires": [
|
||||
[
|
||||
"4f59740b.296b7c"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "5f6987dd.b89378",
|
||||
"type": "binary",
|
||||
"z": "c26229c6.2d1ae8",
|
||||
"name": "device config",
|
||||
"property": "payload",
|
||||
"pattern": "b8 => loradr,\nb8 => txPower,\nl16 => rssilimit,\nb8 => sendcycle,\nb8 => wifichancycle,\nb8 => blescantime,\nb8 => rgblum,\nb8 => configmask,\nb8 => payloadmask,\nb8z|str(\"ascii\") => version",
|
||||
"x": 650,
|
||||
"y": 240,
|
||||
"wires": [
|
||||
[
|
||||
"4f59740b.296b7c"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "7b6cbc9d.18fe44",
|
||||
"type": "binary",
|
||||
"z": "c26229c6.2d1ae8",
|
||||
"name": "battery",
|
||||
"property": "payload",
|
||||
"pattern": "l16 => voltage",
|
||||
"x": 630,
|
||||
"y": 360,
|
||||
"wires": [
|
||||
[
|
||||
"4f59740b.296b7c"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "d269537.4738fb",
|
||||
"type": "binary",
|
||||
"z": "c26229c6.2d1ae8",
|
||||
"name": "time",
|
||||
"property": "payload",
|
||||
"pattern": "l32 => unixtime",
|
||||
"x": 630,
|
||||
"y": 400,
|
||||
"wires": [
|
||||
[
|
||||
"4f59740b.296b7c"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "ce0cb32b.b7b96",
|
||||
"type": "base64",
|
||||
"z": "c26229c6.2d1ae8",
|
||||
"name": "Encode",
|
||||
"action": "",
|
||||
"property": "payload",
|
||||
"x": 200,
|
||||
"y": 420,
|
||||
"wires": [
|
||||
[
|
||||
"b4478f8.f8b747"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "c246a129.eeb5e",
|
||||
"type": "inject",
|
||||
"z": "c26229c6.2d1ae8",
|
||||
"name": "rcmd",
|
||||
"props": [
|
||||
{
|
||||
"p": "payload"
|
||||
},
|
||||
{
|
||||
"p": "topic",
|
||||
"vt": "str"
|
||||
}
|
||||
],
|
||||
"repeat": "",
|
||||
"crontab": "",
|
||||
"once": false,
|
||||
"onceDelay": 0.1,
|
||||
"topic": "paxin",
|
||||
"payload": "[128, 129]",
|
||||
"payloadType": "bin",
|
||||
"x": 190,
|
||||
"y": 360,
|
||||
"wires": [
|
||||
[
|
||||
"ce0cb32b.b7b96"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "bd56b04d.db0ff",
|
||||
"type": "mqtt-broker",
|
||||
"name": "Shiftr.io",
|
||||
"broker": "public.cloud.shiftr.io",
|
||||
"port": "1883",
|
||||
"clientid": "",
|
||||
"usetls": false,
|
||||
"compatmode": false,
|
||||
"keepalive": "60",
|
||||
"cleansession": true,
|
||||
"birthTopic": "paxout/status",
|
||||
"birthQos": "0",
|
||||
"birthPayload": "on",
|
||||
"closeTopic": "paxout/status",
|
||||
"closeQos": "0",
|
||||
"closePayload": "off",
|
||||
"willTopic": "paxout/status",
|
||||
"willQos": "0",
|
||||
"willPayload": "unknown"
|
||||
},
|
||||
{
|
||||
"id": "6838565d.06bf08",
|
||||
"type": "ui_group",
|
||||
"name": "MQTT",
|
||||
"tab": "ad5894fa.466c58",
|
||||
"order": 1,
|
||||
"disp": true,
|
||||
"width": "6",
|
||||
"collapse": false
|
||||
},
|
||||
{
|
||||
"id": "ad5894fa.466c58",
|
||||
"type": "ui_tab",
|
||||
"name": "Paxcounter",
|
||||
"icon": "people",
|
||||
"order": 4
|
||||
}
|
||||
]
|
@ -262,7 +262,7 @@ var bitmap2 = function (byte) {
|
||||
}
|
||||
var i = bytesToInt(byte);
|
||||
var bm = ('00000000' + Number(i).toString(2)).substr(-8).split('').map(Number).map(Boolean);
|
||||
return ['battery', 'sensor3', 'sensor2', 'sensor1', 'counter', 'bme', 'alarm', 'gps']
|
||||
return ['battery', 'sensor3', 'sensor2', 'sensor1', 'gps', 'bme', 'alarm', 'counter']
|
||||
.reduce(function (obj, pos, index) {
|
||||
obj[pos] = +bm[index];
|
||||
return obj;
|
||||
|
@ -277,12 +277,11 @@ void start_BLEscan(void) {
|
||||
// Register callback function for capturing bluetooth packets
|
||||
register_ble_callback(false);
|
||||
ESP_LOGI(TAG, "Bluetooth scanner started");
|
||||
#endif // BLECOUNTER
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Bluetooth controller start failed. Resetting device");
|
||||
do_reset(true);
|
||||
}
|
||||
|
||||
#endif // BLECOUNTER
|
||||
} // start_BLEscan
|
||||
|
||||
void stop_BLEscan(void) {
|
||||
|
@ -46,10 +46,10 @@ Adafruit_BMP085 bmp; // I2C
|
||||
void setBMEIRQ() { xTaskNotify(irqHandlerTask, BME_IRQ, eSetBits); }
|
||||
|
||||
// initialize MEMS sensor
|
||||
// return = 0 -> error / return = 1 -> success
|
||||
int bme_init(void) {
|
||||
|
||||
// return = 0 -> error / return = 1 -> success
|
||||
int rc = 1;
|
||||
int rc = 0;
|
||||
|
||||
#ifdef HAS_BME680
|
||||
// block i2c bus access
|
||||
@ -63,76 +63,33 @@ int bme_init(void) {
|
||||
iaqSensor.version.minor_bugfix);
|
||||
|
||||
iaqSensor.setConfig(bsec_config_iaq);
|
||||
|
||||
if (checkIaqSensorStatus())
|
||||
ESP_LOGI(TAG, "BME680 sensor found and initialized");
|
||||
else {
|
||||
ESP_LOGE(TAG, "BME680 sensor not found");
|
||||
rc = 0;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
loadState();
|
||||
|
||||
iaqSensor.setTemperatureOffset((float)BME_TEMP_OFFSET);
|
||||
iaqSensor.updateSubscription(sensorList, 10, BSEC_SAMPLE_RATE_LP);
|
||||
|
||||
if (checkIaqSensorStatus())
|
||||
ESP_LOGI(TAG, "BSEC subscription succesful");
|
||||
else {
|
||||
ESP_LOGE(TAG, "BSEC subscription error");
|
||||
rc = 0;
|
||||
goto finish;
|
||||
}
|
||||
} else {
|
||||
rc = checkIaqSensorStatus();
|
||||
|
||||
} else
|
||||
ESP_LOGE(TAG, "I2c bus busy - BME680 initialization error");
|
||||
rc = 0;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
#elif defined HAS_BME280
|
||||
|
||||
bool status;
|
||||
|
||||
// block i2c bus access
|
||||
if (I2C_MUTEX_LOCK()) {
|
||||
|
||||
status = bme.begin(BME280_ADDR);
|
||||
if (!status) {
|
||||
ESP_LOGE(TAG, "BME280 sensor not found");
|
||||
rc = 0;
|
||||
goto finish;
|
||||
}
|
||||
ESP_LOGI(TAG, "BME280 sensor found and initialized");
|
||||
} else {
|
||||
rc = bme.begin(BME280_ADDR);
|
||||
} else
|
||||
ESP_LOGE(TAG, "I2c bus busy - BME280 initialization error");
|
||||
rc = 0;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
#elif defined HAS_BMP180
|
||||
bool status;
|
||||
// block i2c bus access
|
||||
if (I2C_MUTEX_LOCK()) {
|
||||
// Wire.begin(21, 22);
|
||||
status = bmp.begin();
|
||||
if (!status) {
|
||||
ESP_LOGE(TAG, "BMP180 sensor not found");
|
||||
rc = 0;
|
||||
goto finish;
|
||||
}
|
||||
ESP_LOGI(TAG, "BMP180 sensor found and initialized");
|
||||
} else {
|
||||
rc = bmp.begin();
|
||||
} else
|
||||
ESP_LOGE(TAG, "I2c bus busy - BMP180 initialization error");
|
||||
rc = 0;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
finish:
|
||||
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
||||
if (rc)
|
||||
bmecycler.attach(BMECYCLE, setBMEIRQ);
|
||||
bmecycler.attach(BMECYCLE, setBMEIRQ); // start cyclic data transmit
|
||||
return rc;
|
||||
|
||||
} // bme_init()
|
||||
|
@ -5,6 +5,10 @@
|
||||
// (c) by Kaspar Metz
|
||||
// modified for use in the Paxcounter by AQ
|
||||
|
||||
#if (COUNT_ENS) && !(BLECOUNTER)
|
||||
#warning ENS-Counter needs Bluetooth, but Bluetooth compile option is disabled
|
||||
#endif
|
||||
|
||||
#if (COUNT_ENS)
|
||||
|
||||
// Local logging tag
|
||||
|
@ -14,22 +14,15 @@ extern boolean isSDS011Active;
|
||||
#endif
|
||||
|
||||
void setCyclicIRQ() {
|
||||
xTaskNotifyFromISR(irqHandlerTask, CYCLIC_IRQ, eSetBits, NULL);
|
||||
xTaskNotify(irqHandlerTask, CYCLIC_IRQ, eSetBits);
|
||||
}
|
||||
|
||||
// do all housekeeping
|
||||
void doHousekeeping() {
|
||||
|
||||
// check if update mode trigger switch was set
|
||||
if (RTC_runmode == RUNMODE_UPDATE) {
|
||||
// check battery status if we can before doing ota
|
||||
if (batt_sufficient()) {
|
||||
do_reset(true); // warmstart to runmode update
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Battery level %d%% is too low for OTA", batt_level);
|
||||
RTC_runmode = RUNMODE_NORMAL; // keep running in normal mode
|
||||
}
|
||||
}
|
||||
// check if update mode trigger switch was set by rcommand
|
||||
if (RTC_runmode == RUNMODE_UPDATE)
|
||||
do_reset(true);
|
||||
|
||||
// heap and task storage debugging
|
||||
ESP_LOGD(TAG, "Heap: Free:%d, Min:%d, Size:%d, Alloc:%d, StackHWM:%d",
|
||||
@ -41,6 +34,8 @@ void doHousekeeping() {
|
||||
ESP_LOGD(TAG, "MACprocessor %d bytes left | Taskstate = %d",
|
||||
uxTaskGetStackHighWaterMark(macProcessTask),
|
||||
eTaskGetState(macProcessTask));
|
||||
ESP_LOGD(TAG, "Rcommand interpreter %d bytes left | Taskstate = %d",
|
||||
uxTaskGetStackHighWaterMark(rcmdTask), eTaskGetState(rcmdTask));
|
||||
#if (HAS_LORA)
|
||||
ESP_LOGD(TAG, "LMiCtask %d bytes left | Taskstate = %d",
|
||||
uxTaskGetStackHighWaterMark(lmicTask), eTaskGetState(lmicTask));
|
||||
@ -104,7 +99,6 @@ void doHousekeeping() {
|
||||
"free heap = %d bytes)",
|
||||
ESP.getMinFreeHeap(), ESP.getFreeHeap());
|
||||
reset_counters(); // clear macs container and reset all counters
|
||||
get_salt(); // get new salt for salting hashes
|
||||
|
||||
if (ESP.getMinFreeHeap() <= MEM_LOW) // check again
|
||||
do_reset(true); // memory leak, reset device
|
||||
@ -115,7 +109,6 @@ void doHousekeeping() {
|
||||
if (ESP.getMinFreePsram() <= MEM_LOW) {
|
||||
ESP_LOGI(TAG, "PSRAM full, counter cleared");
|
||||
reset_counters(); // clear macs container and reset all counters
|
||||
get_salt(); // get new salt for salting hashes
|
||||
|
||||
if (ESP.getMinFreePsram() <= MEM_LOW) // check again
|
||||
do_reset(true); // memory leak, reset device
|
||||
@ -147,6 +140,7 @@ void reset_counters() {
|
||||
macs.clear(); // clear all macs container
|
||||
macs_wifi = 0;
|
||||
macs_ble = 0;
|
||||
renew_salt(); // get new salt
|
||||
#ifdef HAS_DISPLAY
|
||||
dp_plotCurve(0, true);
|
||||
#endif
|
||||
|
@ -345,10 +345,10 @@ void dp_drawPage(time_t t, bool nextpage) {
|
||||
|
||||
#if (HAS_LORA)
|
||||
// LMiC event display
|
||||
dp_printf("%-16s", lmic_event_msg);
|
||||
dp_printf("%-16s ", lmic_event_msg);
|
||||
// LORA datarate, display inverse if ADR disabled
|
||||
dp_setFont(MY_FONT_SMALL, !cfg.adrmode);
|
||||
dp_printf(" %-4s", getSfName(updr2rps(LMIC.datarate)));
|
||||
dp_printf("%-4s", getSfName(updr2rps(LMIC.datarate)));
|
||||
dp_setFont(MY_FONT_SMALL, 0);
|
||||
dp_println();
|
||||
#endif // HAS_LORA
|
||||
@ -400,7 +400,7 @@ void dp_drawPage(time_t t, bool nextpage) {
|
||||
gps.location.lat());
|
||||
|
||||
// line 6-7: GPS longitude
|
||||
dp_printf("%c%07.4f", gps.location.rawLat().negative ? 'W' : 'E',
|
||||
dp_printf("%c%07.4f", gps.location.rawLng().negative ? 'W' : 'E',
|
||||
gps.location.lng());
|
||||
|
||||
} else {
|
||||
|
@ -30,34 +30,27 @@ static uint16_t nmea_txDelay_ms = 0;
|
||||
// initialize and configure GPS
|
||||
int gps_init(void) {
|
||||
|
||||
int ret = 1;
|
||||
|
||||
if (!gps_config()) {
|
||||
ESP_LOGE(TAG, "GPS chip initializiation error");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef GPS_SERIAL
|
||||
ESP_LOGI(TAG, "Opening serial GPS");
|
||||
GPS_Serial.begin(GPS_SERIAL);
|
||||
ESP_LOGI(TAG, "Using serial GPS");
|
||||
#elif defined GPS_I2C
|
||||
ESP_LOGI(TAG, "Opening I2C GPS");
|
||||
Wire.begin(GPS_I2C, 400000); // I2C connect to GPS device with 400 KHz
|
||||
Wire.beginTransmission(GPS_ADDR);
|
||||
Wire.write(0x00); // dummy write
|
||||
ret = Wire.endTransmission(); // check if chip is seen on i2c bus
|
||||
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG,
|
||||
"Quectel L76 GPS chip not found on i2c bus, bus error %d. "
|
||||
"Stopping GPS-Task.",
|
||||
ret);
|
||||
ret = 0;
|
||||
} else {
|
||||
Wire.write(0x00); // dummy write
|
||||
if (Wire.endTransmission()) {
|
||||
ESP_LOGE(TAG, "Quectel L76 GPS chip not found");
|
||||
return 0;
|
||||
} else
|
||||
ESP_LOGI(TAG, "Quectel L76 GPS chip found");
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
return 1;
|
||||
} // gps_init()
|
||||
|
||||
// detect gps chipset type and configure it with device specific settings
|
||||
@ -109,7 +102,7 @@ time_t get_gpstime(uint16_t *msec) {
|
||||
#endif
|
||||
|
||||
// did we get a current date & time?
|
||||
if (gpstime.isValid() && gpsday.isValid()) {
|
||||
if (gpstime.isValid()) {
|
||||
|
||||
time_t t = 0;
|
||||
tmElements_t tm;
|
||||
@ -126,8 +119,8 @@ time_t get_gpstime(uint16_t *msec) {
|
||||
tm.Year = CalendarYrToTm(atoi(gpsyear.value())); // year offset from 1970
|
||||
t = makeTime(tm);
|
||||
|
||||
// ESP_LOGD(TAG, "GPS time/date = %2d:%2d:%2d / %2d.%2d.%2d", tm.Hour,
|
||||
// tm.Minute, tm.Second, tm.Day, tm.Month, tm.Year + 1970);
|
||||
ESP_LOGD(TAG, "GPS time/date = %02d:%02d:%02d / %02d.%02d.%2d", tm.Hour,
|
||||
tm.Minute, tm.Second, tm.Day, tm.Month, tm.Year + 1970);
|
||||
|
||||
// add protocol delay with millisecond precision
|
||||
t += delay_ms / 1000 - 1; // whole seconds
|
||||
@ -188,4 +181,4 @@ void gps_loop(void *pvParameters) {
|
||||
|
||||
} // gps_loop()
|
||||
|
||||
#endif // HAS_GPS
|
||||
#endif // HAS_GPS
|
||||
|
@ -10,7 +10,6 @@
|
||||
// Hardware related definitions for Pycom LoPy4 Board
|
||||
|
||||
#define HAS_LORA 1 // comment out if device shall not send data via LoRa
|
||||
#define LORA_RST LMIC_UNUSED_PIN // reset pin of lora chip is not wired von LoPy4
|
||||
|
||||
//#defin HAS_SPI 1 // comment out if device shall not send data via SPI
|
||||
// pin definitions for local wired SPI slave interface
|
||||
|
58
src/hal/ttgotwristband.h
Normal file
58
src/hal/ttgotwristband.h
Normal file
@ -0,0 +1,58 @@
|
||||
// clang-format off
|
||||
// upload_speed 1500000
|
||||
// board pico32
|
||||
|
||||
#ifndef _TTGOTWRISTBAND_H
|
||||
#define _TTGOTWRISTBAND_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature
|
||||
|
||||
#define HAS_DISPLAY 2 // TFT-LCD, support work in progess, not ready yet
|
||||
#define MY_DISPLAY_FLIP 1 // use if display is rotated
|
||||
|
||||
#define HAS_LED NOT_A_PIN // no on board LED (?)
|
||||
#define HAS_BUTTON (33) // on board button A
|
||||
|
||||
// power management settings
|
||||
#define BAT_MEASURE_ADC ADC1_GPIO35_CHANNEL // battery probe GPIO pin -> ADC1_CHANNEL_7
|
||||
#define BAT_VOLTAGE_DIVIDER 2.605f // voltage divider
|
||||
|
||||
// Display Settings
|
||||
#define MY_DISPLAY_WIDTH 80
|
||||
#define MY_DISPLAY_HEIGHT 160
|
||||
#define MY_DISPLAY_INVERT 1
|
||||
|
||||
// setting for TTGO T-display
|
||||
#define USER_SETUP_LOADED 1
|
||||
#define ST7735_DRIVER 1
|
||||
|
||||
#define CGRAM_OFFSET
|
||||
|
||||
#define TFT_MISO -1
|
||||
#define TFT_MOSI GPIO_NUM_19 // SPI
|
||||
#define TFT_SCLK GPIO_NUM_18 // SPI
|
||||
#define TFT_CS GPIO_NUM_5 // Chip select control
|
||||
#define TFT_DC GPIO_NUM_23 // Data Command control
|
||||
#define TFT_RST GPIO_NUM_26 // Reset
|
||||
#define TFT_BL GPIO_NUM_27 // LED back-light
|
||||
#define TFT_BACKLIGHT_ON 1
|
||||
#define ST7735_GREENTAB160x80
|
||||
|
||||
#define TFT_RGB_ORDER TFT_BGR // Colour order Blue-Green-Red
|
||||
|
||||
#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
|
||||
#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
|
||||
#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
|
||||
#define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
|
||||
#define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-.
|
||||
#define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
|
||||
#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts
|
||||
#define SMOOTH_FONT
|
||||
|
||||
#define SPI_FREQUENCY 27000000
|
||||
#define SPI_READ_FREQUENCY 6000000
|
||||
|
||||
#endif
|
||||
|
52
src/hash.cpp
52
src/hash.cpp
@ -36,52 +36,10 @@
|
||||
|
||||
#include "hash.h"
|
||||
|
||||
uint32_t IRAM_ATTR rokkit(const char *data, int len) {
|
||||
uint32_t hash, tmp;
|
||||
int rem;
|
||||
#ifdef ROKKIT_ENABLE_8BIT_OPTIMIZATIONS
|
||||
#undef ROKKIT_ENABLE_8BIT_OPTIMIZATIONS
|
||||
#endif
|
||||
|
||||
if (len <= 0 || data == 0)
|
||||
return 0;
|
||||
hash = len;
|
||||
rem = len & 3;
|
||||
len >>= 2;
|
||||
|
||||
/* Main loop */
|
||||
while (len > 0) {
|
||||
hash += *((uint16_t *)data);
|
||||
tmp = (*((uint16_t *)(data + 2)) << 11) ^ hash;
|
||||
hash = (hash << 16) ^ tmp;
|
||||
data += 2 * 2;
|
||||
hash += hash >> 11;
|
||||
len--;
|
||||
}
|
||||
|
||||
/* Handle end cases */
|
||||
switch (rem) {
|
||||
case 3:
|
||||
hash += *((uint16_t *)data);
|
||||
hash ^= hash << 16;
|
||||
hash ^= ((signed char)data[2]) << 18;
|
||||
hash += hash >> 11;
|
||||
break;
|
||||
case 2:
|
||||
hash += *((uint16_t *)data);
|
||||
hash ^= hash << 11;
|
||||
hash += hash >> 17;
|
||||
break;
|
||||
case 1:
|
||||
hash += (signed char)*data;
|
||||
hash ^= hash << 10;
|
||||
hash += hash >> 1;
|
||||
}
|
||||
|
||||
/* Force "avalanching" of final 127 bits */
|
||||
hash ^= hash << 3;
|
||||
hash += hash >> 5;
|
||||
hash ^= hash << 4;
|
||||
hash += hash >> 17;
|
||||
hash ^= hash << 25;
|
||||
hash += hash >> 6;
|
||||
|
||||
return hash;
|
||||
uint32_t IRAM_ATTR hash(const char *data, int len) {
|
||||
return rokkit(data, len);
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ void i2c_scan(void) {
|
||||
}
|
||||
|
||||
// mutexed functions for i2c r/w access
|
||||
uint8_t i2c_readBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len) {
|
||||
int i2c_readBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len) {
|
||||
if (I2C_MUTEX_LOCK()) {
|
||||
|
||||
uint8_t ret = 0;
|
||||
@ -112,7 +112,7 @@ uint8_t i2c_readBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len) {
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t i2c_writeBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len) {
|
||||
int i2c_writeBytes(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len) {
|
||||
if (I2C_MUTEX_LOCK()) {
|
||||
|
||||
uint8_t ret = 0;
|
||||
|
@ -18,9 +18,10 @@
|
||||
|
||||
// use interrupts only if LORA_IRQ and LORA_DIO are connected to interrupt
|
||||
// capable and separate GPIO pins on your board, if not don't enable
|
||||
#if (LORA_IRQ) != (LORA_IO1)
|
||||
#define LMIC_USE_INTERRUPTS 1
|
||||
#endif
|
||||
// note: this feature can't be used on ESP32 unless PR #556 of MCCI LMIC was merged
|
||||
//#if (LORA_IRQ) != (LORA_IO1)
|
||||
//#define LMIC_USE_INTERRUPTS 1
|
||||
//#endif
|
||||
|
||||
// avoid lmic warning if we don't configure radio in case we haven't one
|
||||
#if !(defined(CFG_sx1272_radio) || defined(CFG_sx1276_radio))
|
||||
|
@ -19,7 +19,7 @@ RTC_DATA_ATTR lmic_t RTC_LMIC;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
QueueHandle_t LoraSendQueue;
|
||||
static QueueHandle_t LoraSendQueue;
|
||||
TaskHandle_t lmicTask = NULL, lorasendTask = NULL;
|
||||
|
||||
class MyHalConfig_t : public Arduino_LMIC::HalConfiguration_t {
|
||||
@ -284,14 +284,10 @@ esp_err_t lmic_init(void) {
|
||||
// Pass OTA parameters to LMIC_setSession
|
||||
#else
|
||||
// load saved session from RTC, if we have one
|
||||
if (RTC_runmode == RUNMODE_WAKEUP) {
|
||||
if (RTC_runmode == RUNMODE_WAKEUP)
|
||||
LoadLMICFromRTC();
|
||||
}
|
||||
// otherwise start join procedure if not already joined
|
||||
else {
|
||||
if (!LMIC_startJoining())
|
||||
ESP_LOGI(TAG, "Already joined");
|
||||
}
|
||||
if (!LMIC_startJoining())
|
||||
ESP_LOGI(TAG, "Already joined");
|
||||
#endif
|
||||
|
||||
// start lmic loop task
|
||||
@ -545,7 +541,7 @@ void SaveLMICToRTC(int deepsleep_sec) {
|
||||
unsigned long now = millis();
|
||||
|
||||
// EU Like Bands
|
||||
#if defined(CFG_LMIC_EU_like)
|
||||
#if CFG_LMIC_EU_like
|
||||
for (int i = 0; i < MAX_BANDS; i++) {
|
||||
ostime_t correctedAvail =
|
||||
RTC_LMIC.bands[i].avail -
|
||||
|
@ -6,13 +6,14 @@
|
||||
// Local logging tag
|
||||
static const char TAG[] = __FILE__;
|
||||
|
||||
QueueHandle_t MacQueue;
|
||||
static QueueHandle_t MacQueue;
|
||||
TaskHandle_t macProcessTask;
|
||||
|
||||
uint16_t salt = 0;
|
||||
static uint32_t salt = renew_salt();
|
||||
|
||||
uint16_t get_salt(void) {
|
||||
salt = (uint16_t)random(65536); // get new 16bit random for salting hashes
|
||||
uint32_t renew_salt(void) {
|
||||
salt = esp_random();
|
||||
ESP_LOGV(TAG, "new salt = %04X", salt);
|
||||
return salt;
|
||||
}
|
||||
|
||||
@ -101,8 +102,9 @@ void IRAM_ATTR mac_add(uint8_t *paddr, int8_t rssi, snifftype_t sniff_type) {
|
||||
|
||||
uint16_t mac_analyze(MacBuffer_t MacBuffer) {
|
||||
|
||||
if (salt == 0) // ensure we have salt (appears after radio is turned on)
|
||||
return 0;
|
||||
uint32_t *mac; // pointer to shortened 4 byte MAC
|
||||
uint32_t saltedmac;
|
||||
uint16_t hashedmac;
|
||||
|
||||
if ((cfg.rssilimit) &&
|
||||
(MacBuffer.rssi < cfg.rssilimit)) { // rssi is negative value
|
||||
@ -117,18 +119,13 @@ uint16_t mac_analyze(MacBuffer_t MacBuffer) {
|
||||
int8_t beaconID = isBeacon(macConvert(MacBuffer.mac));
|
||||
if (beaconID >= 0) {
|
||||
ESP_LOGI(TAG, "Beacon ID#%d detected", beaconID);
|
||||
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
|
||||
blink_LED(COLOR_WHITE, 2000);
|
||||
#endif
|
||||
payload.reset();
|
||||
payload.addAlarm(MacBuffer.rssi, beaconID);
|
||||
SendPayload(BEACONPORT);
|
||||
}
|
||||
};
|
||||
|
||||
char buff[10]; // temporary buffer for printf
|
||||
uint32_t *mac; // temporary buffer for shortened MAC
|
||||
|
||||
// only last 3 MAC Address bytes are used for MAC address anonymization
|
||||
// but since it's uint32 we take 4 bytes to avoid 1st value to be 0.
|
||||
// this gets MAC in msb (= reverse) order, but doesn't matter for hashing it.
|
||||
@ -138,11 +135,15 @@ uint16_t mac_analyze(MacBuffer_t MacBuffer) {
|
||||
// and increment counter on display
|
||||
// https://en.wikipedia.org/wiki/MAC_Address_Anonymization
|
||||
|
||||
snprintf(buff, sizeof(buff), "%08X",
|
||||
*mac + (uint32_t)salt); // convert unsigned 32-bit salted MAC
|
||||
// to 8 digit hex string
|
||||
uint16_t hashedmac = rokkit(&buff[3], 5); // hash MAC 8 digit -> 5 digit
|
||||
auto newmac = macs.insert(hashedmac); // add hashed MAC, if new unique
|
||||
// reversed 4 byte MAC added to current salt
|
||||
saltedmac = *mac + salt;
|
||||
|
||||
// hashed 4 byte MAC
|
||||
// to save RAM, we use only lower 2 bytes of hash, since collisions don't
|
||||
// matter in our use case
|
||||
hashedmac = hash((const char *)&saltedmac, 4);
|
||||
|
||||
auto newmac = macs.insert(hashedmac); // add hashed MAC, if new unique
|
||||
bool added =
|
||||
newmac.second ? true : false; // true if hashed MAC is unique in container
|
||||
|
||||
@ -153,37 +154,30 @@ uint16_t mac_analyze(MacBuffer_t MacBuffer) {
|
||||
|
||||
case MAC_SNIFF_WIFI:
|
||||
macs_wifi++; // increment Wifi MACs counter
|
||||
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
|
||||
blink_LED(COLOR_GREEN, 50);
|
||||
#endif
|
||||
break;
|
||||
|
||||
#if (BLECOUNTER)
|
||||
case MAC_SNIFF_BLE:
|
||||
macs_ble++; // increment BLE Macs counter
|
||||
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
|
||||
blink_LED(COLOR_MAGENTA, 50);
|
||||
#endif
|
||||
break;
|
||||
|
||||
#if (COUNT_ENS)
|
||||
case MAC_SNIFF_BLE_ENS:
|
||||
macs_ble++; // increment BLE Macs counter
|
||||
cwa_mac_add(hashedmac); // process ENS beacon
|
||||
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
|
||||
blink_LED(COLOR_WHITE, 50);
|
||||
#endif
|
||||
break;
|
||||
|
||||
#endif // COUNT_ENS
|
||||
#endif // BLECOUNTER
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
|
||||
} // switch
|
||||
} // added
|
||||
|
||||
// Log scan result
|
||||
ESP_LOGV(TAG,
|
||||
"%s %s RSSI %ddBi -> salted MAC %s -> Hash %04X -> WiFi:%d "
|
||||
"%s %s RSSI %ddBi -> MAC %0x:%0x:%0x:%0x:%0x:%0x -> salted %04X"
|
||||
" -> hashed %04X -> WiFi:%d "
|
||||
"BLTH:%d "
|
||||
#if (COUNT_ENS)
|
||||
"(CWA:%d)"
|
||||
@ -191,7 +185,9 @@ uint16_t mac_analyze(MacBuffer_t MacBuffer) {
|
||||
"-> %d Bytes left",
|
||||
added ? "new " : "known",
|
||||
MacBuffer.sniff_type == MAC_SNIFF_WIFI ? "WiFi" : "BLTH",
|
||||
MacBuffer.rssi, buff, hashedmac, macs_wifi, macs_ble,
|
||||
MacBuffer.rssi, MacBuffer.mac[0], MacBuffer.mac[1], MacBuffer.mac[2],
|
||||
MacBuffer.mac[3], MacBuffer.mac[4], MacBuffer.mac[5], saltedmac,
|
||||
hashedmac, macs_wifi, macs_ble,
|
||||
#if (COUNT_ENS)
|
||||
cwa_report(),
|
||||
#endif
|
||||
|
23
src/main.cpp
23
src/main.cpp
@ -29,16 +29,17 @@ Task Core Prio Purpose
|
||||
-------------------------------------------------------------------------------
|
||||
ledloop 0 3 blinks LEDs
|
||||
spiloop 0 2 reads/writes data on spi interface
|
||||
mqttloop 0 2 reads/writes data on ETH interface
|
||||
IDLE 0 0 ESP32 arduino scheduler -> runs wifi sniffer
|
||||
|
||||
lmictask 1 2 MCCI LMiC LORAWAN stack
|
||||
clockloop 1 4 generates realtime telegrams for external clock
|
||||
mqttloop 1 2 reads/writes data on ETH interface
|
||||
timesync_proc 1 3 processes realtime time sync requests
|
||||
irqhandler 1 2 cyclic tasks (i.e. displayrefresh) triggered by timers
|
||||
gpsloop 1 1 reads data from GPS via serial or i2c
|
||||
lorasendtask 1 1 feeds data from lora sendqueue to lmcic
|
||||
macprocess 1 1 analyzes sniffed MACs
|
||||
macprocess 1 1 MAC analyzer loop
|
||||
rmcd_process 1 1 Remote command interpreter loop
|
||||
IDLE 1 0 ESP32 arduino scheduler -> runs wifi channel rotator
|
||||
|
||||
Low priority numbers denote low priority tasks.
|
||||
@ -60,8 +61,10 @@ irqHandlerTask (Core 1), see irqhandler.cpp
|
||||
|
||||
fired by hardware
|
||||
DisplayIRQ -> esp32 timer 0
|
||||
ButtonIRQ -> external gpio
|
||||
PMUIRQ -> PMU chip gpio
|
||||
CLOCKIRQ -> esp32 timer 1 or external GPIO (RTC_INT or GPS_INT)
|
||||
MatrixDisplayIRQ-> esp32 timer 3
|
||||
ButtonIRQ -> external GPIO
|
||||
PMUIRQ -> PMU chip GPIO
|
||||
|
||||
fired by software (Ticker.h)
|
||||
TIMESYNC_IRQ -> setTimeSyncIRQ()
|
||||
@ -100,7 +103,7 @@ timesource_t timeSource = _unsynced;
|
||||
|
||||
// container holding unique MAC address hashes with Memory Alloctor using PSRAM,
|
||||
// if present
|
||||
std::set<uint16_t, std::less<uint16_t>, Mallocator<uint16_t>> macs;
|
||||
DRAM_ATTR std::set<uint16_t, std::less<uint16_t>, Mallocator<uint16_t>> macs;
|
||||
|
||||
// initialize payload encoder
|
||||
PayloadConvert payload(PAYLOAD_BUFFER_SIZE);
|
||||
@ -291,6 +294,10 @@ void setup() {
|
||||
ESP_LOGI(TAG, "Starting MAC processor...");
|
||||
macQueueInit();
|
||||
|
||||
// start rcommand processing task
|
||||
ESP_LOGI(TAG, "Starting rcommand interpreter...");
|
||||
rcmd_init();
|
||||
|
||||
// start BLE scan callback if BLE function is enabled in NVRAM configuration
|
||||
// or remove bluetooth stack from RAM, if option bluetooth is not compiled
|
||||
#if (BLECOUNTER)
|
||||
@ -428,7 +435,7 @@ void setup() {
|
||||
// initialize salt value using esp_random() called by random() in
|
||||
// arduino-esp32 core. Note: do this *after* wifi has started, since
|
||||
// function gets it's seed from RF noise
|
||||
get_salt(); // get new 16bit for salting hashes
|
||||
reset_counters();
|
||||
|
||||
// start state machine
|
||||
ESP_LOGI(TAG, "Starting Interrupt Handler...");
|
||||
@ -451,8 +458,10 @@ void setup() {
|
||||
#endif
|
||||
if (bme_init())
|
||||
ESP_LOGI(TAG, "BME sensor initialized");
|
||||
else
|
||||
else {
|
||||
ESP_LOGE(TAG, "BME sensor could not be initialized");
|
||||
cfg.payloadmask &= ~MEMS_DATA; // switch off transmit of BME data
|
||||
}
|
||||
#endif
|
||||
|
||||
// starting timers and interrupts
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
static const char TAG[] = __FILE__;
|
||||
|
||||
QueueHandle_t MQTTSendQueue;
|
||||
static QueueHandle_t MQTTSendQueue;
|
||||
TaskHandle_t mqttTask;
|
||||
|
||||
Ticker mqttTimer;
|
||||
@ -12,6 +12,7 @@ WiFiClient netClient;
|
||||
MQTTClient mqttClient;
|
||||
|
||||
void mqtt_deinit(void) {
|
||||
mqttClient.unsubscribe(MQTT_INTOPIC);
|
||||
mqttClient.onMessageAdvanced(NULL);
|
||||
mqttClient.disconnect();
|
||||
vTaskDelete(mqttTask);
|
||||
@ -19,12 +20,10 @@ void mqtt_deinit(void) {
|
||||
|
||||
esp_err_t mqtt_init(void) {
|
||||
|
||||
// setup network connection
|
||||
WiFi.onEvent(NetworkEvent);
|
||||
// setup network connection and MQTT client
|
||||
ETH.begin();
|
||||
|
||||
// setup mqtt client
|
||||
mqttClient.begin(MQTT_SERVER, MQTT_PORT, netClient);
|
||||
mqttClient.setKeepAlive(MQTT_KEEPALIVE);
|
||||
mqttClient.onMessageAdvanced(mqtt_callback);
|
||||
|
||||
_ASSERT(SEND_QUEUE_SIZE > 0);
|
||||
@ -37,15 +36,20 @@ esp_err_t mqtt_init(void) {
|
||||
SEND_QUEUE_SIZE * PAYLOAD_BUFFER_SIZE);
|
||||
|
||||
ESP_LOGI(TAG, "Starting MQTTloop...");
|
||||
xTaskCreate(mqtt_client_task, "mqttloop", 4096, (void *)NULL, 1, &mqttTask);
|
||||
|
||||
xTaskCreatePinnedToCore(mqtt_client_task, "mqttloop", 4096, (void *)NULL, 1,
|
||||
&mqttTask, 1);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int mqtt_connect(const char *my_host, const uint16_t my_port) {
|
||||
IPAddress mqtt_server_ip;
|
||||
uint8_t mac[6];
|
||||
char clientId[20];
|
||||
|
||||
static String clientId = "paxcounter-" + ETH.macAddress();
|
||||
// hash 6 byte MAC to 4 byte hash
|
||||
esp_eth_get_mac(mac);
|
||||
const uint32_t hashedmac = hash((const char *)mac, 6);
|
||||
snprintf(clientId, 20, "paxcounter_%08x", hashedmac);
|
||||
|
||||
ESP_LOGI(TAG, "MQTT name is %s", MQTT_CLIENTNAME);
|
||||
|
||||
@ -75,41 +79,6 @@ int mqtt_connect(const char *my_host, const uint16_t my_port) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NetworkEvent(WiFiEvent_t event) {
|
||||
switch (event) {
|
||||
case SYSTEM_EVENT_ETH_START:
|
||||
case SYSTEM_EVENT_STA_START:
|
||||
ESP_LOGI(TAG, "Network link layer started");
|
||||
// ETH.setHostname(ETH.macAddress().c_str());
|
||||
break;
|
||||
case SYSTEM_EVENT_ETH_STOP:
|
||||
case SYSTEM_EVENT_STA_STOP:
|
||||
ESP_LOGI(TAG, "Network link layer stopped");
|
||||
break;
|
||||
case SYSTEM_EVENT_ETH_CONNECTED:
|
||||
case SYSTEM_EVENT_STA_CONNECTED:
|
||||
ESP_LOGI(TAG, "Network link connected");
|
||||
break;
|
||||
case SYSTEM_EVENT_ETH_DISCONNECTED:
|
||||
case SYSTEM_EVENT_STA_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "Network link disconnected");
|
||||
break;
|
||||
case SYSTEM_EVENT_ETH_GOT_IP:
|
||||
ESP_LOGI(TAG, "IP: %s", ETH.localIP().toString().c_str());
|
||||
ESP_LOGI(TAG, "Link Speed: %d Mbps %s", ETH.linkSpeed(),
|
||||
ETH.fullDuplex() ? "full duplex" : "half duplex");
|
||||
mqtt_connect(MQTT_SERVER, MQTT_PORT);
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_GOT_IP:
|
||||
ESP_LOGI(TAG, "IP: %s", WiFi.localIP().toString().c_str());
|
||||
mqtt_connect(MQTT_SERVER, MQTT_PORT);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void mqtt_client_task(void *param) {
|
||||
|
||||
MessageBuffer_t msg;
|
||||
@ -128,21 +97,28 @@ void mqtt_client_task(void *param) {
|
||||
MQTT_KEEPALIVE * 1000 / portTICK_PERIOD_MS) != pdTRUE)
|
||||
continue;
|
||||
|
||||
// send data to mqtt server
|
||||
char buffer[PAYLOAD_BUFFER_SIZE + 3];
|
||||
snprintf(buffer, msg.MessageSize + 3, "%u/%s", msg.MessagePort,
|
||||
msg.Message);
|
||||
// prepare mqtt topic
|
||||
char topic[16];
|
||||
snprintf(topic, 16, "%s/%u", MQTT_OUTTOPIC, msg.MessagePort);
|
||||
size_t out_len = 0;
|
||||
|
||||
if (mqttClient.publish(MQTT_OUTTOPIC, buffer)) {
|
||||
ESP_LOGI(TAG, "%d byte(s) sent to MQTT server", msg.MessageSize + 2);
|
||||
// delete sent item from queue
|
||||
// get length of base64 encoded message
|
||||
mbedtls_base64_encode(NULL, 0, &out_len, (unsigned char *)msg.Message,
|
||||
msg.MessageSize);
|
||||
|
||||
// base64 encode the message
|
||||
unsigned char encoded[out_len];
|
||||
mbedtls_base64_encode(encoded, out_len, &out_len,
|
||||
(unsigned char *)msg.Message, msg.MessageSize);
|
||||
|
||||
// send encoded message to mqtt server and delete it from queue
|
||||
if (mqttClient.publish(topic, (const char *)encoded, out_len)) {
|
||||
ESP_LOGD(TAG, "%u bytes sent to MQTT server", out_len);
|
||||
xQueueReceive(MQTTSendQueue, &msg, (TickType_t)0);
|
||||
} else
|
||||
ESP_LOGD(TAG, "Couldn't sent message to MQTT server");
|
||||
} else {
|
||||
// attempt to reconnect to MQTT server
|
||||
ESP_LOGD(TAG, "MQTT error = %d / rc = %d", mqttClient.lastError(),
|
||||
mqttClient.returnCode());
|
||||
ESP_LOGD(TAG, "MQTT client reconnecting...");
|
||||
delay(MQTT_RETRYSEC * 1000);
|
||||
mqtt_connect(MQTT_SERVER, MQTT_PORT);
|
||||
@ -150,16 +126,27 @@ void mqtt_client_task(void *param) {
|
||||
} // while (1)
|
||||
}
|
||||
|
||||
void mqtt_enqueuedata(MessageBuffer_t *message) {
|
||||
// enqueue message in MQTT send queue
|
||||
if (xQueueSendToBack(MQTTSendQueue, (void *)message, (TickType_t)0) != pdTRUE)
|
||||
ESP_LOGW(TAG, "MQTT sendqueue is full");
|
||||
// process incoming MQTT messages
|
||||
void mqtt_callback(MQTTClient *client, char *topic, char *payload, int length) {
|
||||
if (strcmp(topic, MQTT_INTOPIC) == 0) {
|
||||
|
||||
// get length of base64 encoded message
|
||||
size_t out_len = 0;
|
||||
mbedtls_base64_decode(NULL, 0, &out_len, (unsigned char *)payload, length);
|
||||
|
||||
// decode the base64 message
|
||||
unsigned char decoded[out_len];
|
||||
mbedtls_base64_decode(decoded, out_len, &out_len, (unsigned char *)payload,
|
||||
length);
|
||||
|
||||
rcommand(decoded, out_len);
|
||||
}
|
||||
}
|
||||
|
||||
void mqtt_callback(MQTTClient *client, char topic[], char payload[],
|
||||
int length) {
|
||||
if (strcmp(topic, MQTT_INTOPIC) == 0)
|
||||
rcommand((const uint8_t *)payload, (const uint8_t)length);
|
||||
// enqueue outgoing messages in MQTT send queue
|
||||
void mqtt_enqueuedata(MessageBuffer_t *message) {
|
||||
if (xQueueSendToBack(MQTTSendQueue, (void *)message, (TickType_t)0) != pdTRUE)
|
||||
ESP_LOGW(TAG, "MQTT sendqueue is full");
|
||||
}
|
||||
|
||||
void mqtt_queuereset(void) { xQueueReset(MQTTSendQueue); }
|
||||
|
@ -121,3 +121,15 @@
|
||||
#define CAYENNE_DEVICECONFIG 11 // device period configuration
|
||||
#define CAYENNE_SENSORREAD 13 // sensor period configuration
|
||||
#define CAYENNE_SENSORENABLE 14 // sensor enable configuration
|
||||
|
||||
// MQTT settings, only needed if MQTT is used (#define HAS_MQTT in board hal file)
|
||||
#define MQTT_ETHERNET 0 // select PHY: set 0 for Wifi, 1 for ethernet
|
||||
#define MQTT_INTOPIC "paxin"
|
||||
#define MQTT_OUTTOPIC "paxout"
|
||||
#define MQTT_PORT 1883
|
||||
#define MQTT_SERVER "public.cloud.shiftr.io"
|
||||
#define MQTT_USER "public"
|
||||
#define MQTT_PASSWD "public"
|
||||
#define MQTT_RETRYSEC 20 // retry reconnect every 20 seconds
|
||||
#define MQTT_KEEPALIVE 10 // keep alive interval in seconds
|
||||
//#define MQTT_CLIENTNAME "my_paxcounter" // generated by default
|
||||
|
@ -46,6 +46,14 @@ void AXP192_powerevent_IRQ(void) {
|
||||
ESP_LOGI(TAG, "Battery high temperature.");
|
||||
if (pmu.isBattTempHighIRQ())
|
||||
ESP_LOGI(TAG, "Battery low temperature.");
|
||||
if (pmu.isLowVoltageLevel1IRQ()) {
|
||||
ESP_LOGI(TAG, "Battery has reached voltage level 1.");
|
||||
pmu.setChgLEDMode(AXP20X_LED_BLINK_4HZ);
|
||||
}
|
||||
if (pmu.isLowVoltageLevel2IRQ()) {
|
||||
ESP_LOGI(TAG, "Battery has reached voltage level 2.");
|
||||
pmu.setChgLEDMode(AXP20X_LED_BLINK_1HZ);
|
||||
}
|
||||
|
||||
// short press -> esp32 deep sleep mode, can be exited by pressing user button
|
||||
if (pmu.isPEKShortPressIRQ()) {
|
||||
@ -129,10 +137,15 @@ void AXP192_init(void) {
|
||||
pmu.setLDO2Voltage(3300); // LORA VDD 3v3
|
||||
pmu.setLDO3Voltage(3300); // GPS VDD 3v3
|
||||
|
||||
// configure voltage warning levels
|
||||
pmu.setVWarningLevel1(3600);
|
||||
pmu.setVWarningLevel2(3800);
|
||||
pmu.setPowerDownVoltage(3300);
|
||||
|
||||
// configure PEK button settings
|
||||
pmu.setTimeOutShutdown(false); // forced shutdown by PEK enabled
|
||||
pmu.setShutdownTime(
|
||||
AXP_POWER_OFF_TIME_65); // 6 sec button press for shutdown
|
||||
AXP_POWER_OFF_TIME_6S); // 6 sec button press for shutdown
|
||||
pmu.setlongPressTime(
|
||||
AXP_LONGPRESS_TIME_1S5); // 1.5 sec button press for long press
|
||||
pmu.setStartupTime(
|
||||
@ -158,9 +171,9 @@ void AXP192_init(void) {
|
||||
#endif // PMU_INT
|
||||
|
||||
// set charging parameterss according to user settings if we have (see power.h)
|
||||
#ifdef PMU_CHARGE_CURRENT
|
||||
pmu.setChargeControlCur(PMU_CHARGE_CURRENT);
|
||||
pmu.setChargingTargetVoltage(PMU_CHARGE_CUTOFF);
|
||||
#ifdef PMU_CHG_CURRENT
|
||||
pmu.setChargeControlCur(PMU_CHG_CURRENT);
|
||||
pmu.setChargingTargetVoltage(PMU_CHG_CUTOFF);
|
||||
pmu.enableChargeing(true);
|
||||
#endif
|
||||
|
||||
@ -251,10 +264,11 @@ uint8_t read_battlevel(mapFn_t mapFunction) {
|
||||
|
||||
bool batt_sufficient() {
|
||||
#if (defined HAS_PMU || defined BAT_MEASURE_ADC || defined HAS_IP5306)
|
||||
return (batt_level > OTA_MIN_BATT);
|
||||
#else
|
||||
return true; // we don't know batt level
|
||||
if (batt_level) // we have a battery voltage
|
||||
return (batt_level > OTA_MIN_BATT);
|
||||
else
|
||||
#endif
|
||||
return true; // we don't know batt level
|
||||
}
|
||||
|
||||
#ifdef HAS_IP5306
|
||||
|
139
src/rcommand.cpp
139
src/rcommand.cpp
@ -5,8 +5,8 @@
|
||||
// Local logging tag
|
||||
static const char TAG[] = __FILE__;
|
||||
|
||||
// global variable indicating if rcommand() is executing
|
||||
bool rcmd_busy = false;
|
||||
static QueueHandle_t RcmdQueue;
|
||||
TaskHandle_t rcmdTask;
|
||||
|
||||
// set of functions that can be triggered by remote commands
|
||||
void set_reset(uint8_t val[]) {
|
||||
@ -18,7 +18,6 @@ void set_reset(uint8_t val[]) {
|
||||
case 1: // reset MAC counter
|
||||
ESP_LOGI(TAG, "Remote command: reset MAC counter");
|
||||
reset_counters(); // clear macs
|
||||
get_salt(); // get new salt
|
||||
break;
|
||||
case 2: // reset device to factory settings
|
||||
ESP_LOGI(TAG, "Remote command: reset device to factory settings");
|
||||
@ -35,7 +34,11 @@ void set_reset(uint8_t val[]) {
|
||||
case 9: // reset and ask for software update via Wifi OTA
|
||||
ESP_LOGI(TAG, "Remote command: software update via Wifi");
|
||||
#if (USE_OTA)
|
||||
RTC_runmode = RUNMODE_UPDATE;
|
||||
// check power status before scheduling ota update
|
||||
if (batt_sufficient())
|
||||
RTC_runmode = RUNMODE_UPDATE;
|
||||
else
|
||||
ESP_LOGE(TAG, "Battery level %d%% is too low for OTA", batt_level);
|
||||
#endif // USE_OTA
|
||||
break;
|
||||
|
||||
@ -115,7 +118,6 @@ void set_countmode(uint8_t val[]) {
|
||||
return;
|
||||
}
|
||||
reset_counters(); // clear macs
|
||||
get_salt(); // get new salt
|
||||
}
|
||||
|
||||
void set_screensaver(uint8_t val[]) {
|
||||
@ -164,7 +166,7 @@ void set_payloadmask(uint8_t val[]) {
|
||||
|
||||
void set_sensor(uint8_t val[]) {
|
||||
#if (HAS_SENSORS)
|
||||
switch (val[0]) { // check if valid sensor number 1...4
|
||||
switch (val[0]) { // check if valid sensor number 1..3
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
@ -367,41 +369,49 @@ void set_enscount(uint8_t val[]) {
|
||||
cfg.payloadmask &= ~SENSOR1_DATA;
|
||||
}
|
||||
|
||||
void set_loadconfig(uint8_t val[]) {
|
||||
ESP_LOGI(TAG, "Remote command: load config from NVRAM");
|
||||
loadConfig();
|
||||
};
|
||||
|
||||
void set_saveconfig(uint8_t val[]) {
|
||||
ESP_LOGI(TAG, "Remote command: save config to NVRAM");
|
||||
saveConfig(false);
|
||||
};
|
||||
|
||||
// assign previously defined functions to set of numeric remote commands
|
||||
// format: opcode, function, #bytes params,
|
||||
// flag (true = do make settings persistent / false = don't)
|
||||
//
|
||||
// format: {opcode, function, number of function arguments}
|
||||
|
||||
static const cmd_t table[] = {
|
||||
{0x01, set_rssi, 1, true}, {0x02, set_countmode, 1, true},
|
||||
{0x03, set_gps, 1, true}, {0x04, set_display, 1, true},
|
||||
{0x05, set_loradr, 1, true}, {0x06, set_lorapower, 1, true},
|
||||
{0x07, set_loraadr, 1, true}, {0x08, set_screensaver, 1, true},
|
||||
{0x09, set_reset, 1, false}, {0x0a, set_sendcycle, 1, true},
|
||||
{0x0b, set_wifichancycle, 1, true}, {0x0c, set_blescantime, 1, true},
|
||||
{0x0d, set_macfilter, 1, false}, {0x0e, set_blescan, 1, true},
|
||||
{0x0f, set_wifiant, 1, true}, {0x10, set_rgblum, 1, true},
|
||||
{0x11, set_monitor, 1, true}, {0x12, set_beacon, 7, false},
|
||||
{0x13, set_sensor, 2, true}, {0x14, set_payloadmask, 1, true},
|
||||
{0x15, set_bme, 1, true}, {0x16, set_batt, 1, true},
|
||||
{0x17, set_wifiscan, 1, true}, {0x18, set_enscount, 1, true},
|
||||
{0x19, set_sleepcycle, 1, true}, {0x80, get_config, 0, false},
|
||||
{0x81, get_status, 0, false}, {0x83, get_batt, 0, false},
|
||||
{0x84, get_gps, 0, false}, {0x85, get_bme, 0, false},
|
||||
{0x86, get_time, 0, false}, {0x87, set_time, 0, false},
|
||||
{0x99, set_flush, 0, false}};
|
||||
{0x01, set_rssi, 1}, {0x02, set_countmode, 1},
|
||||
{0x03, set_gps, 1}, {0x04, set_display, 1},
|
||||
{0x05, set_loradr, 1}, {0x06, set_lorapower, 1},
|
||||
{0x07, set_loraadr, 1}, {0x08, set_screensaver, 1},
|
||||
{0x09, set_reset, 1}, {0x0a, set_sendcycle, 1},
|
||||
{0x0b, set_wifichancycle, 1}, {0x0c, set_blescantime, 1},
|
||||
{0x0d, set_macfilter, 1}, {0x0e, set_blescan, 1},
|
||||
{0x0f, set_wifiant, 1}, {0x10, set_rgblum, 1},
|
||||
{0x11, set_monitor, 1}, {0x12, set_beacon, 7},
|
||||
{0x13, set_sensor, 2}, {0x14, set_payloadmask, 1},
|
||||
{0x15, set_bme, 1}, {0x16, set_batt, 1},
|
||||
{0x17, set_wifiscan, 1}, {0x18, set_enscount, 1},
|
||||
{0x19, set_sleepcycle, 1}, {0x20, set_loadconfig, 0},
|
||||
{0x21, set_saveconfig, 0}, {0x80, get_config, 0},
|
||||
{0x81, get_status, 0}, {0x83, get_batt, 0},
|
||||
{0x84, get_gps, 0}, {0x85, get_bme, 0},
|
||||
{0x86, get_time, 0}, {0x87, set_time, 0},
|
||||
{0x99, set_flush, 0}};
|
||||
|
||||
static const uint8_t cmdtablesize =
|
||||
sizeof(table) / sizeof(table[0]); // number of commands in command table
|
||||
|
||||
// check and execute remote command
|
||||
void rcommand(const uint8_t cmd[], const uint8_t cmdlength) {
|
||||
void rcmd_execute(const uint8_t cmd[], const uint8_t cmdlength) {
|
||||
|
||||
if (cmdlength == 0)
|
||||
return;
|
||||
|
||||
uint8_t foundcmd[cmdlength], cursor = 0;
|
||||
bool storeflag = false;
|
||||
rcmd_busy = true;
|
||||
|
||||
while (cursor < cmdlength) {
|
||||
|
||||
@ -413,8 +423,6 @@ void rcommand(const uint8_t cmd[], const uint8_t cmdlength) {
|
||||
memmove(foundcmd, cmd + cursor,
|
||||
table[i].params); // strip opcode from cmd array
|
||||
cursor += table[i].params;
|
||||
if (table[i].store) // ceck if function needs to store configuration
|
||||
storeflag = true;
|
||||
table[i].func(
|
||||
foundcmd); // execute assigned function with given parameters
|
||||
} else
|
||||
@ -422,18 +430,75 @@ void rcommand(const uint8_t cmd[], const uint8_t cmdlength) {
|
||||
"Remote command x%02X called with missing parameter(s), "
|
||||
"skipped",
|
||||
table[i].opcode);
|
||||
break; // command found -> exit table lookup loop
|
||||
} // end of command validation
|
||||
} // end of command table lookup loop
|
||||
break; // command found -> exit table lookup loop
|
||||
} // end of command validation
|
||||
} // end of command table lookup loop
|
||||
|
||||
if (i < 0) { // command not found -> exit parser
|
||||
ESP_LOGI(TAG, "Unknown remote command x%02X, ignored", cmd[cursor]);
|
||||
break;
|
||||
}
|
||||
} // command parsing loop
|
||||
|
||||
if (storeflag)
|
||||
saveConfig();
|
||||
} // rcmd_execute()
|
||||
|
||||
rcmd_busy = false;
|
||||
// remote command processing task
|
||||
void rcmd_process(void *pvParameters) {
|
||||
_ASSERT((uint32_t)pvParameters == 1); // FreeRTOS check
|
||||
|
||||
RcmdBuffer_t RcmdBuffer;
|
||||
|
||||
while (1) {
|
||||
// fetch next or wait for incoming rcommand from queue
|
||||
if (xQueueReceive(RcmdQueue, &RcmdBuffer, portMAX_DELAY) != pdTRUE) {
|
||||
ESP_LOGE(TAG, "Premature return from xQueueReceive() with no data!");
|
||||
continue;
|
||||
}
|
||||
rcmd_execute(RcmdBuffer.cmd, RcmdBuffer.cmdLen);
|
||||
}
|
||||
|
||||
delay(2); // yield to CPU
|
||||
} // rcmd_process()
|
||||
|
||||
// enqueue remote command
|
||||
void IRAM_ATTR rcommand(const uint8_t *cmd, const size_t cmdlength) {
|
||||
|
||||
RcmdBuffer_t rcmd = {0};
|
||||
|
||||
rcmd.cmdLen = cmdlength;
|
||||
memcpy(rcmd.cmd, cmd, cmdlength);
|
||||
|
||||
if (xQueueSendToBack(RcmdQueue, (void *)&rcmd, (TickType_t)0) != pdTRUE)
|
||||
ESP_LOGW(TAG, "Remote command queue is full");
|
||||
} // rcommand()
|
||||
|
||||
void rcmd_queuereset(void) { xQueueReset(RcmdQueue); }
|
||||
|
||||
uint32_t rcmd_queuewaiting(void) { return uxQueueMessagesWaiting(RcmdQueue); }
|
||||
|
||||
void rcmd_deinit(void) {
|
||||
rcmd_queuereset();
|
||||
vTaskDelete(rcmdTask);
|
||||
}
|
||||
|
||||
esp_err_t rcmd_init(void) {
|
||||
|
||||
_ASSERT(RCMD_QUEUE_SIZE > 0);
|
||||
RcmdQueue = xQueueCreate(RCMD_QUEUE_SIZE, sizeof(RcmdBuffer_t));
|
||||
if (RcmdQueue == 0) {
|
||||
ESP_LOGE(TAG, "Could not create rcommand send queue. Aborting.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
ESP_LOGI(TAG, "Rcommand send queue created, size %d Bytes",
|
||||
RCMD_QUEUE_SIZE * sizeof(RcmdBuffer_t));
|
||||
|
||||
xTaskCreatePinnedToCore(rcmd_process, // task function
|
||||
"rcmdloop", // name of task
|
||||
3072, // stack size of task
|
||||
(void *)1, // parameter of the task
|
||||
1, // priority of the task
|
||||
&rcmdTask, // task handle
|
||||
1); // CPU core
|
||||
|
||||
return ESP_OK;
|
||||
} // rcmd_init()
|
101
src/reset.cpp
101
src/reset.cpp
@ -9,7 +9,7 @@ static const char TAG[] = __FILE__;
|
||||
#define uS_TO_S_FACTOR 1000000ULL
|
||||
|
||||
// variables keep its values after a wakeup from sleep
|
||||
RTC_DATA_ATTR runmode_t RTC_runmode = RUNMODE_POWERCYCLE;
|
||||
RTC_NOINIT_ATTR runmode_t RTC_runmode = RUNMODE_POWERCYCLE;
|
||||
RTC_DATA_ATTR struct timeval RTC_sleep_start_time;
|
||||
RTC_DATA_ATTR unsigned long long RTC_millis = 0;
|
||||
timeval sleep_stop_time;
|
||||
@ -36,14 +36,19 @@ void do_after_reset(void) {
|
||||
struct timeval sleep_stop_time;
|
||||
uint64_t sleep_time_ms;
|
||||
|
||||
switch (esp_sleep_get_wakeup_cause()) {
|
||||
case ESP_SLEEP_WAKEUP_EXT0: // Wakeup caused by external signal using RTC_IO
|
||||
case ESP_SLEEP_WAKEUP_EXT1: // Wakeup caused by external signal using
|
||||
// RTC_CNTL
|
||||
case ESP_SLEEP_WAKEUP_TIMER: // Wakeup caused by timer
|
||||
case ESP_SLEEP_WAKEUP_TOUCHPAD: // Wakeup caused by touchpad
|
||||
case ESP_SLEEP_WAKEUP_ULP: // Wakeup caused by ULP program
|
||||
switch (rtc_get_reset_reason(0)) {
|
||||
|
||||
case POWERON_RESET: // 0x01 Vbat power on reset
|
||||
case RTCWDT_BROWN_OUT_RESET: // 0x0f Reset when the vdd voltage is not
|
||||
// stable
|
||||
RTC_runmode = RUNMODE_POWERCYCLE;
|
||||
break;
|
||||
|
||||
case SW_CPU_RESET: // 0x0c Software reset CPU
|
||||
// keep previous runmode (could be RUNMODE_UPDATE)
|
||||
break;
|
||||
|
||||
case DEEPSLEEP_RESET: // 0x05 Deep Sleep reset digital core
|
||||
// calculate time spent in deep sleep
|
||||
gettimeofday(&sleep_stop_time, NULL);
|
||||
sleep_time_ms =
|
||||
@ -51,48 +56,46 @@ void do_after_reset(void) {
|
||||
(sleep_stop_time.tv_usec - RTC_sleep_start_time.tv_usec) / 1000;
|
||||
ESP_LOGI(TAG, "Time spent in deep sleep: %d ms", sleep_time_ms);
|
||||
RTC_millis += sleep_time_ms; // increment system monotonic time
|
||||
|
||||
RTC_runmode = RUNMODE_WAKEUP;
|
||||
// set wakeup state, not if we have pending OTA update
|
||||
if (RTC_runmode == RUNMODE_SLEEP)
|
||||
RTC_runmode = RUNMODE_WAKEUP;
|
||||
break;
|
||||
|
||||
case ESP_SLEEP_WAKEUP_ALL:
|
||||
case ESP_SLEEP_WAKEUP_GPIO:
|
||||
case ESP_SLEEP_WAKEUP_UART:
|
||||
case ESP_SLEEP_WAKEUP_UNDEFINED:
|
||||
case SW_RESET: // 0x03 Software reset digital core
|
||||
case OWDT_RESET: // 0x04 Legacy watch dog reset digital core
|
||||
case SDIO_RESET: // 0x06 Reset by SLC module, reset digital core
|
||||
case TG0WDT_SYS_RESET: // 0x07 Timer Group0 Watch dog reset digital core
|
||||
case TG1WDT_SYS_RESET: // 0x08 Timer Group1 Watch dog reset digital core
|
||||
case RTCWDT_SYS_RESET: // 0x09 RTC Watch dog Reset digital core
|
||||
case INTRUSION_RESET: // 0x0a Instrusion tested to reset CPU
|
||||
case TGWDT_CPU_RESET: // 0x0b Time Group reset CPU
|
||||
case RTCWDT_CPU_RESET: // 0x0d RTC Watch dog Reset CPU
|
||||
case EXT_CPU_RESET: // 0x0e for APP CPU, reseted by PRO CPU
|
||||
case RTCWDT_RTC_RESET: // 0x10 RTC Watch dog reset digital core and rtc mode
|
||||
default:
|
||||
// not a deep sleep reset
|
||||
RTC_runmode = RUNMODE_POWERCYCLE;
|
||||
break;
|
||||
} // switch
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Starting Software v%s, runmode %s", PROGVERSION,
|
||||
runmode[RTC_runmode]);
|
||||
}
|
||||
|
||||
void enter_deepsleep(const uint64_t wakeup_sec = 60,
|
||||
gpio_num_t wakeup_gpio = GPIO_NUM_MAX) {
|
||||
void enter_deepsleep(const uint64_t wakeup_sec, gpio_num_t wakeup_gpio) {
|
||||
|
||||
#if (HAS_LORA)
|
||||
if (!LMIC.devaddr) {
|
||||
ESP_LOGI(TAG, "Can't go to sleep while joining");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
ESP_LOGI(TAG, "Preparing to sleep...");
|
||||
|
||||
RTC_runmode = RUNMODE_SLEEP;
|
||||
int i;
|
||||
|
||||
// validate wake up pin, if we have
|
||||
if (!GPIO_IS_VALID_GPIO(wakeup_gpio))
|
||||
wakeup_gpio = GPIO_NUM_MAX;
|
||||
|
||||
ESP_LOGI(TAG, "Preparing to sleep...");
|
||||
|
||||
RTC_runmode = RUNMODE_SLEEP;
|
||||
|
||||
// stop further enqueuing of senddata and MAC processing
|
||||
sendTimer.detach();
|
||||
|
||||
// switch off radio
|
||||
// switch off radio and other power consuming hardware
|
||||
#if (WIFICOUNTER)
|
||||
switch_wifi_sniffer(0);
|
||||
#endif
|
||||
@ -100,6 +103,9 @@ void enter_deepsleep(const uint64_t wakeup_sec = 60,
|
||||
stop_BLEscan();
|
||||
btStop();
|
||||
#endif
|
||||
#if (HAS_SDS011)
|
||||
sds011_sleep(void);
|
||||
#endif
|
||||
|
||||
// stop MAC processing
|
||||
vTaskDelete(macProcessTask);
|
||||
@ -109,27 +115,22 @@ void enter_deepsleep(const uint64_t wakeup_sec = 60,
|
||||
|
||||
// wait a while (max 100 sec) to clear send queues
|
||||
ESP_LOGI(TAG, "Waiting until send queues are empty...");
|
||||
for (i = 10; i > 0; i--) {
|
||||
if (!allQueuesEmtpy())
|
||||
vTaskDelay(pdMS_TO_TICKS(10000));
|
||||
else
|
||||
for (i = 100; i > 0; i--) {
|
||||
if (allQueuesEmtpy())
|
||||
break;
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
if (i == 0)
|
||||
goto Error;
|
||||
|
||||
// shutdown LMIC safely, waiting max 100 sec
|
||||
// shutdown LMIC safely, waiting max 100 sec
|
||||
#if (HAS_LORA)
|
||||
ESP_LOGI(TAG, "Waiting until LMIC is idle...");
|
||||
for (i = 10; i > 0; i--) {
|
||||
for (i = 100; i > 0; i--) {
|
||||
if ((LMIC.opmode & OP_TXRXPEND) ||
|
||||
os_queryTimeCriticalJobs(sec2osticks(wakeup_sec)))
|
||||
vTaskDelay(pdMS_TO_TICKS(10000));
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (i == 0)
|
||||
goto Error;
|
||||
#endif // (HAS_LORA)
|
||||
|
||||
// shutdown MQTT safely
|
||||
@ -142,17 +143,7 @@ void enter_deepsleep(const uint64_t wakeup_sec = 60,
|
||||
spi_deinit();
|
||||
#endif
|
||||
|
||||
// wait until rcommands are all done
|
||||
for (i = 10; i > 0; i--) {
|
||||
if (rcmd_busy)
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (i == 0)
|
||||
goto Error;
|
||||
|
||||
// save LMIC state to RTC RAM
|
||||
// save LMIC state to RTC RAM
|
||||
#if (HAS_LORA)
|
||||
SaveLMICToRTC(wakeup_sec);
|
||||
#endif // (HAS_LORA)
|
||||
@ -162,9 +153,11 @@ void enter_deepsleep(const uint64_t wakeup_sec = 60,
|
||||
dp_shutdown();
|
||||
#endif
|
||||
|
||||
// reduce power if has PMU
|
||||
// reduce power if has PMU or VEXT
|
||||
#ifdef HAS_PMU
|
||||
AXP192_power(pmu_power_sleep);
|
||||
#elif EXT_POWER_SW
|
||||
digitalWrite(EXT_POWER_SW, EXT_POWER_OFF);
|
||||
#endif
|
||||
|
||||
// shutdown i2c bus
|
||||
@ -189,10 +182,6 @@ void enter_deepsleep(const uint64_t wakeup_sec = 60,
|
||||
RTC_millis += millis();
|
||||
ESP_LOGI(TAG, "Going to sleep, good bye.");
|
||||
esp_deep_sleep_start();
|
||||
|
||||
Error:
|
||||
ESP_LOGE(TAG, "Can't go to sleep. Resetting.");
|
||||
do_reset(true);
|
||||
}
|
||||
|
||||
unsigned long long uptime() { return (RTC_millis + millis()); }
|
@ -4,7 +4,7 @@
|
||||
Ticker sendTimer;
|
||||
|
||||
void setSendIRQ() {
|
||||
xTaskNotifyFromISR(irqHandlerTask, SENDCYCLE_IRQ, eSetBits, NULL);
|
||||
xTaskNotify(irqHandlerTask, SENDCYCLE_IRQ, eSetBits);
|
||||
}
|
||||
|
||||
// put data to send in RTos Queues used for transmit over channels Lora and SPI
|
||||
@ -12,8 +12,7 @@ void SendPayload(uint8_t port) {
|
||||
|
||||
ESP_LOGD(TAG, "sending Payload for Port %d", port);
|
||||
|
||||
MessageBuffer_t
|
||||
SendBuffer; // contains MessageSize, MessagePort, Message[]
|
||||
MessageBuffer_t SendBuffer; // contains MessageSize, MessagePort, Message[]
|
||||
|
||||
SendBuffer.MessageSize = payload.getSize();
|
||||
|
||||
@ -115,7 +114,6 @@ void sendData() {
|
||||
// clear counter if not in cumulative counter mode
|
||||
if (cfg.countermode != 1) {
|
||||
reset_counters(); // clear macs container and reset all counters
|
||||
get_salt(); // get new salt for salting hashes
|
||||
ESP_LOGI(TAG, "Counter cleared");
|
||||
}
|
||||
#ifdef HAS_DISPLAY
|
||||
@ -191,6 +189,7 @@ void sendData() {
|
||||
} // sendData()
|
||||
|
||||
void flushQueues(void) {
|
||||
rcmd_queuereset();
|
||||
#if (HAS_LORA)
|
||||
lora_queuereset();
|
||||
#endif
|
||||
@ -203,7 +202,7 @@ void flushQueues(void) {
|
||||
}
|
||||
|
||||
bool allQueuesEmtpy(void) {
|
||||
uint32_t rc = 0;
|
||||
uint32_t rc = rcmd_queuewaiting();
|
||||
#if (HAS_LORA)
|
||||
rc += lora_queuewaiting();
|
||||
#endif
|
||||
|
@ -43,7 +43,7 @@ static const char TAG[] = __FILE__;
|
||||
DMA_ATTR uint8_t txbuf[BUFFER_SIZE];
|
||||
DMA_ATTR uint8_t rxbuf[BUFFER_SIZE];
|
||||
|
||||
QueueHandle_t SPISendQueue;
|
||||
static QueueHandle_t SPISendQueue;
|
||||
|
||||
TaskHandle_t spiTask;
|
||||
|
||||
|
@ -109,8 +109,9 @@ void IRAM_ATTR setMyTime(uint32_t t_sec, uint16_t t_msec,
|
||||
_seconds(), timeSetSymbols[mytimesource]);
|
||||
} else {
|
||||
timesyncer.attach(TIME_SYNC_INTERVAL_RETRY * 60, setTimeSyncIRQ);
|
||||
ESP_LOGD(TAG, "[%0.3f] Timesync failed, invalid time fetched | source: %c",
|
||||
_seconds(), timeSetSymbols[mytimesource]);
|
||||
time_t unix_sec_at_compilation = compiledUTC();
|
||||
ESP_LOGD(TAG, "[%0.3f] Failed to synchronise time from source %c | unix sec obtained from source: %d | unix sec at program compilation: %d",
|
||||
_seconds(), timeSetSymbols[mytimesource], time_to_set, unix_sec_at_compilation);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user