From f5e24b1358cbae886a89bf340cba3e617d5db239 Mon Sep 17 00:00:00 2001 From: Zoe Pfister <zoe.pfister@uibk.ac.at> Date: Mon, 19 Dec 2022 15:43:05 +0100 Subject: [PATCH] WIP: TimeManager --- .../lib/TimeManager/NTPException.hpp | 23 + .../StringToTimeConversionException.hpp | 26 + .../lib/TimeManager/TimeManager.cpp | 58 ++ .../lib/TimeManager/TimeManager.h | 40 + host/host_central_mast/platformio.ini | 1 + host/host_central_mast/src/main.cpp | 873 +++++++++--------- 6 files changed, 590 insertions(+), 431 deletions(-) create mode 100644 host/host_central_mast/lib/TimeManager/NTPException.hpp create mode 100644 host/host_central_mast/lib/TimeManager/StringToTimeConversionException.hpp create mode 100644 host/host_central_mast/lib/TimeManager/TimeManager.cpp create mode 100644 host/host_central_mast/lib/TimeManager/TimeManager.h diff --git a/host/host_central_mast/lib/TimeManager/NTPException.hpp b/host/host_central_mast/lib/TimeManager/NTPException.hpp new file mode 100644 index 0000000..c64c55c --- /dev/null +++ b/host/host_central_mast/lib/TimeManager/NTPException.hpp @@ -0,0 +1,23 @@ +// +// Created by zoe on 12/19/22. +// + +#ifndef HOST_CENTRAL_MAST_NTPEXCEPTION_HPP +#define HOST_CENTRAL_MAST_NTPEXCEPTION_HPP + +#include <exception> +#include <string> + +class NTPException : public std::exception { +public: + explicit NTPException(const std::string &message) : message(message) {} + + const char *what() const noexcept override { + return message.c_str(); + } + +private: + std::string message; +}; + +#endif //HOST_CENTRAL_MAST_NTPEXCEPTION_HPP diff --git a/host/host_central_mast/lib/TimeManager/StringToTimeConversionException.hpp b/host/host_central_mast/lib/TimeManager/StringToTimeConversionException.hpp new file mode 100644 index 0000000..32e63f4 --- /dev/null +++ b/host/host_central_mast/lib/TimeManager/StringToTimeConversionException.hpp @@ -0,0 +1,26 @@ +// +// Created by zoe on 12/19/22. +// + +#ifndef HOST_CENTRAL_MAST_STRINGTOTIMECONVERSIONEXCEPTION_HPP +#define HOST_CENTRAL_MAST_STRINGTOTIMECONVERSIONEXCEPTION_HPP + +#include <exception> +#include <string> +#include "TimeManager.h" + +class StringToTimeConversionException : public std::exception { +public: + explicit StringToTimeConversionException(const std::string &message) : message(message) {} + + const char *what() const noexcept override { + esp_log_write(ESP_LOG_ERROR, "TimeManager", "Error converting time to epoch: %s", + message.c_str()); + return message.c_str(); + } + +private: + std::string message; +}; + +#endif //HOST_CENTRAL_MAST_STRINGTOTIMECONVERSIONEXCEPTION_HPP diff --git a/host/host_central_mast/lib/TimeManager/TimeManager.cpp b/host/host_central_mast/lib/TimeManager/TimeManager.cpp new file mode 100644 index 0000000..603d717 --- /dev/null +++ b/host/host_central_mast/lib/TimeManager/TimeManager.cpp @@ -0,0 +1,58 @@ +// +// Created by zoe on 12/19/22. +// + +#include "TimeManager.h" + + +TimeManager::TimeManager(TinyGsmSim7000 &modem) : modem(modem) { + +} + +void TimeManager::syncNTP(const std::string &ntpServer) { + esp_log_write(ESP_LOG_DEBUG, TAG, "NTP Server Syncing...\n"); + + auto error = modem.NTPServerSync(ntpServer.c_str(), timeZone); + + /** + According to TinGsmNTP.tpp, the error codes are: + case 1: "Network time synchronization is successful"; + case 61: "Network error"; + case 62: "DNS resolution error"; + case 63: "Connection error"; + case 64: "Service response error"; + case 65: "Service response timeout"; + default: "Unknown error: " + String(error); + */ + if (error != 1) { + throw NTPException(modem.ShowNTPError(error).c_str()); + } else { + esp_log_write(ESP_LOG_DEBUG, TAG, "NTP: %s", modem.ShowNTPError(error).c_str()); + } +} + +time_t TimeManager::timeToUnixEpochSeconds(const std::string &time) { + // 22/10/27,10:16:20+00 + struct tm tm{}; + time_t dateInEpoch = 0; + + std::stringstream stringStream(time); + + try { + stringStream >> std::get_time(&tm, "%y/%m/%d,%H:%M:%S%z"); + } catch (std::exception &e) { + throw StringToTimeConversionException(("Error converting time to epoch %s", e.what())); + } + + return dateInEpoch; +} + +void TimeManager::writeModemTimeToRTC() { + auto gsmDateTimeString = modem.getGSMDateTime(DATE_FULL); + esp_log_write(ESP_LOG_DEBUG, TAG, "GSM DateTime: %s\n", gsmDateTimeString.c_str()); + time_t time = timeToUnixEpochSeconds(gsmDateTimeString.c_str()); + + rtc.setTime(time); + esp_log_write(ESP_LOG_INFO, TAG, "Time set to EPOCH: %s\n", + String(rtc.getEpoch()).c_str()); +} diff --git a/host/host_central_mast/lib/TimeManager/TimeManager.h b/host/host_central_mast/lib/TimeManager/TimeManager.h new file mode 100644 index 0000000..3079b9f --- /dev/null +++ b/host/host_central_mast/lib/TimeManager/TimeManager.h @@ -0,0 +1,40 @@ +// +// Created by zoe on 12/19/22. +// + +#ifndef HOST_CENTRAL_MAST_TIMEMANAGER_H +#define HOST_CENTRAL_MAST_TIMEMANAGER_H + +#define TINY_GSM_MODEM_SIM7000 + +#include <TinyGsmClientSIM7000.h> +#include <string> +#include "NTPException.hpp" +#include "StringToTimeConversionException.hpp" +#include "ESP32Time.h" +#include <iomanip> + +class TimeManager { +public: + explicit TimeManager(TinyGsmSim7000 &modem); + +private: + constexpr static char *TAG = "GSM"; + ESP32Time rtc; + int timeZone = 0; + + // I would like this to be a const reference but the functions used by the modem are not const + TinyGsmSim7000 &modem; + + // sync ntp + void syncNTP(const std::string &ntpServer = "time1.uibk.ac.at"); + + // convert time to unix epoch seconds + time_t timeToUnixEpochSeconds(const std::string &time); + + // write modem time to rtc + void writeModemTimeToRTC(); +}; + + +#endif //HOST_CENTRAL_MAST_TIMEMANAGER_H diff --git a/host/host_central_mast/platformio.ini b/host/host_central_mast/platformio.ini index 1e0fb84..f935fa8 100644 --- a/host/host_central_mast/platformio.ini +++ b/host/host_central_mast/platformio.ini @@ -13,6 +13,7 @@ platform = espressif32 board = esp-wrover-kit framework = arduino monitor_speed = 115200 +lib_ldf_mode = deep monitor_port = /dev/ttyACM0 upload_port = /dev/ttyACM0 build_flags = diff --git a/host/host_central_mast/src/main.cpp b/host/host_central_mast/src/main.cpp index ff11b84..ecb1003 100644 --- a/host/host_central_mast/src/main.cpp +++ b/host/host_central_mast/src/main.cpp @@ -1,3 +1,6 @@ +#define TINY_GSM_MODEM_SIM7000 + + #include "FS.h" #include "SD.h" #include "SPI.h" @@ -21,7 +24,6 @@ static const std::string TAG_GSM = "GSM"; PURPOSE: Test functionality */ -#define TINY_GSM_MODEM_SIM7000 #define TINY_GSM_RX_BUFFER 1024 // Set RX buffer to 1Kb #define SerialAT Serial1 @@ -39,7 +41,9 @@ const char gprsPass[] = ""; #include <TinyGsmClient.h> #ifdef DUMP_AT_COMMANDS // if enabled it requires the streamDebugger lib + #include <StreamDebugger.h> + StreamDebugger debugger(SerialAT, Serial); TinyGsm modem(debugger); #else @@ -61,17 +65,19 @@ TinyGsm modem(SerialAT); #define SD_CS 13 #define LED_PIN 12 -enum MessageType{ +enum MessageType { dataAck, hostChange }; -typedef struct response{ - MessageType type; - uint8_t mac[6]; - long time; -}response; +typedef struct response { + MessageType type; + uint8_t mac[6]; + long time; +} response; + +#include <TimeManager.h> -uint8_t BROADCAST_MAC[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; +uint8_t BROADCAST_MAC[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; esp_now_peer_info_t broadcast = {}; response announce = {}; @@ -83,475 +89,480 @@ TaskHandle_t ESPNOWTask; static std::queue<String> queue; -void on_data_sent(const uint8_t *mac_addr, esp_now_send_status_t status) -{ - // go to sleep +void on_data_sent(const uint8_t *mac_addr, esp_now_send_status_t status) { + // go to sleep } static char log_print_buffer[512]; -int vprintf_into_sd(const char *szFormat, va_list args) -{ - String logstring = "[" + rtc.getDateTime() + "] "; - logstring += szFormat; - // write evaluated format string into buffer - int ret = vsnprintf(log_print_buffer, sizeof(log_print_buffer), logstring.c_str(), args); - - String date = rtc.getDate(); - String filename = "/log_" + date + ".txt"; - - // output is now in buffer. write to file. - if (ret >= 0) { - if (!SD.exists(filename)) { - File writeLog = SD.open(filename, FILE_WRITE); - if (!writeLog) - Serial.println("Couldn't open " + filename + " for writing"); - delay(50); - writeLog.close(); - } - - File logFile = SD.open(filename, FILE_APPEND); - - // debug output - vprintf(logstring.c_str(), args); - logFile.write((uint8_t *)log_print_buffer, (size_t)ret); - // to be safe in case of crashes: flush the output - logFile.flush(); - logFile.close(); - } - return ret; +int vprintf_into_sd(const char *szFormat, va_list args) { + String logstring = "[" + rtc.getDateTime() + "] "; + logstring += szFormat; + // write evaluated format string into buffer + int ret = vsnprintf(log_print_buffer, sizeof(log_print_buffer), logstring.c_str(), args); + + String date = rtc.getDate(); + String filename = "/log_" + date + ".txt"; + + // output is now in buffer. write to file. + if (ret >= 0) { + if (!SD.exists(filename)) { + File writeLog = SD.open(filename, FILE_WRITE); + if (!writeLog) + Serial.println("Couldn't open " + filename + " for writing"); + delay(50); + writeLog.close(); + } + + File logFile = SD.open(filename, FILE_APPEND); + + // debug output + vprintf(logstring.c_str(), args); + logFile.write((uint8_t *) log_print_buffer, (size_t) ret); + // to be safe in case of crashes: flush the output + logFile.flush(); + logFile.close(); + } + return ret; } String getMacAddressAsString(const uint8_t *mac); + DynamicJsonDocument parseReceivedJsonData(char *data); + void saveStringToSDCard(const std::string &dataString); + String documentToLineProtocolString(const DynamicJsonDocument &doc); + void turnOffLEDs(); + void setupSDCard(); + void syncUTCTimeToRTC(); -void on_data_recv(const uint8_t *mac, const uint8_t *incomingData, int len) -{ - esp_log_write(ESP_LOG_INFO, TAG_ESPNOW.c_str(), "Message recieved\n"); - // copy received data to a char array - char data[len]; - memcpy(data, incomingData, len); - esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW.c_str(), "Raw received Data: %s\n", data); - - if(!esp_now_is_peer_exist(mac)){ - esp_now_peer_info_t client = {}; - memcpy(client.peer_addr, mac, sizeof(uint8_t) * 6); - client.encrypt = false; - client.channel = 0; - - esp_err_t status = esp_now_add_peer(&client); - if(status != ESP_OK){ - esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW.c_str(), "Failed to add new Peer: %d", status); - } - } - - DynamicJsonDocument doc = parseReceivedJsonData(data); - - String macAddress = getMacAddressAsString(mac); - - // add timestamp and mac address - // doc["timestamp"] = rtc.getEpoch(); - doc["clientMac"] = macAddress; - - // serialize json document again - std::string dataString{}; - serializeJson(doc, dataString); - - saveStringToSDCard(dataString); - - String lineData = documentToLineProtocolString(doc); - - esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW.c_str(), "Line protocol data: %s\n", lineData.c_str()); - - xSemaphoreTake(xMutex, portMAX_DELAY); - queue.push(lineData); - xSemaphoreGive(xMutex); - - response response = {}; - response.type = dataAck; - esp_read_mac(response.mac, ESP_MAC_WIFI_STA); - response.time = rtc.getEpoch(); - esp_err_t success = esp_now_send(mac, (uint8_t*) &response, sizeof(response)); - esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW.c_str(), - (success == ESP_OK) ? "Response sent\n" : "Failed to respond\n"); + +void on_data_recv(const uint8_t *mac, const uint8_t *incomingData, int len) { + esp_log_write(ESP_LOG_INFO, TAG_ESPNOW.c_str(), "Message recieved\n"); + // copy received data to a char array + char data[len]; + memcpy(data, incomingData, len); + esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW.c_str(), "Raw received Data: %s\n", data); + + if (!esp_now_is_peer_exist(mac)) { + esp_now_peer_info_t client = {}; + memcpy(client.peer_addr, mac, sizeof(uint8_t) * 6); + client.encrypt = false; + client.channel = 0; + + esp_err_t status = esp_now_add_peer(&client); + if (status != ESP_OK) { + esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW.c_str(), "Failed to add new Peer: %d", status); + } + } + + DynamicJsonDocument doc = parseReceivedJsonData(data); + + String macAddress = getMacAddressAsString(mac); + + // add timestamp and mac address + // doc["timestamp"] = rtc.getEpoch(); + doc["clientMac"] = macAddress; + + // serialize json document again + std::string dataString{}; + serializeJson(doc, dataString); + + saveStringToSDCard(dataString); + + String lineData = documentToLineProtocolString(doc); + + esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW.c_str(), "Line protocol data: %s\n", lineData.c_str()); + + xSemaphoreTake(xMutex, portMAX_DELAY); + queue.push(lineData); + xSemaphoreGive(xMutex); + + response response = {}; + response.type = dataAck; + esp_read_mac(response.mac, ESP_MAC_WIFI_STA); + response.time = rtc.getEpoch(); + esp_err_t success = esp_now_send(mac, (uint8_t *) &response, sizeof(response)); + esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW.c_str(), + (success == ESP_OK) ? "Response sent\n" : "Failed to respond\n"); } -String documentToLineProtocolString(const DynamicJsonDocument &doc) -{ - String measurementType = doc["measurementType"].as<String>(); - String sensorName = doc["sensorName"].as<String>(); - String timestamp = doc["timestamp"].as<String>(); - String protocol = doc["protocol"].as<String>(); - String value = doc["value"].as<String>(); - String channel = doc["channel"].as<String>(); - String clientMac = doc["clientMac"].as<String>(); - - String lineData = sensorName + ",clientMac=" + clientMac + ",protocol=" + protocol + ",channel=" + channel + " " - + measurementType + "=" + value + " " + timestamp; - return lineData; +String documentToLineProtocolString(const DynamicJsonDocument &doc) { + String measurementType = doc["measurementType"].as<String>(); + String sensorName = doc["sensorName"].as<String>(); + String timestamp = doc["timestamp"].as<String>(); + String protocol = doc["protocol"].as<String>(); + String value = doc["value"].as<String>(); + String channel = doc["channel"].as<String>(); + String clientMac = doc["clientMac"].as<String>(); + + String lineData = + sensorName + ",clientMac=" + clientMac + ",protocol=" + protocol + ",channel=" + + channel + " " + + measurementType + "=" + value + " " + timestamp; + return lineData; } -void saveStringToSDCard(const std::string &dataString) -{ - File dataFile = SD.open("/datalog.txt", FILE_APPEND); - - // if the file is available, write to it: - if (dataFile) { - if (dataString.length() > 0) { - dataFile.println(dataString.c_str()); - } - dataFile.close(); - } - // if the file isn't open, pop up an error: - else { - esp_log_write(ESP_LOG_ERROR, TAG.c_str(), "error opening datalog.txt\n"); - // TODO: Error handling - } + +void saveStringToSDCard(const std::string &dataString) { + File dataFile = SD.open("/datalog.txt", FILE_APPEND); + + // if the file is available, write to it: + if (dataFile) { + if (dataString.length() > 0) { + dataFile.println(dataString.c_str()); + } + dataFile.close(); + } + // if the file isn't open, pop up an error: + else { + esp_log_write(ESP_LOG_ERROR, TAG.c_str(), "error opening datalog.txt\n"); + // TODO: Error handling + } } -DynamicJsonDocument parseReceivedJsonData(char *data) -{ - DynamicJsonDocument doc(250); - auto error = deserializeJson(doc, data); - if (error) { - esp_log_write(ESP_LOG_ERROR, TAG_ESPNOW.c_str(), "Error while parsing json: %s\n", error.f_str()); - // TODO error handling - } - return doc; + +DynamicJsonDocument parseReceivedJsonData(char *data) { + DynamicJsonDocument doc(250); + auto error = deserializeJson(doc, data); + if (error) { + esp_log_write(ESP_LOG_ERROR, TAG_ESPNOW.c_str(), "Error while parsing json: %s\n", + error.f_str()); + // TODO error handling + } + return doc; } -String getMacAddressAsString(const uint8_t *mac) -{ - String macAddress; - for (int i = 0; i < 6; i++) { - macAddress += String(mac[i], HEX); - } - esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW.c_str(), "MAC: %s\n", macAddress.c_str()); - return macAddress; + +String getMacAddressAsString(const uint8_t *mac) { + String macAddress; + for (int i = 0; i < 6; i++) { + macAddress += String(mac[i], HEX); + } + esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW.c_str(), "MAC: %s\n", macAddress.c_str()); + return macAddress; } -[[noreturn]] void ESPNOWReceiveTask(void *parameter) -{ - esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW.c_str(), "ESPNOWReceiveTask started on core %d\n", xPortGetCoreID()); +[[noreturn]] void ESPNOWReceiveTask(void *parameter) { + esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW.c_str(), "ESPNOWReceiveTask started on core %d\n", + xPortGetCoreID()); - WiFi.mode(WIFI_STA); + WiFi.mode(WIFI_STA); - esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW.c_str(), "Initialising ESPNow...\n"); + esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW.c_str(), "Initialising ESPNow...\n"); - if (esp_now_init() != ESP_OK) { - // initialization failed - esp_log_write(ESP_LOG_ERROR, TAG_ESPNOW.c_str(), "Initialising ESPNow FAILED\n"); - exit(ESP_FAIL); - } + if (esp_now_init() != ESP_OK) { + // initialization failed + esp_log_write(ESP_LOG_ERROR, TAG_ESPNOW.c_str(), "Initialising ESPNow FAILED\n"); + exit(ESP_FAIL); + } - esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW.c_str(), "Initialising ESPNow SUCCESS\n"); + esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW.c_str(), "Initialising ESPNow SUCCESS\n"); - esp_now_register_recv_cb(on_data_recv); + esp_now_register_recv_cb(on_data_recv); - while (true) { - } + while (true) { + } } -time_t timeToUnixEpochSeconds(const std::string &time) -{ - // 22/10/27,10:16:20+00 - struct tm tm {}; - time_t dateInEpoch = 0; - - if (strptime(time.c_str(), "%y/%m/%d,%T+00", &tm)) { - time_t curTime; - struct tm *timeinfo; - - timeinfo = localtime(&curTime); - - timeinfo->tm_year = tm.tm_year; - timeinfo->tm_mon = tm.tm_mon; - timeinfo->tm_mday = tm.tm_mday; - timeinfo->tm_hour = tm.tm_hour; - timeinfo->tm_min = tm.tm_min; - timeinfo->tm_sec = tm.tm_sec; - timeinfo->tm_isdst = -1; - - dateInEpoch = mktime(timeinfo); - } - return dateInEpoch; +time_t timeToUnixEpochSeconds(const std::string &time) { + // 22/10/27,10:16:20+00 + struct tm tm{}; + time_t dateInEpoch = 0; + + if (strptime(time.c_str(), "%y/%m/%d,%T+00", &tm)) { + time_t curTime; + struct tm *timeinfo; + + timeinfo = localtime(&curTime); + + timeinfo->tm_year = tm.tm_year; + timeinfo->tm_mon = tm.tm_mon; + timeinfo->tm_mday = tm.tm_mday; + timeinfo->tm_hour = tm.tm_hour; + timeinfo->tm_min = tm.tm_min; + timeinfo->tm_sec = tm.tm_sec; + timeinfo->tm_isdst = -1; + + dateInEpoch = mktime(timeinfo); + } + return dateInEpoch; } -void setup() -{ - // Set console baud rate - Serial.begin(115200); - delay(10); - setupSDCard(); - - // https://stackoverflow.com/questions/60442350/arduinos-esp-log-set-vprintf-does-not-work-on-esp32 - esp_log_set_vprintf(&vprintf_into_sd); - esp_log_level_set("*", ESP_LOG_VERBOSE); - esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "%s", WiFi.macAddress().c_str()); - - turnOffLEDs(); - - xMutex = xSemaphoreCreateMutex(); - - delay(1000); - - // create ESPNOWReceiveTask. TODO: Until the UTC time is not synced, this will not add the correct time. If we - // TODO: create the task after the time is synced, no messages will be received until synchronization is done - xTaskCreatePinnedToCore(ESPNOWReceiveTask, /* Function to implement the task */ - "ESPNOWReceiveTask", /* Name of the task */ - 10000, /* Stack size in words */ - nullptr, /* Task input parameter */ - 0, /* Priority of the task */ - &ESPNOWTask, /* Task handle. */ - 0); /* Core where the task should run */ - - SerialAT.begin(UART_BAUD, SERIAL_8N1, PIN_RX, PIN_TX); - - // Restart takes quite some time - // To skip it, call init() instead of restart() - esp_log_write(ESP_LOG_DEBUG, TAG_GSM.c_str(), "Initializing modem...\n"); - if (!modem.restart()) { - esp_log_write(ESP_LOG_WARN, TAG_GSM.c_str(), - "Failed to restart modem, attempting to continue without restarting\n"); - } - - syncUTCTimeToRTC(); - - broadcast.channel = 0; - broadcast.encrypt = false; - memcpy(&broadcast.peer_addr, &BROADCAST_MAC, sizeof(BROADCAST_MAC)); - if(esp_now_add_peer(&broadcast) != ESP_OK){ - esp_log_write(ESP_LOG_WARN, TAG_ESPNOW.c_str(), "Failed to add Broadcast Host"); - } - - announce.type = hostChange; - esp_read_mac(announce.mac, ESP_MAC_WIFI_STA); - announce.time = rtc.getEpoch(); - if(esp_now_send(BROADCAST_MAC, (uint8_t *) &announce, sizeof(announce)) != ESP_OK){ - esp_log_write(ESP_LOG_WARN, TAG_ESPNOW.c_str(), "Failed to announce mac"); - } - else{ - esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW.c_str(), "Mac announced!"); - } +void setup() { + // Set console baud rate + Serial.begin(115200); + delay(10); + setupSDCard(); + + // https://stackoverflow.com/questions/60442350/arduinos-esp-log-set-vprintf-does-not-work-on-esp32 + esp_log_set_vprintf(&vprintf_into_sd); + esp_log_level_set("*", ESP_LOG_VERBOSE); + esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "%s", WiFi.macAddress().c_str()); + + turnOffLEDs(); + + xMutex = xSemaphoreCreateMutex(); + + delay(1000); + + // create ESPNOWReceiveTask. TODO: Until the UTC time is not synced, this will not add the correct time. If we + // TODO: create the task after the time is synced, no messages will be received until synchronization is done + xTaskCreatePinnedToCore(ESPNOWReceiveTask, /* Function to implement the task */ + "ESPNOWReceiveTask", /* Name of the task */ + 10000, /* Stack size in words */ + nullptr, /* Task input parameter */ + 0, /* Priority of the task */ + &ESPNOWTask, /* Task handle. */ + 0); /* Core where the task should run */ + + SerialAT.begin(UART_BAUD, SERIAL_8N1, PIN_RX, PIN_TX); + + // Restart takes quite some time + // To skip it, call init() instead of restart() + esp_log_write(ESP_LOG_DEBUG, TAG_GSM.c_str(), "Initializing modem...\n"); + if (!modem.restart()) { + esp_log_write(ESP_LOG_WARN, TAG_GSM.c_str(), + "Failed to restart modem, attempting to continue without restarting\n"); + } + + syncUTCTimeToRTC(); + + broadcast.channel = 0; + broadcast.encrypt = false; + memcpy(&broadcast.peer_addr, &BROADCAST_MAC, sizeof(BROADCAST_MAC)); + if (esp_now_add_peer(&broadcast) != ESP_OK) { + esp_log_write(ESP_LOG_WARN, TAG_ESPNOW.c_str(), "Failed to add Broadcast Host"); + } + + announce.type = hostChange; + esp_read_mac(announce.mac, ESP_MAC_WIFI_STA); + announce.time = rtc.getEpoch(); + if (esp_now_send(BROADCAST_MAC, (uint8_t *) &announce, sizeof(announce)) != ESP_OK) { + esp_log_write(ESP_LOG_WARN, TAG_ESPNOW.c_str(), "Failed to announce mac"); + } else { + esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW.c_str(), "Mac announced!"); + } } -void syncUTCTimeToRTC() -{ - esp_log_write(ESP_LOG_DEBUG, TAG_GSM.c_str(), "NTP Server Syncing...\n"); - modem.NTPServerSync("pool.ntp.org", 0); - auto gsmDateTimeString = modem.getGSMDateTime(DATE_FULL); - esp_log_write(ESP_LOG_DEBUG, TAG_GSM.c_str(), "GSM DateTime: %s\n", gsmDateTimeString.c_str()); - time_t time = timeToUnixEpochSeconds(gsmDateTimeString.c_str()); - rtc.setTime(time); - esp_log_write(ESP_LOG_INFO, TAG_GSM.c_str(), "Time set to EPOCH: %s\n", String(rtc.getEpoch()).c_str()); + +// waitResponse default is 1000ms + +void syncUTCTimeToRTC() { + esp_log_write(ESP_LOG_DEBUG, TAG_GSM.c_str(), "NTP Server Syncing...\n"); + auto error = modem.NTPServerSync("pool.ntp.org", 0); + esp_log_write(ESP_LOG_DEBUG, TAG_GSM.c_str(), "NTP: %s", modem.ShowNTPError(error).c_str()); + + auto gsmDateTimeString = modem.getGSMDateTime(DATE_FULL); + esp_log_write(ESP_LOG_DEBUG, TAG_GSM.c_str(), "GSM DateTime: %s\n", gsmDateTimeString.c_str()); + time_t time = timeToUnixEpochSeconds(gsmDateTimeString.c_str()); + + rtc.setTime(time); + esp_log_write(ESP_LOG_INFO, TAG_GSM.c_str(), "Time set to EPOCH: %s\n", + String(rtc.getEpoch()).c_str()); } -void setupSDCard() -{ - SPI.begin(SD_SCLK, SD_MISO, SD_MOSI, SD_CS); - if (!SD.begin(SD_CS)) { - esp_log_write(ESP_LOG_ERROR, TAG.c_str(), "Card MOUNT FAIL\n"); - // TODO: Error handling - } else { - uint32_t cardSize = SD.cardSize() / (1024 * 1024); - String sdcardSizeString = "SDCard Size: " + String(cardSize) + "MB"; - esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "%s\n", sdcardSizeString.c_str()); - } + +void setupSDCard() { + SPI.begin(SD_SCLK, SD_MISO, SD_MOSI, SD_CS); + if (!SD.begin(SD_CS)) { + esp_log_write(ESP_LOG_ERROR, TAG.c_str(), "Card MOUNT FAIL\n"); + // TODO: Error handling + } else { + uint32_t cardSize = SD.cardSize() / (1024 * 1024); + String sdcardSizeString = "SDCard Size: " + String(cardSize) + "MB"; + esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "%s\n", sdcardSizeString.c_str()); + } } // I don't think this does anything. Copied from the example -void turnOffLEDs() -{ // Set LED OFF - pinMode(LED_PIN, OUTPUT); - digitalWrite(LED_PIN, HIGH); - - pinMode(PWR_PIN, OUTPUT); - digitalWrite(PWR_PIN, HIGH); - delay(300); - digitalWrite(PWR_PIN, LOW); +void turnOffLEDs() { // Set LED OFF + pinMode(LED_PIN, OUTPUT); + digitalWrite(LED_PIN, HIGH); + + pinMode(PWR_PIN, OUTPUT); + digitalWrite(PWR_PIN, HIGH); + delay(300); + digitalWrite(PWR_PIN, LOW); } const String INFLUXDB_TOKEN = - "dUh2gbVLv7e3egqocxriDsJQNUacA9qZ5YXsYtdnVAglnHgy4nx-jDVO7nGlSF34BosfnuwnUDaviC7dQeC5RQ=="; + "dUh2gbVLv7e3egqocxriDsJQNUacA9qZ5YXsYtdnVAglnHgy4nx-jDVO7nGlSF34BosfnuwnUDaviC7dQeC5RQ=="; struct RequestInformation { - String method; - String host; - String path; - String body; + String method; + String host; + String path; + String body; }; -String buildRequest(const RequestInformation &requestInformation) -{ - String request = ""; - request += requestInformation.method + " " + requestInformation.path + " HTTP/1.1\r\n"; - request += "Host: " + requestInformation.host + "\r\n"; - request += "Authorization: Token " + INFLUXDB_TOKEN + "\r\n"; - request += "User-Agent: ESP32\r\n"; - request += "Content-Type: text/plain\r\n"; - request += "Content-Length: " + String(requestInformation.body.length()) + "\r\n"; - request += "\r\n"; - request += requestInformation.body; - return request; +String buildRequest(const RequestInformation &requestInformation) { + String request = ""; + request += requestInformation.method + " " + requestInformation.path + " HTTP/1.1\r\n"; + request += "Host: " + requestInformation.host + "\r\n"; + request += "Authorization: Token " + INFLUXDB_TOKEN + "\r\n"; + request += "User-Agent: ESP32\r\n"; + request += "Content-Type: text/plain\r\n"; + request += "Content-Length: " + String(requestInformation.body.length()) + "\r\n"; + request += "\r\n"; + request += requestInformation.body; + return request; } -void loop() -{ - - // Restart takes quite some time - // To skip it, call init() instead of restart() - esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "Initializing modem...\n"); - if (!modem.init()) { - esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), - "Failed to restart modem, attempting to continue without restarting\n"); - } - - announce.time = rtc.getEpoch(); - if(esp_now_send(BROADCAST_MAC, (uint8_t *) &announce, sizeof(announce)) != ESP_OK){ - esp_log_write(ESP_LOG_WARN, TAG_ESPNOW.c_str(), "Failed to announce mac\n"); - } - else{ - esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW.c_str(), "Mac announced!\n"); - } - - String name = modem.getModemName(); - delay(500); - esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "Modem Name %s\n", name.c_str()); - - String modemInfo = modem.getModemInfo(); - delay(500); - esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "Modem Info: %s\n", modemInfo.c_str()); - - // Set SIM7000G GPIO4 LOW ,turn off GPS power - // CMD:AT+SGPIO=0,4,1,0 - // Only in version 20200415 is there a function to control GPS power - modem.sendAT("+SGPIO=0,4,1,0"); - if (modem.waitResponse(10000L) != 1) { - DBG(" SGPIO=0,4,1,0 false "); - } - - modem.sendAT("+CFUN=0 "); - if (modem.waitResponse(10000L) != 1) { - DBG(" +CFUN=0 false "); - } - delay(200); - - /* - 2 Automatic - 13 GSM only - 38 LTE only - 51 GSM and LTE only - * * * */ - String res; - res = modem.setNetworkMode(38); - if (res != "1") { - DBG("setNetworkMode false "); - return; - } - delay(200); - - /* - 1 CAT-M - 2 NB-Iot - 3 CAT-M and NB-IoT - * * */ - // res = modem.setPreferredMode(1); - // if (res != "1") { - // - // DBG("setPreferredMode false "); - // return; - // } - delay(200); - - /*AT+CBANDCFG=<mode>,<band>[,<band>…] - * <mode> "CAT-M" "NB-IOT" - * <band> The value of <band> must is in the band list of getting from AT+CBANDCFG=? - * For example, my SIM card carrier "NB-iot" supports B8. I will configure +CBANDCFG= "Nb-iot ",8 - */ - modem.sendAT("+CBANDCFG=\"CAT-M\",8 "); - if (modem.waitResponse(10000L) != 1) { - DBG(" +CBANDCFG=\"NB-IOT\" "); - } - delay(200); - - modem.sendAT("+CFUN=1 "); - if (modem.waitResponse(10000L) != 1) { - DBG(" +CFUN=1 false "); - } - delay(200); - - // modem.disableGPS(); - delay(200); - esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "%s\n", String(modem.getSignalQuality()).c_str()); - delay(200); - esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "Trying to connect to network\n"); - modem.gprsConnect(apn, gprsUser, gprsPass); - delay(200); - syncUTCTimeToRTC(); - - esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "Waiting for network...\n"); - if (!modem.isNetworkConnected()) { - esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "Network not connected\n"); - return; - } else { - esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "Network connected\n"); - delay(200); - - // quality - esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "%s\n", String(modem.getSignalQuality()).c_str()); - // make a http post request - String url = "influxdb.qe-forte.uibk.ac.at"; - String path = "/api/v2/write?org=QE&bucket=esp32test&precision=s"; - Serial.print("Connecting to "); - esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "%s\n", url.c_str()); - // Use WiFiClient class to create TCP connections - - while (!queue.empty()) { - - xSemaphoreTake(xMutex, portMAX_DELAY); - String lineData = queue.front(); - queue.pop(); - xSemaphoreGive(xMutex); - - RequestInformation requestInformation{.method = "POST", .host = url, .path = path, .body = lineData}; - - //"sensorName":"DRS26","timestamp":1666872216,"protocol":"I2C","value":0,"channel":0,"measurementType":"CIRCUMFERENCE_INCREMENT" - - String request = buildRequest(requestInformation); - esp_log_write(ESP_LOG_VERBOSE, TAG.c_str(), "request: %s\n", request.c_str()); - - TinyGsmClient client{modem}; - const int httpPort = 80; - if (!client.connect(url.c_str(), httpPort)) { - esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "connection failed\n"); - return; - } - - client.print(request); - - // print response - while (client.connected()) { - String line = client.readStringUntil('\n'); - if (line == "\r") { - esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "headers received\n"); - break; - } - } - client.stop(); - delay(1000); - } - DBG("Network connected"); - } +void loop() { + + // Restart takes quite some time + // To skip it, call init() instead of restart() + esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "Initializing modem...\n"); + if (!modem.init()) { + esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), + "Failed to restart modem, attempting to continue without restarting\n"); + } + + announce.time = rtc.getEpoch(); + if (esp_now_send(BROADCAST_MAC, (uint8_t *) &announce, sizeof(announce)) != ESP_OK) { + esp_log_write(ESP_LOG_WARN, TAG_ESPNOW.c_str(), "Failed to announce mac\n"); + } else { + esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW.c_str(), "Mac announced!\n"); + } + + String name = modem.getModemName(); + delay(500); + esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "Modem Name %s\n", name.c_str()); + + String modemInfo = modem.getModemInfo(); + delay(500); + esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "Modem Info: %s\n", modemInfo.c_str()); + + // Set SIM7000G GPIO4 LOW ,turn off GPS power + // CMD:AT+SGPIO=0,4,1,0 + // Only in version 20200415 is there a function to control GPS power + modem.sendAT("+SGPIO=0,4,1,0"); + if (modem.waitResponse(10000L) != 1) { + DBG(" SGPIO=0,4,1,0 false "); + } + + modem.sendAT("+CFUN=0 "); + if (modem.waitResponse(10000L) != 1) { + DBG(" +CFUN=0 false "); + } + delay(200); + + /* + 2 Automatic + 13 GSM only + 38 LTE only + 51 GSM and LTE only + * * * */ + String res; + res = modem.setNetworkMode(38); + if (res != "1") { + DBG("setNetworkMode false "); + return; + } + delay(200); + + /* + 1 CAT-M + 2 NB-Iot + 3 CAT-M and NB-IoT + * * */ + // res = modem.setPreferredMode(1); + // if (res != "1") { + // + // DBG("setPreferredMode false "); + // return; + // } + delay(200); + + /*AT+CBANDCFG=<mode>,<band>[,<band>…] + * <mode> "CAT-M" "NB-IOT" + * <band> The value of <band> must is in the band list of getting from AT+CBANDCFG=? + * For example, my SIM card carrier "NB-iot" supports B8. I will configure +CBANDCFG= "Nb-iot ",8 + */ + modem.sendAT("+CBANDCFG=\"CAT-M\",8 "); + if (modem.waitResponse(10000L) != 1) { + DBG(" +CBANDCFG=\"NB-IOT\" "); + } + delay(200); + + modem.sendAT("+CFUN=1 "); + if (modem.waitResponse(10000L) != 1) { + DBG(" +CFUN=1 false "); + } + delay(200); + + // modem.disableGPS(); + delay(200); + esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "%s\n", String(modem.getSignalQuality()).c_str()); + delay(200); + esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "Trying to connect to network\n"); + modem.gprsConnect(apn, gprsUser, gprsPass); + delay(200); + syncUTCTimeToRTC(); + + esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "Waiting for network...\n"); + if (!modem.isNetworkConnected()) { + esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "Network not connected\n"); + return; + } else { + esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "Network connected\n"); + delay(200); + + // quality + esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "%s\n", String(modem.getSignalQuality()).c_str()); + // make a http post request + String url = "influxdb.qe-forte.uibk.ac.at"; + String path = "/api/v2/write?org=QE&bucket=esp32test&precision=s"; + Serial.print("Connecting to "); + esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "%s\n", url.c_str()); + // Use WiFiClient class to create TCP connections + + while (!queue.empty()) { + + xSemaphoreTake(xMutex, portMAX_DELAY); + String lineData = queue.front(); + queue.pop(); + xSemaphoreGive(xMutex); + + RequestInformation requestInformation{.method = "POST", .host = url, .path = path, .body = lineData}; + + //"sensorName":"DRS26","timestamp":1666872216,"protocol":"I2C","value":0,"channel":0,"measurementType":"CIRCUMFERENCE_INCREMENT" + + String request = buildRequest(requestInformation); + esp_log_write(ESP_LOG_VERBOSE, TAG.c_str(), "request: %s\n", request.c_str()); + + TinyGsmClient client{modem}; + const int httpPort = 80; + if (!client.connect(url.c_str(), httpPort)) { + esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "connection failed\n"); + return; + } + + client.print(request); + + // print response + while (client.connected()) { + String line = client.readStringUntil('\n'); + if (line == "\r") { + esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "headers received\n"); + break; + } + } + client.stop(); + delay(1000); + } + DBG("Network connected"); + } #if TINY_GSM_POWERDOWN - // Try to power-off (modem may decide to restart automatically) - // To turn off modem completely, please use Reset/Enable pins - // modem.sendAT("+CPOWD=1"); - // if (modem.waitResponse(10000L) != 1) { - // DBG("+CPOWD=1"); - // } - // modem.poweroff(); - esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "Poweroff."); + // Try to power-off (modem may decide to restart automatically) + // To turn off modem completely, please use Reset/Enable pins + // modem.sendAT("+CPOWD=1"); + // if (modem.waitResponse(10000L) != 1) { + // DBG("+CPOWD=1"); + // } + // modem.poweroff(); + esp_log_write(ESP_LOG_DEBUG, TAG.c_str(), "Poweroff."); #endif - delay(1000); + delay(1000); } -- GitLab