Merge pull request #950 from cyberman54/development

Development
This commit is contained in:
Verkehrsrot 2023-03-12 09:31:02 +01:00 committed by GitHub
commit 2682d893a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 49 additions and 19 deletions

View File

@ -88,6 +88,10 @@ Supported external time sources are GPS, LORAWAN network time and LORAWAN applic
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. 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, greater than zero, and smaller than `SLEEPCYCLE`. 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 ## Wall clock controller
Paxcounter can be used to sync a wall clock which has a DCF77 or IF482 time telegram input. Set `#define HAS_IF482` or `#define HAS_DCF77` in board's hal file to setup clock controller. Use case of this function is to integrate paxcounter and clock. Accurary of the synthetic DCF77 signal depends on accuracy of on board's time base, see above. Paxcounter can be used to sync a wall clock which has a DCF77 or IF482 time telegram input. Set `#define HAS_IF482` or `#define HAS_DCF77` in board's hal file to setup clock controller. Use case of this function is to integrate paxcounter and clock. Accurary of the synthetic DCF77 signal depends on accuracy of on board's time base, see above.

View File

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

View File

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

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 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 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 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) // default settings for transmission of sensor data (first list = data on / second line = data off)
#define PAYLOADMASK \ #define PAYLOADMASK \

View File

@ -5,14 +5,14 @@
// Conversion factor for micro seconds to seconds // Conversion factor for micro seconds to seconds
#define uS_TO_S_FACTOR 1000000ULL #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 runmode_t RTC_runmode;
RTC_NOINIT_ATTR uint32_t RTC_restarts; RTC_NOINIT_ATTR uint32_t RTC_restarts;
// RTC_DATA_ATTR -> keep values after a wakeup from sleep // RTC_DATA_ATTR -> keeps value after a wakeup from sleep
RTC_DATA_ATTR struct timeval RTC_sleep_start_time; RTC_DATA_ATTR struct timeval sleep_start_time;
RTC_DATA_ATTR unsigned long long RTC_millis = 0; RTC_DATA_ATTR int64_t RTC_millis = 0;
timeval sleep_stop_time; struct timeval sleep_stop_time;
void reset_rtc_vars(void) { void reset_rtc_vars(void) {
RTC_runmode = RUNMODE_POWERCYCLE; RTC_runmode = RUNMODE_POWERCYCLE;
@ -36,7 +36,7 @@ void do_reset(bool warmstart) {
void do_after_reset(void) { void do_after_reset(void) {
struct timeval sleep_stop_time; 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 // read (and initialize on first run) runtime settings from NVRAM
loadConfig(); loadConfig();
@ -62,11 +62,13 @@ void do_after_reset(void) {
case RESET_REASON_CORE_DEEP_SLEEP: case RESET_REASON_CORE_DEEP_SLEEP:
// calculate time spent in deep sleep // calculate time spent in deep sleep
gettimeofday(&sleep_stop_time, NULL); gettimeofday(&sleep_stop_time, NULL);
sleep_time_ms = sleep_time_ms = ((int64_t)sleep_stop_time.tv_sec * 1000000L +
(sleep_stop_time.tv_sec - RTC_sleep_start_time.tv_sec) * 1000 + (int64_t)sleep_stop_time.tv_usec -
(sleep_stop_time.tv_usec - RTC_sleep_start_time.tv_usec) / 1000; (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 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 // do we have a valid time? -> set global variable
timeSource = timeIsValid(sleep_stop_time.tv_sec) ? _set : _unsynced; timeSource = timeIsValid(sleep_stop_time.tv_sec) ? _set : _unsynced;
// set wakeup state, not if we have pending OTA update // set wakeup state, not if we have pending OTA update
@ -81,7 +83,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..."); ESP_LOGI(TAG, "Preparing to sleep...");
RTC_runmode = RUNMODE_SLEEP; RTC_runmode = RUNMODE_SLEEP;
@ -146,6 +148,28 @@ void enter_deepsleep(const uint32_t wakeup_sec, gpio_num_t wakeup_gpio) {
// configure wakeup sources // configure wakeup sources
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/sleep_modes.html // https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/sleep_modes.html
#if (HAS_TIME)
#if (SYNCWAKEUP) && (SLEEPCYCLE)
if ((timeSource != _unsynced) &&
(sntp_get_sync_status() !=
SNTP_SYNC_STATUS_IN_PROGRESS)) { // only sync if we have a valid time
time_t now;
time(&now);
// 1..3600 seconds between next wakeup time and following top-of-hour
uint16_t shift_sec = 3600 - (now + wakeup_sec) % 3600;
if (shift_sec <= SYNCWAKEUP) {
wakeup_sec += 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)) {
wakeup_sec = 3600 - shift_sec; // shorten wake up to next top-of-hour
ESP_LOGI(TAG, "Syncwakeup: Wakeup %hu sec preponed", shift_sec);
}
}
#endif
#endif
// set up RTC wakeup timer, if we have // set up RTC wakeup timer, if we have
if (wakeup_sec > 0) { if (wakeup_sec > 0) {
esp_sleep_enable_timer_wakeup(wakeup_sec * uS_TO_S_FACTOR); esp_sleep_enable_timer_wakeup(wakeup_sec * uS_TO_S_FACTOR);
@ -158,8 +182,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. // time stamp sleep start time and save system monotonic time. Deep sleep.
gettimeofday(&RTC_sleep_start_time, NULL); gettimeofday(&sleep_start_time, NULL);
RTC_millis += esp_timer_get_time() / 1000; RTC_millis += esp_timer_get_time() / 1000LL;
ESP_LOGI(TAG, "Going to sleep, good bye."); ESP_LOGI(TAG, "Going to sleep, good bye.");
// flush & close sd card, if we have // flush & close sd card, if we have
@ -170,6 +194,6 @@ void enter_deepsleep(const uint32_t wakeup_sec, gpio_num_t wakeup_gpio) {
esp_deep_sleep_start(); esp_deep_sleep_start();
} }
unsigned long long uptime() { uint64_t uptime() {
return (RTC_millis + esp_timer_get_time() / 1000); return (uint64_t)(RTC_millis + esp_timer_get_time() / 1000LL);
} }

View File

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