Merge branch 'master' into feature/be-more-verbose-when-LoRa-TX-not-successful

This commit is contained in:
Verkehrsrot 2023-04-28 18:30:23 +02:00 committed by GitHub
commit fb1f46e892
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 161 additions and 89 deletions

View File

@ -86,7 +86,11 @@ Supported external time sources are GPS, LORAWAN network time and LORAWAN applic
!!! tip
If your LORAWAN network does not support network time, you can run a Node-Red timeserver application using the enclosed [**Timeserver code**](https://github.com/cyberman54/ESP32-Paxcounter/blob/master/src/Node-RED/Timeserver.json). Configure the MQTT nodes in Node-Red for the LORAWAN application used by your paxocunter device. Time can also be set without precision liability, by simple remote command, see section remote control.
If your LORAWAN network does not support network time, you can run a Node-Red timeserver application using the enclosed [**Timeserver code**](https://github.com/cyberman54/ESP32-Paxcounter/blob/master/src/Node-RED/Timeserver.json). Configure the MQTT nodes in Node-Red for the LORAWAN application used by your paxcounter device. Time can also be set without precision liability, by simple remote command, see section remote control.
## Syncing multiple paxcounters
A fleet of paxcounters can be synchronized to keep all devices wake up and start scanning at the same time. Synchronization is based on top-of-hour as common time point of reference. This feature requires time-of-day to be present on each device. Thus, `TIME_SYNC_INTERVAL` option, as explained above, must be enabled. Wake up syncing is enabled by setting `SYNCWAKEUP` in `paxcounter.conf` to a value X, in seconds, greater than zero, and smaller than `SLEEPCYCLE` (in seconds/10). This defines a time window, centered at top-of-hour, sized +/- X seconds. If a device, returning from sleep, would wakeup within this time window, it's wakeup will be adjusted to top-of-hour.
## Wall clock controller

View File

@ -7,7 +7,7 @@ You can select different payload formats in [`paxcounter.conf`](https://github.c
- ***Packed*** uses little endian format and generates json fields
- [***CayenneLPP***](https://mydevices.com/cayenne/docs/lora/#lora-cayenne-low-power-payload-reference-implementation) generates MyDevices Cayenne readable fields
- [***CayenneLPP***](https://developers.mydevices.com/cayenne/docs/lora/#lora-cayenne-low-power-payload) generates MyDevices Cayenne readable fields
```c linenums="20" title="src/paxcounter_orig.conf"

View File

@ -91,6 +91,11 @@ Send for example `83` `86` as Downlink on Port 2 to get battery status and time/
0 ... 255 duration for scanning a bluetooth advertising channel in seconds/100
e.g. 8 -> each channel is scanned for 80 milliseconds [default]
#### 0x0D set wakeup sync window
bytes 1..2 = wakeup sync window size in seconds (MSB), 0..255 (0 = no wakuep sync)
e.g. {0x02, 0x58} -> device adjusts it's wakeup time when it is +/- 5 minutes from top-of-hour [default = 0]
#### 0x0E set Bluetooth scanner
0 = disabled
@ -106,6 +111,11 @@ Send for example `83` `86` as Downlink on Port 2 to get battery status and time/
0 ... 100 percentage of luminosity (100% = full light)
e.g. 50 -> 50% of luminosity [default]
#### 0x11 set Wifi scanner channel map bitmask
bytes 1..2 = wifi channel map bitmask (MSB), 0..8191
e.g. 0b1010000001001 sets channels 1, 4, 11, 13
#### 0x13 set user sensor mode
byte 1 = user sensor number (1..3)

View File

@ -64,7 +64,9 @@ typedef struct __attribute__((packed)) {
int16_t rssilimit; // threshold for rssilimiter, negative value!
uint8_t sendcycle; // payload send cycle [seconds/2]
uint16_t sleepcycle; // sleep cycle [seconds/10]
uint16_t wakesync; // time window [seconds] to sync wakeup on top-of-hour
uint8_t wifichancycle; // wifi channel switch cycle [seconds/100]
uint16_t wifichanmap; // wifi channel hopping scheme
uint8_t blescantime; // BLE scan cycle duration [seconds]
uint8_t blescan; // 0=disabled, 1=enabled
uint8_t wifiscan; // 0=disabled, 1=enabled
@ -109,6 +111,6 @@ typedef struct {
float pm25;
} sdsStatus_t;
extern char clientId[20]; // unique clientID
extern char clientId[20]; // unique clientID
#endif

View File

@ -14,8 +14,8 @@
void reset_rtc_vars(void);
void do_reset(bool warmstart);
void do_after_reset(void);
void enter_deepsleep(const uint32_t wakeup_sec, const gpio_num_t wakeup_gpio);
unsigned long long uptime(void);
void enter_deepsleep(uint32_t wakeup_sec, const gpio_num_t wakeup_gpio);
uint64_t uptime(void);
enum runmode_t {
RUNMODE_POWERCYCLE,

View File

@ -15,7 +15,7 @@ void sendData(void);
void checkSendQueues(void);
void flushQueues(void);
bool allQueuesEmtpy(void);
void setSendIRQ(TimerHandle_t xTimer);
//void setSendIRQ(TimerHandle_t xTimer);
void setSendIRQ(void);
#endif // _SENDDATA_H_

View File

@ -12,6 +12,7 @@
#define HAS_LORA_TIME \
((HAS_LORA) && ((TIME_SYNC_LORASERVER) || (TIME_SYNC_LORAWAN)))
#define HAS_TIME (TIME_SYNC_INTERVAL) && (HAS_LORA_TIME || HAS_GPS)
#define SECS_YR_2000 (946684800UL) // the time at the start of y2k
#define GPS_UTC_DIFF 315964800UL // seconds diff between gps and utc epoch

View File

@ -47,7 +47,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 = 3.4.62
release_version = 3.5.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,13 +55,13 @@ extra_scripts = pre:src/build.py
otakeyfile = ota.conf
lorakeyfile = loraconf.h
lmicconfigfile = lmic_config.h
platform_espressif32 = espressif32@6.0.0
platform_espressif32 = espressif32@6.0.1
monitor_speed = 115200
upload_speed = 115200 ; set by build.py and taken from hal file
lib_deps_lora =
mcci-catena/MCCI LoRaWAN LMIC library @ ^4.1.1
lib_deps_display =
bitbank2/OneBitDisplay @ ^2.3.0
bitbank2/OneBitDisplay @ ^2.3.1
bitbank2/bb_spi_lcd @ ^2.4.1
ricmoo/QRCode @ ^0.0.1
lib_deps_ledmatrix =
@ -71,19 +71,19 @@ lib_deps_rgbled =
lib_deps_gps =
mikalhart/TinyGPSPlus @ ^1.0.3
lib_deps_sensors =
adafruit/Adafruit Unified Sensor @ ^1.1.7
adafruit/Adafruit Unified Sensor @ ^1.1.9
adafruit/Adafruit BME280 Library @ ^2.2.2
adafruit/Adafruit BMP085 Library @ ^1.2.2
boschsensortec/BSEC Software Library @ 1.6.1480
boschsensortec/BSEC Software Library @ 1.8.1492
lewapek/Nova Fitness Sds dust sensors library @ ^1.5.1
lib_deps_basic =
greyrook/libpax @ ^1.1.0
https://github.com/SukkoPera/Arduino-Rokkit-Hash.git
bblanchon/ArduinoJson @ ^6.20.0
makuna/RTC @ ^2.3.5
bblanchon/ArduinoJson @ ^6.21.2
makuna/RTC @ ^2.3.7
mathertel/OneButton @ ^2.0.3
lewisxhe/XPowersLib @ ^0.1.5
256dpi/MQTT @ ^2.5.0
256dpi/MQTT @ ^2.5.1
lib_deps_all =
${common.lib_deps_basic}
${common.lib_deps_lora}

View File

@ -10,7 +10,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 = 3.4.62
release_version = 3.5.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
@ -18,7 +18,7 @@ extra_scripts = pre:src/build.py
otakeyfile = ota.conf
lorakeyfile = loraconf.h
lmicconfigfile = lmic_config.h
platform_espressif32 = espressif32@6.0.0
platform_espressif32 = espressif32@6.0.1
monitor_speed = 115200
upload_speed = 115200 ; set by build.py and taken from hal file
lib_deps_all =
@ -27,9 +27,9 @@ lib_deps_all =
fastled/FastLED @ ^3.5.0
greyrook/libpax @ ^1.1.0
https://github.com/SukkoPera/Arduino-Rokkit-Hash.git
bblanchon/ArduinoJson @ ^6.20.0
bblanchon/ArduinoJson @ ^6.21.2
mathertel/OneButton @ ^2.0.3
256dpi/MQTT @ ^2.5.0
256dpi/MQTT @ ^2.5.1
ricmoo/QRCode @ ^0.0.1
build_flags_basic =
-include "src/paxcounter.conf"

View File

@ -82,20 +82,20 @@ int bme_init(void) {
int checkIaqSensorStatus(void) {
int rslt = 1; // true = 1 = no error, false = 0 = error
if (iaqSensor.status != BSEC_OK) {
if (iaqSensor.bsecStatus != BSEC_OK) {
rslt = 0;
if (iaqSensor.status < BSEC_OK)
ESP_LOGE(TAG, "BSEC error %d", iaqSensor.status);
if (iaqSensor.bsecStatus < BSEC_OK)
ESP_LOGE(TAG, "BSEC error %d", iaqSensor.bsecStatus);
else
ESP_LOGW(TAG, "BSEC warning %d", iaqSensor.status);
ESP_LOGW(TAG, "BSEC warning %d", iaqSensor.bsecStatus);
}
if (iaqSensor.bme680Status != BME680_OK) {
if (iaqSensor.bme68xStatus != BME68X_OK) {
rslt = 0;
if (iaqSensor.bme680Status < BME680_OK)
ESP_LOGE(TAG, "BME680 error %d", iaqSensor.bme680Status);
if (iaqSensor.bme68xStatus < BME68X_OK)
ESP_LOGE(TAG, "BME680 error %d", iaqSensor.bme68xStatus);
else
ESP_LOGW(TAG, "BME680 warning %d", iaqSensor.bme680Status);
ESP_LOGW(TAG, "BME680 warning %d", iaqSensor.bme68xStatus);
}
return rslt;

View File

@ -3,7 +3,6 @@
#include "globals.h"
#include "configmanager.h"
// namespace for device runtime preferences
#define DEVCONFIG "paxcntcfg"
@ -38,8 +37,10 @@ static void defaultConfig(configData_t *myconfig) {
myconfig->rssilimit = RSSILIMIT; // threshold for rssilimiter, negative value!
myconfig->sendcycle = SENDCYCLE; // payload send cycle [seconds/2]
myconfig->sleepcycle = SLEEPCYCLE; // sleep cycle [seconds/10]
myconfig->wakesync = SYNCWAKEUP; // wakeup sync window [seconds]
myconfig->wifichancycle =
WIFI_CHANNEL_SWITCH_INTERVAL; // wifi channel switch cycle [seconds/100]
myconfig->wifichanmap = WIFI_CHANNEL_MAP; // wifi channel hopping scheme
myconfig->blescantime =
BLESCANINTERVAL /
10; // BT channel scan cycle [seconds/100], default 1 (= 10ms)

View File

@ -37,7 +37,6 @@ MY_FONT_LARGE: 16x32px = 8 chars / line @ 2 lines
#include "globals.h"
#include "display.h"
static uint8_t plotbuf[PLOTBUFFERSIZE] = {0};
uint8_t DisplayIsOn = 0;
hw_timer_t *displayIRQ = NULL;
@ -374,7 +373,7 @@ void dp_refresh(bool nextPage) {
#ifdef HAS_BUTTON
dp_clear();
break;
#else // skip this page
#else // skip this page and start over
DisplayPage = 0;
break;
#endif

View File

@ -37,7 +37,7 @@
// BME680 sensor on I2C bus
#define HAS_BME 1 // Enable BME sensors in general
#define HAS_BME680 GPIO_NUM_21, GPIO_NUM_22 // SDA, SCL
#define BME680_ADDR BME680_I2C_ADDR_PRIMARY // connect SDIO of BME680 to GND
#define BME680_ADDR BME68X_I2C_ADDR_LOW // connect SDIO of BME680 to GND
// BME280 sensor on I2C bus
//#define HAS_BME 1 // Enable BME sensors in general

View File

@ -18,7 +18,7 @@
// Octopus32 has a pre-populated BME680 on i2c addr 0x76
#define HAS_BME 1 // Enable BME sensors in general
#define HAS_BME680 GPIO_NUM_23, GPIO_NUM_22 // SDA, SCL
#define BME680_ADDR BME680_I2C_ADDR_PRIMARY // connect SDIO of BME680 to GND
#define BME680_ADDR BME68X_I2C_ADDR_LOW // connect SDIO of BME680 to GND
#define HAS_LED 13 // ESP32 GPIO12 (pin22) On Board LED
//#define LED_ACTIVE_LOW 1 // Onboard LED is active when pin is LOW

View File

@ -30,7 +30,7 @@
// BME680 sensor on I2C bus
//#define HAS_BME 1 // Enable BME sensors in general
//#define HAS_BME680 SDA, SCL
//#define BME680_ADDR BME680_I2C_ADDR_PRIMARY // !! connect SDIO of BME680 to GND !!
//#define BME680_ADDR BME68X_I2C_ADDR_LOW // !! connect SDIO of BME680 to GND !!
// display (if connected)
//#define HAS_DISPLAY 1

View File

@ -52,7 +52,7 @@ Reset -> reset device
// BME680 sensor on I2C bus
//#define HAS_BME 1 // Enable BME sensors in general
//#define HAS_BME680 SDA, SCL
//#define BME680_ADDR BME680_I2C_ADDR_PRIMARY // !! connect SDIO of BME680 to GND !!
//#define BME680_ADDR BME68X_I2C_ADDR_LOW // !! connect SDIO of BME680 to GND !!
//#define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature

View File

@ -71,7 +71,7 @@ PMUIRQ <- GPIO <- PMU chip
Application IRQs fired by software:
TIMESYNC_IRQ <- setTimeSyncIRQ() <- Ticker.h
CYCLIC_IRQ <- setCyclicIRQ() <- Ticker.h
SENDCYCLE_IRQ <- setSendIRQ() <- xTimer or libpax callback
SENDCYCLE_IRQ <- setSendIRQ() <- libpax callback
BME_IRQ <- setBMEIRQ() <- Ticker.h
*/
@ -282,7 +282,7 @@ void setup() {
// configure WIFI sniffing
strcpy(configuration.wifi_my_country_str, WIFI_MY_COUNTRY);
configuration.wificounter = cfg.wifiscan;
configuration.wifi_channel_map = WIFI_CHANNEL_ALL;
configuration.wifi_channel_map = cfg.wifichanmap;
configuration.wifi_channel_switch_interval = cfg.wifichancycle;
configuration.wifi_rssi_threshold = cfg.rssilimit;
ESP_LOGI(TAG, "WIFISCAN: %s", cfg.wifiscan ? "on" : "off");
@ -456,7 +456,7 @@ void setup() {
#endif // HAS_BUTTON
// only if we have a timesource we do timesync
#if ((HAS_LORA_TIME) || (HAS_GPS) || (HAS_RTC))
#if ((HAS_LORA_TIME) || (HAS_GPS) || defined HAS_RTC)
time_init();
strcat_P(features, " TIME");
#endif // timesync

View File

@ -20,6 +20,7 @@
#define SLEEPCYCLE 0 // sleep time after a send cycle [seconds/10], 0 .. 65535; 0 means no sleep [default = 0]
#define PAYLOAD_ENCODER 2 // payload encoder: 1=Plain, 2=Packed, 3=Cayenne LPP dynamic, 4=Cayenne LPP packed
#define COUNTERMODE 0 // 0=cyclic, 1=cumulative, 2=cyclic confirmed
#define SYNCWAKEUP 300 // shifts sleep wakeup to top-of-hour, when +/- X seconds off [0=off]
// default settings for transmission of sensor data (first list = data on / second line = data off)
#define PAYLOADMASK \
@ -52,6 +53,7 @@
// WiFi scan parameters
#define WIFI_MY_COUNTRY "01" // select 2-letter locale for Wifi RF settings, e.g. "DE"; use "01" for world safe mode
#define WIFI_CHANNEL_SWITCH_INTERVAL 50 // [seconds/100] -> 0,5 sec.
#define WIFI_CHANNEL_MAP WIFI_CHANNEL_ALL // possible values see libpax_api.h
// LoRa payload default parameters
#define MEM_LOW 2048 // [Bytes] low memory threshold triggering a send cycle

View File

@ -44,6 +44,7 @@ void PayloadConvert::addConfig(configData_t value) {
buffer[cursor++] = lowByte(value.rssilimit);
buffer[cursor++] = value.sendcycle;
buffer[cursor++] = value.wifichancycle;
//buffer[cursor++] = value.wifichanmap;
buffer[cursor++] = value.blescantime;
buffer[cursor++] = value.blescan;
buffer[cursor++] = value.wifiant;
@ -170,6 +171,7 @@ void PayloadConvert::addConfig(configData_t value) {
writeUint16(value.rssilimit);
writeUint8(value.sendcycle);
writeUint8(value.wifichancycle);
//writeUint8(value.wifichanmap);
writeUint8(value.blescantime);
writeUint16(value.sleepcycle);
writeBitmap(value.adrmode ? true : false, value.screensaver ? true : false,

View File

@ -2,7 +2,6 @@
#include "globals.h"
#include "rcommand.h"
static QueueHandle_t RcmdQueue;
TaskHandle_t rcmdTask;
@ -59,7 +58,7 @@ void set_rssi(uint8_t val[]) {
current_config.ble_rssi_threshold = cfg.rssilimit;
libpax_update_config(&current_config);
init_libpax();
ESP_LOGI(TAG, "Remote command: set RSSI limit to %d", cfg.rssilimit);
ESP_LOGI(TAG, "Remote command: set RSSI limit to %hd", cfg.rssilimit);
}
void set_sendcycle(uint8_t val[]) {
@ -67,7 +66,7 @@ void set_sendcycle(uint8_t val[]) {
return;
// update send cycle interrupt [seconds / 2]
cfg.sendcycle = val[0];
ESP_LOGI(TAG, "Remote command: set send cycle to %d seconds",
ESP_LOGI(TAG, "Remote command: set send cycle to %u seconds",
cfg.sendcycle * 2);
libpax_counter_stop();
init_libpax();
@ -76,10 +75,16 @@ void set_sendcycle(uint8_t val[]) {
void set_sleepcycle(uint8_t val[]) {
// swap byte order from msb to lsb, note: this is a platform dependent hack
cfg.sleepcycle = __builtin_bswap16(*(uint16_t *)(val));
ESP_LOGI(TAG, "Remote command: set sleep cycle to %d seconds",
ESP_LOGI(TAG, "Remote command: set sleep cycle to %hu seconds",
cfg.sleepcycle * 10);
}
void set_wakesync(uint8_t val[]) {
// swap byte order from msb to lsb, note: this is a platform dependent hack
cfg.wakesync = __builtin_bswap16(*(uint16_t *)(val));
ESP_LOGI(TAG, "Remote command: set wakesync to %hu seconds", cfg.wakesync);
}
void set_wifichancycle(uint8_t val[]) {
cfg.wifichancycle = val[0];
libpax_counter_stop();
@ -101,6 +106,17 @@ void set_wifichancycle(uint8_t val[]) {
init_libpax();
}
void set_wifichanmap(uint8_t val[]) {
// swap byte order from msb to lsb, note: this is a platform dependent hack
cfg.wifichanmap = __builtin_bswap16(*(uint16_t *)(val));
libpax_counter_stop();
libpax_config_t current_config;
libpax_get_current_config(&current_config);
current_config.wifi_channel_map = cfg.wifichanmap;
libpax_update_config(&current_config);
init_libpax();
}
void set_blescantime(uint8_t val[]) {
cfg.blescantime = val[0];
libpax_counter_stop();
@ -193,7 +209,7 @@ void set_sensor(uint8_t val[]) {
return; // invalid sensor number -> exit
}
ESP_LOGI(TAG, "Remote command: set sensor #%d mode to %s", val[0],
ESP_LOGI(TAG, "Remote command: set sensor #%u mode to %s", val[0],
val[1] ? "on" : "off");
if (val[1])
@ -213,7 +229,7 @@ void set_loradr(uint8_t val[]) {
#if (HAS_LORA)
if (validDR(val[0])) {
cfg.loradr = val[0];
ESP_LOGI(TAG, "Remote command: set LoRa Datarate to %d", cfg.loradr);
ESP_LOGI(TAG, "Remote command: set LoRa Datarate to %u", cfg.loradr);
LMIC_setDrTxpow(assertDR(cfg.loradr), KEEP_TXPOW);
ESP_LOGI(TAG, "Radio parameters now %s / %s / %s",
getSfName(updr2rps(LMIC.datarate)),
@ -222,7 +238,7 @@ void set_loradr(uint8_t val[]) {
} else
ESP_LOGI(
TAG,
"Remote command: set LoRa Datarate called with illegal datarate %d",
"Remote command: set LoRa Datarate called with illegal datarate %u",
val[0]);
#else
ESP_LOGW(TAG, "Remote command: LoRa not implemented");
@ -275,15 +291,15 @@ void set_wifiant(uint8_t val[]) {
void set_rgblum(uint8_t val[]) {
// Avoid wrong parameters
cfg.rgblum = (val[0] <= 100) ? (uint8_t)val[0] : RGBLUMINOSITY;
ESP_LOGI(TAG, "Remote command: set RGB Led luminosity %d", cfg.rgblum);
};
ESP_LOGI(TAG, "Remote command: set RGB Led luminosity %u", cfg.rgblum);
}
void set_lorapower(uint8_t val[]) {
#if (HAS_LORA)
// set data rate and transmit power only if we have no ADR
if (!cfg.adrmode) {
cfg.txpower = val[0];
ESP_LOGI(TAG, "Remote command: set LoRa TXPOWER to %d", cfg.txpower);
ESP_LOGI(TAG, "Remote command: set LoRa TXPOWER to %u", cfg.txpower);
LMIC_setDrTxpow(assertDR(cfg.loradr), cfg.txpower);
} else
ESP_LOGI(
@ -293,14 +309,14 @@ void set_lorapower(uint8_t val[]) {
#else
ESP_LOGW(TAG, "Remote command: LoRa not implemented");
#endif // HAS_LORA
};
}
void get_config(uint8_t val[]) {
ESP_LOGI(TAG, "Remote command: get device configuration");
payload.reset();
payload.addConfig(cfg);
SendPayload(CONFIGPORT);
};
}
void get_status(uint8_t val[]) {
ESP_LOGI(TAG, "Remote command: get device status");
@ -315,7 +331,7 @@ void get_status(uint8_t val[]) {
RTC_restarts);
#endif
SendPayload(STATUSPORT);
};
}
void get_gps(uint8_t val[]) {
ESP_LOGI(TAG, "Remote command: get gps status");
@ -328,7 +344,7 @@ void get_gps(uint8_t val[]) {
#else
ESP_LOGW(TAG, "GPS function not supported");
#endif
};
}
void get_bme(uint8_t val[]) {
ESP_LOGI(TAG, "Remote command: get bme680 sensor data");
@ -339,7 +355,7 @@ void get_bme(uint8_t val[]) {
#else
ESP_LOGW(TAG, "BME sensor not supported");
#endif
};
}
void get_batt(uint8_t val[]) {
ESP_LOGI(TAG, "Remote command: get battery voltage");
@ -350,7 +366,7 @@ void get_batt(uint8_t val[]) {
#else
ESP_LOGW(TAG, "Battery voltage not supported");
#endif
};
}
void get_time(uint8_t val[]) {
ESP_LOGI(TAG, "Remote command: get time");
@ -359,35 +375,35 @@ void get_time(uint8_t val[]) {
payload.addTime(t);
payload.addByte(sntp_get_sync_status() << 4 | timeSource);
SendPayload(TIMEPORT);
};
}
void set_timesync(uint8_t val[]) {
ESP_LOGI(TAG, "Remote command: timesync requested");
setTimeSyncIRQ();
};
}
void set_time(uint8_t val[]) {
// swap byte order from msb to lsb, note: this is a platform dependent hack
uint32_t t = __builtin_bswap32(*(uint32_t *)(val));
ESP_LOGI(TAG, "Remote command: set time to %d", t);
ESP_LOGI(TAG, "Remote command: set time to %lu", t);
setMyTime(t, 0, _set);
};
}
void set_flush(uint8_t val[]) {
ESP_LOGI(TAG, "Remote command: flush");
// does nothing
// used to open receive window on LoRaWAN class a nodes
};
}
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, number of function arguments}
@ -399,8 +415,9 @@ static const cmd_t table[] = {
{0x07, set_loraadr, 1}, {0x08, set_screensaver, 1},
{0x09, set_reset, 1}, {0x0a, set_sendcycle, 1},
{0x0b, set_wifichancycle, 1}, {0x0c, set_blescantime, 1},
{0x0e, set_blescan, 1}, {0x0f, set_wifiant, 1},
{0x10, set_rgblum, 1}, {0x13, set_sensor, 2},
{0x0d, set_wakesync, 2}, {0x0e, set_blescan, 1},
{0x0f, set_wifiant, 1}, {0x10, set_rgblum, 1},
{0x11, set_wifichanmap, 2}, {0x13, set_sensor, 2},
{0x14, set_payloadmask, 1}, {0x15, set_bme, 1},
{0x16, set_batt, 1}, {0x17, set_wifiscan, 1},
{0x18, set_flush, 0}, {0x19, set_sleepcycle, 2},
@ -492,7 +509,7 @@ esp_err_t rcmd_init(void) {
ESP_LOGE(TAG, "Could not create rcommand send queue. Aborting.");
return ESP_FAIL;
}
ESP_LOGI(TAG, "Rcommand send queue created, size %d Bytes",
ESP_LOGI(TAG, "Rcommand send queue created, size %u Bytes",
RCMD_QUEUE_SIZE * sizeof(RcmdBuffer_t));
xTaskCreatePinnedToCore(rcmd_process, // task function

View File

@ -5,20 +5,46 @@
// Conversion factor for micro seconds to seconds
#define uS_TO_S_FACTOR 1000000ULL
// RTC_NOINIT_ATTR -> keep value after a software restart or system crash
// RTC_NOINIT_ATTR -> keeps value after a software restart or system crash
RTC_NOINIT_ATTR runmode_t RTC_runmode;
RTC_NOINIT_ATTR uint32_t RTC_restarts;
// RTC_DATA_ATTR -> keep values after a wakeup from sleep
RTC_DATA_ATTR struct timeval RTC_sleep_start_time;
RTC_DATA_ATTR unsigned long long RTC_millis = 0;
// RTC_DATA_ATTR -> keeps value after a wakeup from sleep
RTC_DATA_ATTR struct timeval sleep_start_time;
RTC_DATA_ATTR int64_t RTC_millis = 0;
timeval sleep_stop_time;
struct timeval sleep_stop_time;
void reset_rtc_vars(void) {
RTC_runmode = RUNMODE_POWERCYCLE;
RTC_restarts = 0;
}
#if (HAS_TIME)
void adjust_wakeup(uint32_t *wakeuptime) {
// only adjust wakeup if we have a valid time
if ((timeSource == _unsynced) ||
(sntp_get_sync_status() == SNTP_SYNC_STATUS_IN_PROGRESS)) {
ESP_LOGI(TAG, "Syncwakeup: No valid time for sync");
return;
}
time_t now;
time(&now);
// 1..3600 seconds between next wakeup time and following top-of-hour
uint16_t shift_sec = 3600 - (now + *wakeuptime) % 3600;
if (shift_sec <= SYNCWAKEUP) {
*wakeuptime += shift_sec; // delay wakeup to catch top-of-hour
ESP_LOGI(TAG, "Syncwakeup: Wakeup %hu sec postponed", shift_sec);
} else if (shift_sec >= (3600 - SYNCWAKEUP)) {
*wakeuptime = 3600 - shift_sec; // shorten wake up to next top-of-hour
ESP_LOGI(TAG, "Syncwakeup: Wakeup %hu sec preponed", shift_sec);
} else
ESP_LOGI(TAG, "Syncwakeup: Wakeup keeping unshifted");
}
#endif
void do_reset(bool warmstart) {
if (warmstart) {
ESP_LOGI(TAG, "restarting device (warmstart)");
@ -36,7 +62,7 @@ void do_reset(bool warmstart) {
void do_after_reset(void) {
struct timeval sleep_stop_time;
uint64_t sleep_time_ms;
int64_t sleep_time_ms;
// read (and initialize on first run) runtime settings from NVRAM
loadConfig();
@ -62,11 +88,13 @@ void do_after_reset(void) {
case RESET_REASON_CORE_DEEP_SLEEP:
// calculate time spent in deep sleep
gettimeofday(&sleep_stop_time, NULL);
sleep_time_ms =
(sleep_stop_time.tv_sec - RTC_sleep_start_time.tv_sec) * 1000 +
(sleep_stop_time.tv_usec - RTC_sleep_start_time.tv_usec) / 1000;
sleep_time_ms = ((int64_t)sleep_stop_time.tv_sec * 1000000L +
(int64_t)sleep_stop_time.tv_usec -
(int64_t)sleep_start_time.tv_sec * 1000000L -
(int64_t)sleep_start_time.tv_usec) /
1000LL;
RTC_millis += sleep_time_ms; // increment system monotonic time
ESP_LOGI(TAG, "Time spent in deep sleep: %d ms", sleep_time_ms);
ESP_LOGI(TAG, "Time spent in deep sleep: %llu ms", sleep_time_ms);
// do we have a valid time? -> set global variable
timeSource = timeIsValid(sleep_stop_time.tv_sec) ? _set : _unsynced;
// set wakeup state, not if we have pending OTA update
@ -81,7 +109,7 @@ void do_after_reset(void) {
}
}
void enter_deepsleep(const uint32_t wakeup_sec, gpio_num_t wakeup_gpio) {
void enter_deepsleep(uint32_t wakeup_sec, gpio_num_t wakeup_gpio) {
ESP_LOGI(TAG, "Preparing to sleep...");
RTC_runmode = RUNMODE_SLEEP;
@ -143,6 +171,11 @@ void enter_deepsleep(const uint32_t wakeup_sec, gpio_num_t wakeup_gpio) {
// shutdown i2c bus
i2c_deinit();
#if (HAS_TIME)
if (cfg.wakesync && cfg.sleepcycle)
adjust_wakeup(&wakeup_sec);
#endif
// configure wakeup sources
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/sleep_modes.html
@ -158,8 +191,8 @@ void enter_deepsleep(const uint32_t wakeup_sec, gpio_num_t wakeup_gpio) {
}
// time stamp sleep start time and save system monotonic time. Deep sleep.
gettimeofday(&RTC_sleep_start_time, NULL);
RTC_millis += esp_timer_get_time() / 1000;
gettimeofday(&sleep_start_time, NULL);
RTC_millis += esp_timer_get_time() / 1000LL;
ESP_LOGI(TAG, "Going to sleep, good bye.");
// flush & close sd card, if we have
@ -170,6 +203,6 @@ void enter_deepsleep(const uint32_t wakeup_sec, gpio_num_t wakeup_gpio) {
esp_deep_sleep_start();
}
unsigned long long uptime() {
return (RTC_millis + esp_timer_get_time() / 1000);
uint64_t uptime() {
return (uint64_t)(RTC_millis + esp_timer_get_time() / 1000LL);
}

View File

@ -8,7 +8,7 @@ RtcDS3231<TwoWire> Rtc(Wire); // RTC hardware i2c interface
// initialize RTC
uint8_t rtc_init(void) {
Wire.begin(HAS_RTC);
Rtc.Begin(MY_DISPLAY_SDA, MY_DISPLAY_SCL);
Rtc.Begin(HAS_RTC);
// configure RTC chip
Rtc.Enable32kHzPin(false);
@ -22,7 +22,7 @@ uint8_t rtc_init(void) {
#if (TIME_SYNC_COMPILEDATE)
// initialize a blank RTC without battery backup with build time
RtcDateTime tt = Rtc.GetDateTime();
time_t t = tt.Epoch32Time(); // sec2000 -> epoch
time_t t = tt.Unix32Time(); // sec2000 -> epoch
if (!Rtc.IsDateTimeValid() || !timeIsValid(t)) {
ESP_LOGW(TAG, "RTC has no recent time, setting to compiletime");
@ -53,7 +53,7 @@ time_t get_rtctime(uint16_t *msec) {
*msec = 0;
if (Rtc.IsDateTimeValid() && Rtc.GetIsRunning()) {
RtcDateTime tt = Rtc.GetDateTime();
t = tt.Epoch32Time(); // sec2000 -> epoch
t = tt.Unix32Time(); // sec2000 -> epoch
}
// if we have a RTC pulse, we calculate msec

View File

@ -174,8 +174,8 @@ bool sdcard_init(bool create) {
#if (HAS_SDS011)
fprintf(data_file, "%s", SDCARD_FILE_HEADER_SDS011);
#endif
fprintf(data_file, "\n");
}
fprintf(data_file, "\n");
} else {
useSDCard = false;

View File

@ -1,12 +1,13 @@
// Basic Config
#include "senddata.h"
// void setSendIRQ(TimerHandle_t xTimer) {
// xTaskNotify(irqHandlerTask, SENDCYCLE_IRQ, eSetBits);
//}
void setSendIRQ(TimerHandle_t xTimer) {
xTaskNotify(irqHandlerTask, SENDCYCLE_IRQ, eSetBits);
}
// void setSendIRQ(void) { setSendIRQ(NULL); }
void setSendIRQ(void) { setSendIRQ(NULL); }
void setSendIRQ(void) { xTaskNotify(irqHandlerTask, SENDCYCLE_IRQ, eSetBits); }
// put data to send in RTos Queues used for transmit over channels Lora and SPI
void SendPayload(uint8_t port) {

View File

@ -6,8 +6,8 @@
// symbol to display current time source
// G = GPS / R = RTC / L = LORA / * = no sync / ? = never synced
const char timeSetSymbols[] = {'G', 'R', 'L', '*', '?'};
// G = GPS / R = RTC / L = LORA / ? = unsynced / * = set
const char timeSetSymbols[] = {'G', 'R', 'L', '?', '*'};
DRAM_ATTR bool TimePulseTick = false;
#ifdef GPS_INT
@ -82,7 +82,7 @@ void calibrateTime(void) {
return;
#endif
#if ((HAS_GPS) || (HAS_RTC))
#if ((HAS_GPS) || defined HAS_RTC)
time_t t = 0;
uint16_t t_msec = 0;