Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • informatik/qe/forte/sensor-system
1 result
Show changes
Commits on Source (2)
Showing
with 634 additions and 799 deletions
......@@ -9,6 +9,7 @@ AllowShortFunctionsOnASingleLine: Inline
AlwaysBreakTemplateDeclarations: Yes
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Custom
NamespaceIndentation: All
BraceWrapping:
AfterFunction: false
...
//
// Created by zoe on 1/24/23.
//
#ifndef HOST_CENTRAL_MAST_MESSAGETYPE_H
#define HOST_CENTRAL_MAST_MESSAGETYPE_H
enum MessageType { dataAck, hostChange };
typedef struct response {
MessageType type;
uint8_t mac[6];
long time; // Clang-Tidy: Narrowing conversion from 'unsigned long' to signed type 'long' is implementation-defined
// (see rtc in main.cpp)
} response;
#endif // HOST_CENTRAL_MAST_MESSAGETYPE_H
......@@ -2,18 +2,18 @@
// Created by zoe on 12/19/22.
//
#include "TimeManager.h"
#include "NTPManager.h"
TimeManager::TimeManager(TinyGsmSim7000 &modem) : modem(modem) {}
NTPManager::NTPManager(TinyGsmSim7000 &modem) : modem(modem) {}
void TimeManager::syncNTP(const std::string &ntpServer, const std::string &backupNtpServer) {
void NTPManager::syncNTP(const std::string &ntpServer, const std::string &backupNtpServer) {
// create list of ntp servers
std::vector<std::string> ntpServers;
ntpServers.push_back(ntpServer);
ntpServers.push_back(backupNtpServer);
tryNtpServerSync(backupNtpServer, ntpServers);
}
void TimeManager::tryNtpServerSync(const std::string &backupNtpServer,
void NTPManager::tryNtpServerSync(const std::string &backupNtpServer,
std::vector<std::string> &ntpServers) { // try to sync ntp with each server
for (const auto &server : ntpServers) {
try {
......@@ -21,15 +21,16 @@ void TimeManager::tryNtpServerSync(const std::string &backupNtpServer,
return;
} catch (NTPException &e) {
if (server == backupNtpServer) {
esp_log_write(ESP_LOG_ERROR, TAG, "Failed to sync NTP with %s (%s)\n", server.c_str(), e.what());
esp_log_write(ESP_LOG_ERROR, TAG_TIMEMANAGER, "Failed to sync NTP with %s (%s)\n", server.c_str(),
e.what());
}
esp_log_write(ESP_LOG_ERROR, TAG, "Failed to sync NTP with %s (%s). Retrying with backup...\n",
esp_log_write(ESP_LOG_ERROR, TAG_TIMEMANAGER, "Failed to sync NTP with %s (%s). Retrying with backup...\n",
server.c_str(), e.what());
}
}
}
void TimeManager::synchronizeNTPWithModem(const std::string &ntpServer) {
esp_log_write(ESP_LOG_DEBUG, TAG, "NTP Server Syncing...\n");
void NTPManager::synchronizeNTPWithModem(const std::string &ntpServer) {
esp_log_write(ESP_LOG_DEBUG, TAG_TIMEMANAGER, "NTP Server Syncing...\n");
long error = modem.NTPServerSync(ntpServer.c_str(), timeZone);
/**
......@@ -46,11 +47,11 @@ void TimeManager::synchronizeNTPWithModem(const std::string &ntpServer) {
if (error != 1 && error != 255) {
throw NTPException(modem.ShowNTPError(error).c_str());
} else {
esp_log_write(ESP_LOG_DEBUG, TAG, "NTP: Network time synchronization is successful\n");
esp_log_write(ESP_LOG_DEBUG, TAG_TIMEMANAGER, "NTP: Network time synchronization is successful\n");
}
}
time_t TimeManager::timeToUnixEpochSeconds(const std::string &time, const std::string &format) {
time_t NTPManager::timeToUnixEpochSeconds(const std::string &time, const std::string &format) {
// 22/10/27,10:16:20+00
struct tm tm {};
time_t dateInEpoch = 0;
......@@ -77,11 +78,11 @@ time_t TimeManager::timeToUnixEpochSeconds(const std::string &time, const std::s
return dateInEpoch;
}
void TimeManager::writeModemTimeToRTC() {
void NTPManager::writeModemTimeToRTC() {
auto gsmDateTimeString = modem.getGSMDateTime(DATE_FULL);
esp_log_write(ESP_LOG_DEBUG, TAG, "GSM DateTime: %s\n", gsmDateTimeString.c_str());
esp_log_write(ESP_LOG_DEBUG, TAG_TIMEMANAGER, "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());
esp_log_write(ESP_LOG_INFO, TAG_TIMEMANAGER, "Time set to EPOCH: %s\n", String(rtc.getEpoch()).c_str());
}
......@@ -2,11 +2,12 @@
// Created by zoe on 12/19/22.
//
#ifndef HOST_CENTRAL_MAST_TIMEMANAGER_H
#define HOST_CENTRAL_MAST_TIMEMANAGER_H
#ifndef HOST_CENTRAL_MAST_NTPMANAGER_H
#define HOST_CENTRAL_MAST_NTPMANAGER_H
#define TINY_GSM_MODEM_SIM7000
#include "Definitions.h"
#include "ESP32Time.h"
#include "NTPException.hpp"
#include "StringToTimeConversionException.hpp"
......@@ -14,13 +15,11 @@
#include <iomanip>
#include <string>
class TimeManager {
class NTPManager {
public:
explicit TimeManager(TinyGsmSim7000 &modem);
explicit NTPManager(TinyGsmSim7000 &modem);
private:
constexpr static char *TAG = "TimeManager";
ESP32Time rtc;
int timeZone = 0;
// I would like this to be a const reference but the functions used by the modem are not const
......@@ -40,4 +39,4 @@ class TimeManager {
void writeModemTimeToRTC();
};
#endif // HOST_CENTRAL_MAST_TIMEMANAGER_H
\ No newline at end of file
#endif // HOST_CENTRAL_MAST_NTPMANAGER_H
\ No newline at end of file
......@@ -5,16 +5,16 @@
#ifndef HOST_CENTRAL_MAST_STRINGTOTIMECONVERSIONEXCEPTION_HPP
#define HOST_CENTRAL_MAST_STRINGTOTIMECONVERSIONEXCEPTION_HPP
#include "NTPManager.h"
#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",
esp_log_write(ESP_LOG_ERROR, "NTPManager", "Error converting time to epoch: %s",
message.c_str());
return message.c_str();
}
......
......@@ -3,10 +3,6 @@
//
#include "ConnectionManager.h"
#include "LTEConnectionException.hpp"
#include "ModemFunctionalityLevel.h"
#include <utility>
ConnectionManager::ConnectionManager(TinyGsm &modem, GPRSCredentials credentials, ModemPins modemPins)
: modem(modem), credentials(std::move(credentials)), modemPins(modemPins) {}
......@@ -14,17 +10,16 @@ ConnectionManager::ConnectionManager(TinyGsm &modem, GPRSCredentials credentials
void ConnectionManager::restartModem() {
// Restart takes quite some time
// To skip it, call init() instead of restart()
esp_log_write(ESP_LOG_DEBUG, TAG_GSM.c_str(), "Restarting modem...\n");
esp_log_write(ESP_LOG_DEBUG, TAG_GSM, "Restarting 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");
esp_log_write(ESP_LOG_WARN, TAG_GSM, "Failed to restart modem, attempting to continue without restarting\n");
}
}
void ConnectionManager::initModem() {
esp_log_write(ESP_LOG_DEBUG, TAG_GSM.c_str(), "Initializing modem...\n");
esp_log_write(ESP_LOG_DEBUG, TAG_GSM, "Initializing modem...\n");
if (!modem.init()) {
esp_log_write(ESP_LOG_WARN, TAG_GSM.c_str(), "Failed to initialize modem, attempting to continue...\n");
esp_log_write(ESP_LOG_WARN, TAG_GSM, "Failed to initialize modem, attempting to continue...\n");
}
setModemFunctionalityLevel(MINIMAL);
}
......@@ -100,9 +95,9 @@ bool ConnectionManager::gprsConnect() {
bool ConnectionManager::isNetworkConnected() {
return modem.isNetworkConnected();
}
std::string ConnectionManager::connect(int port, RequestInformation requestInformation) {
std::string ConnectionManager::connect(RequestInformation requestInformation) {
TinyGsmClient client{modem, 0};
if (!client.connect(requestInformation.host.c_str(), port)) {
if (!client.connect(requestInformation.host.c_str(), requestInformation.port)) {
throw LTEConnectionException("Failed to connect to host");
}
......@@ -115,7 +110,7 @@ std::string ConnectionManager::connect(int port, RequestInformation requestInfor
while (client.connected()) {
line += client.readStringUntil('\n');
if (line == "\r") {
esp_log_write(ESP_LOG_DEBUG, TAG_GSM.c_str(), "headers received\n");
esp_log_write(ESP_LOG_DEBUG, TAG_GSM, "headers received\n");
break;
}
}
......@@ -131,9 +126,11 @@ void ConnectionManager::modemPowerOn() {
}
void ConnectionManager::modemPowerOff() {
// 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) {
esp_log_write(ESP_LOG_WARN, TAG_GSM.c_str(), "Failed to power off modem\n");
esp_log_write(ESP_LOG_WARN, TAG_GSM, "Failed to power off modem\n");
}
modem.poweroff();
pinMode(modemPins.pwr, OUTPUT);
......@@ -157,3 +154,28 @@ bool ConnectionManager::waitForNetwork() {
bool ConnectionManager::gprsDisconnect() {
return modem.gprsDisconnect();
}
void ConnectionManager::logModemInformation() {
bool res = modem.isGprsConnected();
esp_log_write(ESP_LOG_DEBUG, TAG_GSM, "GPRS connected: %s\n", res ? "true" : "false");
String ccid = modem.getSimCCID();
esp_log_write(ESP_LOG_DEBUG, TAG_GSM, "CCID: %s\n", ccid.c_str());
String imei = modem.getIMEI();
esp_log_write(ESP_LOG_DEBUG, TAG_GSM, "IMEI: %s\n", imei.c_str());
String imsi = modem.getIMSI();
esp_log_write(ESP_LOG_DEBUG, TAG_GSM, "IMSI: %s\n", imsi.c_str());
String cop = modem.getOperator();
esp_log_write(ESP_LOG_DEBUG, TAG_GSM, "Operator: %s\n", cop.c_str());
IPAddress local = modem.localIP();
esp_log_write(ESP_LOG_DEBUG, TAG_GSM, "Local IP: %s\n", local.toString().c_str());
int csq = modem.getSignalQuality();
esp_log_write(ESP_LOG_DEBUG, TAG_GSM, "Signal quality: %d\n", csq);
}
bool ConnectionManager::isGprsConnected() {
return modem.isGprsConnected();
}
......@@ -7,15 +7,16 @@
#define TINY_GSM_MODEM_SIM7000
#include "Definitions.h"
#include "GPRSCredentials.h"
#include "LTEConnectionException.hpp"
#include "Mode.h"
#include "ModemFunctionalityLevel.h"
#include "NetworkMode.h"
#include "RequestInformation.h"
#include "StreamDebugger.h"
#include <TinyGsmClient.h>
static const std::string TAG_GSM = "GSM";
#include <utility>
class ConnectionManager {
......@@ -35,7 +36,7 @@ class ConnectionManager {
public:
ConnectionManager(TinyGsm &modem, GPRSCredentials credentials, ModemPins modemPins);
std::string connect(int port, RequestInformation requestInformation);
std::string connect(RequestInformation requestInformation);
void enableGPS();
......@@ -66,6 +67,9 @@ class ConnectionManager {
void unlockSimCard();
bool waitForNetwork();
void logModemInformation();
bool isGprsConnected();
};
#endif // HOST_CENTRAL_MAST_CONNECTIONMANAGER_H
......@@ -6,31 +6,42 @@
#define HOST_CENTRAL_MAST_REQUESTINFORMATION_H
#include <Arduino.h>
#include <Definitions.h>
#include <map>
enum RequestMethod {
GET,
POST,
};
struct RequestInformation {
String method;
RequestMethod method;
std::map<String, String> headers;
int port;
String host;
String path;
String body;
RequestInformation(String method, String host, String path, String body) {
RequestInformation(const RequestMethod &method, const String &host, const int &port, const String &path,
const String &body, const std::map<String, String> &headers) {
this->method = method;
this->port = port;
this->headers = headers;
this->host = host;
this->path = path;
this->body = body;
}
// TODO: Move to configuration file
const String INFLUXDB_TOKEN =
"dUh2gbVLv7e3egqocxriDsJQNUacA9qZ5YXsYtdnVAglnHgy4nx-jDVO7nGlSF34BosfnuwnUDaviC7dQeC5RQ==";
String buildRequest() {
String methodString = method == RequestMethod::GET ? "GET" : "POST";
String request = "";
request += method + " " + path + " HTTP/1.1\r\n";
request += methodString + " " + path + " HTTP/1.1\r\n";
request += "Host: " + host + "\r\n";
request += "Authorization: Token " + INFLUXDB_TOKEN + "\r\n";
request += "User-Agent: ESP32\r\n";
request += "Content-Type: text/plain\r\n";
request += "User-Agent: ESP32-Host\r\n";
for (auto &header : headers) {
request += header.first + ": " + header.second + "\r\n";
}
// request += "Authorization: Token " + INFLUXDB_TOKEN + "\r\n";
request += "Content-Length: " + String(body.length()) + "\r\n";
if (body.length() > 0) {
request += "\r\n";
......
......@@ -14,7 +14,7 @@ void ResendManager::init() {
}
uint ResendManager::getLastResendFileId() const { // get the next file id to be resend
auto filesInDirectory = getFilesInDirectory(resendDirectoryPath);
auto filesInDirectory = SDUtilities::getFilesInDirectory(resendDirectoryPath);
// convert the file names to uint
std::list<uint> fileUintIDs;
......@@ -38,24 +38,24 @@ uint ResendManager::getLastResendFileId() const { // get the next file id to be
}
void ResendManager::createResendDirectory() const { // create directory if it doesn't exist
createDirectory("/resend");
SDUtilities::createDirectory("/resend");
}
void ResendManager::storeForResend(const String &messageToBeSend) {
// create file
String filename = String(nextResendFileId);
writeFile(messageToBeSend, resendDirectoryPath + "/" + filename);
SDUtilities::writeFile(messageToBeSend, resendDirectoryPath + "/" + filename);
ResendManager::incrementCount();
}
std::optional<ResendPointType> ResendManager::loadNextToBeResendMessage() {
// get first file in resend directory
auto filename = getFirstFileNameInDirectory(resendDirectoryPath.c_str());
auto filename = SDUtilities::getFirstFileNameInDirectory(resendDirectoryPath.c_str());
if (filename.has_value()) {
// read file
auto message = readFile(resendDirectoryPath + "/" + filename.value().c_str());
auto message = SDUtilities::readFile(resendDirectoryPath + "/" + filename.value().c_str());
return ResendPointType{message, filename.value()};
}
return std::nullopt;
......
......@@ -6,6 +6,7 @@
#define HOST_CENTRAL_MAST_DEFINITIONS_H
#include "Arduino.h"
#include "ESP32Time.h"
#define uS_TO_S_FACTOR 1000000ULL // Conversion factor for micro seconds to seconds
#define TIME_TO_SLEEP 5 // Time ESP32 will go to sleep (in seconds)
......@@ -22,6 +23,23 @@
#define SD_CS 13
#define LED_PIN 12
// See all AT commands, if wanted
// #define DUMP_AT_COMMANDS
#define TAG_ESPNOW "ESPNOW"
#define TAG_MAIN "MAIN"
#define TAG_SD "SD"
#define TAG_GSM "GSM"
#define TAG_TIMEMANAGER "TIMEMANAGER"
#define TAG_SDUTILITIES "SDUTILITIES"
#define SD_CARD_FAIL_COUNTER 100
constexpr bool PRINT_TO_SERIAL = true;
// global definition of RTC. Initialised in main
extern ESP32Time rtc;
const String INFLUXDB_TOKEN =
"dUh2gbVLv7e3egqocxriDsJQNUacA9qZ5YXsYtdnVAglnHgy4nx-jDVO7nGlSF34BosfnuwnUDaviC7dQeC5RQ==";
......
//
// Created by zoe on 1/24/23.
//
#include "SDCardLogger.h"
namespace SDCardLogger {
char log_print_buffer[512];
bool printToSerial = false;
void printDebugToSerial(bool printToSerialAsWell) {
printToSerial = printToSerialAsWell;
}
int vprintf_into_sd(const char *szFormat, va_list args) {
String logstring = "[" + rtc.getDateTime() + "] ";
logstring += szFormat;
if (!SDUtilities::isSDAvailable()) {
if (printToSerial) {
logstring += " (SD card not available)\n";
vprintf(logstring.c_str(), args);
}
return 1;
}
// 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");
SDUtilities::setSDAvailable(false);
return 1;
}
delay(50);
writeLog.close();
}
File logFile = SD.open(filename, FILE_APPEND);
// debug output
if (printToSerial) {
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;
}
} // namespace SDCardLogger
//
// Created by zoe on 1/24/23.
//
#ifndef HOST_CENTRAL_MAST_SDCARDLOGGER_H
#define HOST_CENTRAL_MAST_SDCARDLOGGER_H
#include "Definitions.h"
#include "SD.h"
#include "Utilities.h"
namespace SDCardLogger {
void printDebugToSerial(bool printToSerialAsWell);
int vprintf_into_sd(const char *szFormat, va_list args);
}; // namespace SDCardLogger
#endif // HOST_CENTRAL_MAST_SDCARDLOGGER_H
......@@ -4,148 +4,302 @@
#include "Utilities.h"
void setupSDCard();
void saveStringToSDCard(const std::string &dataString);
std::list<String> getFilesInDirectory(const String &dirname) {
std::list<String> files;
File dir = openDirectory(dirname);
while (true) {
File nextFile = dir.openNextFile();
if (!nextFile) {
break;
}
if (!nextFile.isDirectory()) {
files.emplace_back(nextFile.name());
}
nextFile.close();
}
return files;
}
namespace SDUtilities {
bool SDAvailable = true;
std::optional<String> getLastFileInDirectory(const String &dirname) {
void setSDAvailable(bool sdAvailable) {
SDAvailable = sdAvailable;
}
File root = openDirectory(dirname);
root.rewindDirectory();
// Used to try to remount SD card if it fails more than x times (100)
int sdFailCounter = 0;
bool isSDAvailable() {
return SDAvailable;
}
File file = root.openNextFile();
while (file) {
File nextFile = root.openNextFile();
if (!nextFile) {
break;
void tryRemountingSD() {
try {
setupSDCard(SD_MISO, SD_MOSI, SD_SCLK, SD_CS);
setSDAvailable(true);
} catch (SDSetupException &e) {
esp_log_write(ESP_LOG_ERROR, TAG_SDUTILITIES, "Couldn't remount SD card: %s\n", e.what());
}
file = nextFile;
sdFailCounter = 0;
}
// log
if (file) {
esp_log_write(ESP_LOG_INFO, "getLastFileInDirectory", "Last file name: %s\n", file.name());
return file.name();
} else {
esp_log_write(ESP_LOG_INFO, "getLastFileInDirectory", "No file found\n");
return std::nullopt;
bool checkSDAvailability(const String &errorMessage) {
if (!isSDAvailable()) {
sdFailCounter++;
if (sdFailCounter % SD_CARD_FAIL_COUNTER == 0) {
esp_log_write(ESP_LOG_ERROR, TAG_SDUTILITIES, "SD card not available. Trying to remount...\n");
tryRemountingSD();
}
String message = errorMessage + " (SD card not available, failed " + sdFailCounter + " times)\n";
esp_log_write(ESP_LOG_ERROR, TAG_SDUTILITIES, "%s", message.c_str());
// if re-mount was successful, this will be true
return isSDAvailable();
}
return true;
};
std::list<String> getFilesInDirectory(const String &dirname) {
if (!checkSDAvailability("Couldn't get files in directory " + dirname)) {
return {};
}
std::list<String> files;
File dir = openDirectory(dirname);
while (true) {
File nextFile = dir.openNextFile();
if (!nextFile) {
break;
}
if (!nextFile.isDirectory()) {
files.emplace_back(nextFile.name());
}
nextFile.close();
}
return files;
}
}
File openDirectory(const String &dirname) {
File root = SD.open(dirname);
if (!root) {
esp_log_write(ESP_LOG_ERROR, "openDirectory", "Failed to open directory\n");
throw;
std::optional<String> getLastFileInDirectory(const String &dirname) {
if (!checkSDAvailability("Couldn't get last file in directory " + dirname)) {
return std::nullopt;
}
File root = openDirectory(dirname);
root.rewindDirectory();
File file = root.openNextFile();
while (file) {
File nextFile = root.openNextFile();
if (!nextFile) {
break;
}
file = nextFile;
}
// log
if (file) {
esp_log_write(ESP_LOG_INFO, TAG_SDUTILITIES, "Last file name: %s\n", file.name());
return file.name();
} else {
esp_log_write(ESP_LOG_INFO, TAG_SDUTILITIES, "No file found\n");
return std::nullopt;
}
}
if (!root.isDirectory()) {
esp_log_write(ESP_LOG_ERROR, "openDirectory", "Not a directory\n");
throw;
File openDirectory(const String &dirname) {
if (!checkSDAvailability("Couldn't open directory " + dirname)) {
throw;
}
File root = SD.open(dirname);
if (!root) {
esp_log_write(ESP_LOG_ERROR, TAG_SDUTILITIES, "Failed to open directory\n");
throw;
}
if (!root.isDirectory()) {
esp_log_write(ESP_LOG_ERROR, TAG_SDUTILITIES, "Not a directory\n");
throw;
}
return root;
}
return root;
}
std::optional<String> getFirstFileNameInDirectory(const String &dirname) {
File root = openDirectory(dirname);
root.rewindDirectory();
std::optional<String> getFirstFileNameInDirectory(const String &dirname) {
File file = root.openNextFile();
if (file) {
esp_log_write(ESP_LOG_INFO, "getFirstFileNameInDirectory", "file found: %s\n", file.name());
return file.name();
} else {
esp_log_write(ESP_LOG_INFO, "getFirstFileNameInDirectory", "no file found\n");
return std::nullopt;
if (!checkSDAvailability("Couldn't get first file in directory " + dirname)) {
return std::nullopt;
}
File root = openDirectory(dirname);
root.rewindDirectory();
File file = root.openNextFile();
if (file) {
esp_log_write(ESP_LOG_INFO, TAG_SDUTILITIES, "file found: %s\n", file.name());
return file.name();
} else {
esp_log_write(ESP_LOG_INFO, TAG_SDUTILITIES, "no file found\n");
return std::nullopt;
}
}
}
File openForWrite(const String &filePath) {
File file = SD.open(filePath, FILE_WRITE);
if (!file) {
esp_log_write(ESP_LOG_ERROR, "SD", "Failed to open file for writing\n");
throw;
File openForWrite(const String &filePath) {
if (!checkSDAvailability("Couldn't open file " + filePath + " for writing")) {
throw;
}
File file = SD.open(filePath, FILE_WRITE);
if (!file) {
esp_log_write(ESP_LOG_ERROR, TAG_SDUTILITIES, "Failed to open file for writing\n");
throw;
}
return file;
}
return file;
}
File openForRead(const String &filePath) {
File file = SD.open(filePath, FILE_READ);
if (!file) {
esp_log_write(ESP_LOG_ERROR, "SD", "Failed to open file for reading\n");
throw;
File openForRead(const String &filePath) {
if (!checkSDAvailability("Couldn't open file " + filePath + " for reading")) {
throw;
}
File file = SD.open(filePath, FILE_READ);
if (!file) {
esp_log_write(ESP_LOG_ERROR, TAG_SDUTILITIES, "Failed to open file for reading\n");
throw;
}
return file;
}
return file;
}
void writeFile(const String &messageToBeSend, const String &filePath) {
File file = openForWrite(filePath);
if (file.print(messageToBeSend)) {
esp_log_write(ESP_LOG_INFO, "SD", "File written %s\n", filePath.c_str());
} else {
esp_log_write(ESP_LOG_ERROR, "SD", "Write failed %s\n", filePath.c_str());
throw;
void writeFile(const String &messageToBeSend, const String &filePath) {
if (!checkSDAvailability("Couldn't write to file " + filePath)) {
throw;
}
File file = openForWrite(filePath);
if (file.print(messageToBeSend)) {
esp_log_write(ESP_LOG_INFO, TAG_SDUTILITIES, "File written %s\n", filePath.c_str());
} else {
esp_log_write(ESP_LOG_ERROR, TAG_SDUTILITIES, "Write failed %s\n", filePath.c_str());
throw;
}
file.close();
}
file.close();
}
String readFile(const String &filePath) {
File file = openForRead(filePath);
String ret;
String readFile(const String &filePath) {
if (!checkSDAvailability("Couldn't read file " + filePath)) {
throw;
}
File file = openForRead(filePath);
while (file.available()) {
ret += (char)file.read();
String ret;
while (file.available()) {
ret += (char)file.read();
}
file.close();
return ret;
}
file.close();
return ret;
}
void createDirectory(const String &dirname) {
void createDirectory(const String &dirname) {
if (!SD.exists(dirname)) {
SD.mkdir(dirname);
esp_log_write(ESP_LOG_INFO, "createDirectory", "Created directory: %s\n", dirname.c_str());
} else {
esp_log_write(ESP_LOG_WARN, "createDirectory", "Directory already exists\n");
if (!checkSDAvailability("Couldn't create directory " + dirname)) {
throw;
}
if (!SD.exists(dirname)) {
SD.mkdir(dirname);
esp_log_write(ESP_LOG_INFO, TAG_SDUTILITIES, "Created directory: %s\n", dirname.c_str());
} else {
esp_log_write(ESP_LOG_WARN, TAG_SDUTILITIES, "Directory already exists\n");
}
}
}
void setupSDCard(int MISO, int MOSI, int SCLK, int CS) {
SPI.begin(SCLK, MISO, MOSI, CS);
if (!SD.begin(CS)) {
esp_log_write(ESP_LOG_ERROR, "Utilities", "Card MOUNT FAIL\n");
throw SDSetupException("Card MOUNT FAIL");
} else {
uint32_t cardSize = SD.cardSize() / (1024 * 1024);
String sdcardSizeString = "SDCard Size: " + String(cardSize) + "MB";
esp_log_write(ESP_LOG_DEBUG, "Utilities", "%s\n", sdcardSizeString.c_str());
void setupSDCard(int MISO, int MOSI, int SCLK, int CS) {
SPI.begin(SCLK, MISO, MOSI, CS);
if (!SD.begin(CS)) {
esp_log_write(ESP_LOG_ERROR, TAG_SDUTILITIES, "Card MOUNT FAIL\n");
throw SDSetupException("Card MOUNT FAIL");
} else {
uint32_t cardSize = SD.cardSize() / (1024 * 1024);
String sdcardSizeString = "SDCard Size: " + String(cardSize) + "MB";
esp_log_write(ESP_LOG_DEBUG, TAG_SDUTILITIES, "%s\n", sdcardSizeString.c_str());
}
}
}
void saveStringToSDCard(const std::string &dataString) {
File dataFile = SD.open("/datalog.txt", FILE_APPEND);
void saveStringToSDCard(const std::string &dataString) {
if (!checkSDAvailability("Couldn't save string to SD card")) {
throw SDCardException("Couldn't save string to SD card");
}
// if the file is available, write to it:
if (dataFile) {
if (dataString.length() > 0) {
dataFile.println(dataString.c_str());
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_SDUTILITIES, "error opening datalog.txt\n");
throw SDCardException("error opening datalog.txt");
}
dataFile.close();
}
// if the file isn't open, pop up an error:
else {
esp_log_write(ESP_LOG_ERROR, "Utilities", "error opening datalog.txt\n");
throw SDCardException("error opening datalog.txt");
} // namespace SDUtilities
// 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);
}
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, "MAC: %s\n", macAddress.c_str());
return macAddress;
}
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;
}
DynamicJsonDocument parseReceivedJsonData(char *data) {
DynamicJsonDocument doc(250);
auto error = deserializeJson(doc, data);
if (error) {
esp_log_write(ESP_LOG_ERROR, TAG_ESPNOW, "Error while parsing json: %s\n", error.c_str());
// TODO error handling
}
return doc;
}
String documentToServerReadableString(const DynamicJsonDocument &doc) {
StaticJsonDocument<1024> serverDoc;
String hostMacAddressString = WiFi.macAddress();
hostMacAddressString.replace(":", "");
hostMacAddressString.toLowerCase();
serverDoc["host"] = hostMacAddressString;
serverDoc["client"] = doc["clientMac"].as<String>();
serverDoc["sensorProtocol"] = doc["protocol"].as<String>();
serverDoc["protocolAddress"] = doc["channel"].as<String>();
serverDoc["hardwareName"] = doc["sensorName"].as<String>();
// each value is a element in the readigs array
JsonArray readings = serverDoc.createNestedArray("readings");
JsonObject reading = readings.createNestedObject();
reading["name"] = doc["measurementType"].as<String>();
reading["value"] = doc["value"].as<float>();
serverDoc["time"] = doc["timestamp"].as<uint32_t>();
String serverString;
serializeJson(serverDoc, serverString);
esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW, "Server readable data: %s\n", serverString.c_str());
return serverString;
}
\ No newline at end of file
......@@ -5,21 +5,34 @@
#ifndef HOST_CENTRAL_MAST_UTILITIES_H
#define HOST_CENTRAL_MAST_UTILITIES_H
#include "ArduinoJson.h"
#include "SD.h"
#include "SDCardException.h"
#include "SDSetupException.h"
#include "WiFi.h"
#include <Arduino.h>
#include <Definitions.h>
#include <WString.h>
#include <list>
File openDirectory(const String &dirname);
std::list<String> getFilesInDirectory(const String &dirname);
std::optional<String> getFirstFileNameInDirectory(const String &dirname);
std::optional<String> getLastFileInDirectory(const String &dirname);
void writeFile(const String &messageToBeSend, const String &filePath);
String readFile(const String &filePath);
void createDirectory(const String &dirname);
void setupSDCard(int MISO, int MOSI, int SCLK, int CS);
void saveStringToSDCard(const std::string &dataString);
namespace SDUtilities {
File openDirectory(const String &dirname);
std::list<String> getFilesInDirectory(const String &dirname);
std::optional<String> getFirstFileNameInDirectory(const String &dirname);
std::optional<String> getLastFileInDirectory(const String &dirname);
void writeFile(const String &messageToBeSend, const String &filePath);
String readFile(const String &filePath);
void createDirectory(const String &dirname);
void setupSDCard(int MISO, int MOSI, int SCLK, int CS);
void saveStringToSDCard(const std::string &dataString);
void setSDAvailable(bool sdAvailable);
bool isSDAvailable();
} // namespace SDUtilities
void turnOffLEDs();
String getMacAddressAsString(const uint8_t *mac);
String documentToLineProtocolString(const DynamicJsonDocument &doc);
DynamicJsonDocument parseReceivedJsonData(char *data);
String documentToServerReadableString(const DynamicJsonDocument &doc);
#endif // HOST_CENTRAL_MAST_UTILITIES_H
This diff is collapsed.
///**************************************************************
// *
// * This sketch connects to a website and downloads a page.
// * It can be used to perform HTTP/RESTful API calls.
// *
// * TinyGSM Getting Started guide:
// * https://tiny.cc/tinygsm-readme
// *
// **************************************************************/
//
//// Select your modem:
//// #define TINY_GSM_MODEM_SIM800
//// #define TINY_GSM_MODEM_SIM808
//// #define TINY_GSM_MODEM_SIM868
//// #define TINY_GSM_MODEM_SIM900
//#define TINY_GSM_MODEM_SIM7000
//// #define TINY_GSM_MODEM_SIM7000SSL
//// #define TINY_GSM_MODEM_SIM7080
//// #define TINY_GSM_MODEM_SIM5360
//// #define TINY_GSM_MODEM_SIM7600
//// #define TINY_GSM_MODEM_UBLOX
//// #define TINY_GSM_MODEM_SARAR4
//// #define TINY_GSM_MODEM_M95
//// #define TINY_GSM_MODEM_BG96
//// #define TINY_GSM_MODEM_A6
//// #define TINY_GSM_MODEM_A7
//// #define TINY_GSM_MODEM_M590
//// #define TINY_GSM_MODEM_MC60
//// #define TINY_GSM_MODEM_MC60E
//// #define TINY_GSM_MODEM_ESP8266
//// #define TINY_GSM_MODEM_XBEE
//// #define TINY_GSM_MODEM_SEQUANS_MONARCH
//
//// Set serial for debug console (to the Serial Monitor, default speed 115200)
//#define SerialMon Serial
//
//// Set serial for AT commands (to the module)
//// Use Hardware Serial on Mega, Leonardo, Micro
//#ifndef __AVR_ATmega328P__
//#define SerialAT Serial1
//
//// or Software Serial on Uno, Nano
//#else
//#include <SoftwareSerial.h>
//SoftwareSerial SerialAT(2, 3); // RX, TX
//#endif
//
//// Increase RX buffer to capture the entire response
//// Chips without internal buffering (A6/A7, ESP8266, M590)
//// need enough space in the buffer for the entire response
//// else data will be lost (and the http library will fail).
//#if !defined(TINY_GSM_RX_BUFFER)
//#define TINY_GSM_RX_BUFFER 650
//#endif
//
//// See all AT commands, if wanted
//#define DUMP_AT_COMMANDS
//
//// Define the serial console for debug prints, if needed
//#define TINY_GSM_DEBUG SerialMon
//
//// Range to attempt to autobaud
//// NOTE: DO NOT AUTOBAUD in production code. Once you've established
//// communication, set a fixed baud rate using modem.setBaud(#).
//#define GSM_AUTOBAUD_MIN 9600
//#define GSM_AUTOBAUD_MAX 115200
//
//// Add a reception delay, if needed.
//// This may be needed for a fast processor at a slow baud rate.
//// #define TINY_GSM_YIELD() { delay(2); }
//
//// Uncomment this if you want to use SSL
//// #define USE_SSL
//
//// Define how you're planning to connect to the internet.
//// This is only needed for this example, not in other code.
//#define TINY_GSM_USE_GPRS true
//#define TINY_GSM_USE_WIFI false
//
//// set GSM PIN, if any
//#define GSM_PIN ""
//
//// Your GPRS credentials, if any
//const char apn[] = "m2m.public.at";
//const char gprsUser[] = "";
//const char gprsPass[] = "";
//
//// Your WiFi connection credentials, if applicable
//const char wifiSSID[] = "YourSSID";
//const char wifiPass[] = "YourWiFiPass";
//
//// Server details
//const char server[] = "vsh.pp.ua";
//const char resource[] = "/TinyGSM/logo.txt";
//
//#include <TinyGsmClient.h>
//#include <WiFi.h>
//#include <esp_now.h>
//
//// Just in case someone defined the wrong thing..
//#if TINY_GSM_USE_GPRS && not defined TINY_GSM_MODEM_HAS_GPRS
//#undef TINY_GSM_USE_GPRS
//#undef TINY_GSM_USE_WIFI
//#define TINY_GSM_USE_GPRS false
//#define TINY_GSM_USE_WIFI true
//#endif
//#if TINY_GSM_USE_WIFI && not defined TINY_GSM_MODEM_HAS_WIFI
//#undef TINY_GSM_USE_GPRS
//#undef TINY_GSM_USE_WIFI
//#define TINY_GSM_USE_GPRS true
//#define TINY_GSM_USE_WIFI false
//#endif
//
//#ifdef DUMP_AT_COMMANDS
//#include <StreamDebugger.h>
//StreamDebugger debugger(SerialAT, SerialMon);
//TinyGsm modem(debugger);
//#else
//TinyGsm modem(SerialAT);
//#endif
//
//#ifdef USE_SSL
//TinyGsmClientSecure client_satellite(modem);
//const int port = 443;
//#else
//TinyGsmClient client_satellite(modem);
//const int port = 80;
//#endif
//
//TaskHandle_t Task1;
//
//void on_data_sent(const uint8_t *mac_addr, esp_now_send_status_t status)
//{
// // go to sleep
//}
//
//void on_data_recv(const uint8_t *mac, const uint8_t *incomingData, int len)
//{
// // print mac
// Serial.print("Message recieved: Core ");
// Serial.println(xPortGetCoreID());
// for (int i = 0; i < 6; i++) {
// Serial.print(mac[i], HEX);
// Serial.print(":");
// }
// Serial.println();
// char data[len];
// memcpy(data, incomingData, len);
// Serial.println(data);
//}
//
//[[noreturn]] void Task1code(void *parameter)
//{
// Serial.println(xPortGetCoreID());
// WiFi.mode(WIFI_STA);
// Serial.println("ESPNow init");
// if (esp_now_init() != ESP_OK) {
// // initialization failed
// Serial.println("ESPNow init failed");
// // not sure about this
// }
// Serial.println("ESPNow init success");
// esp_now_register_recv_cb(on_data_recv);
//
// while (true) {
// }
//}
//
//void setup2()
//{
// // Set console baud rate
// SerialMon.begin(115200);
// delay(10);
//
// // !!!!!!!!!!!
// // Set your reset, enable, power pins here
// // !!!!!!!!!!!
//
// SerialMon.println("Wait...");
//
// xTaskCreatePinnedToCore(Task1code, /* Function to implement the task */
// "Task1", /* Name of the task */
// 10000, /* Stack size in words */
// nullptr, /* Task input parameter */
// 0, /* Priority of the task */
// &Task1, /* Task handle. */
// 0); /* Core where the task should run */
//
// // Set GSM module baud rate
// // TinyGsmAutoBaud(SerialAT, GSM_AUTOBAUD_MIN, GSM_AUTOBAUD_MAX);
// modem.setBaud(9600);
// // SerialAT.begin(9600);
// delay(6000);
//
// // Restart takes quite some time
// // To skip it, call init() instead of restart()
// SerialMon.println("Initializing modem...");
// modem.restart();
// // modem.init();
//
// String modemInfo = modem.getModemInfo();
// SerialMon.print("Modem Info: ");
// SerialMon.println(modemInfo);
//
//#if TINY_GSM_USE_GPRS
// // Unlock your SIM card with a PIN if needed
// if (GSM_PIN && modem.getSimStatus() != 3) {
// modem.simUnlock(GSM_PIN);
// }
//#endif
//}
//
//void loop2()
//{
//#if TINY_GSM_USE_WIFI
// // Wifi connection parameters must be set before waiting for the network
// SerialMon.print(F("Setting SSID/password..."));
// if (!modem.networkConnect(wifiSSID, wifiPass)) {
// SerialMon.println(" fail");
// delay(10000);
// return;
// }
// SerialMon.println(" success");
//#endif
//
//#if TINY_GSM_USE_GPRS && defined TINY_GSM_MODEM_XBEE
// // The XBee must run the gprsConnect function BEFORE waiting for network!
// modem.gprsConnect(apn, gprsUser, gprsPass);
//#endif
//
// SerialMon.print("Waiting for network...");
// if (!modem.waitForNetwork()) {
// SerialMon.println(" fail");
// delay(10000);
// return;
// }
// SerialMon.println(" success");
//
// if (modem.isNetworkConnected()) {
// SerialMon.println("Network connected");
// }
//
//#if TINY_GSM_USE_GPRS
// // GPRS connection parameters are usually set after network registration
// SerialMon.print(F("Connecting to "));
// SerialMon.print(apn);
// if (!modem.gprsConnect(apn, gprsUser, gprsPass)) {
// SerialMon.println(" fail");
// delay(10000);
// return;
// }
// SerialMon.println(" success");
//
// if (modem.isGprsConnected()) {
// SerialMon.println("GPRS connected");
// }
//#endif
//
// SerialMon.print("Connecting to ");
// SerialMon.println(server);
// if (!client_satellite.connect(server, port)) {
// SerialMon.println(" fail");
// delay(10000);
// return;
// }
// SerialMon.println(" success");
//
// // Make a HTTP GET request:
// SerialMon.println("Performing HTTP GET request...");
// client_satellite.print(String("GET ") + resource + " HTTP/1.1\r\n");
// client_satellite.print(String("Host: ") + server + "\r\n");
// client_satellite.print("Connection: close\r\n\r\n");
// client_satellite.println();
//
// uint32_t timeout = millis();
// while (client_satellite.connected() && millis() - timeout < 10000L) {
// // Print available data
// while (client_satellite.available()) {
// char c = client_satellite.read();
// SerialMon.print(c);
// timeout = millis();
// }
// }
// SerialMon.println();
//
// // Shutdown
//
// client_satellite.stop();
// SerialMon.println(F("Server disconnected"));
//
//#if TINY_GSM_USE_WIFI
// modem.networkDisconnect();
// SerialMon.println(F("WiFi disconnected"));
//#endif
//#if TINY_GSM_USE_GPRS
// modem.gprsDisconnect();
// SerialMon.println(F("GPRS disconnected"));
//#endif
//
// // Do nothing forevermore
// while (true) {
// delay(1000);
// }
//}