Adding docker + shared lora settings
This commit is contained in:
parent
dab36592a6
commit
7bf2947076
|
|
@ -0,0 +1,18 @@
|
||||||
|
FROM python:3.14.5-slim-bookworm
|
||||||
|
|
||||||
|
ENV PLATFORMIO_CORE_DIR=/workspace/.platformio
|
||||||
|
ENV PATH="/root/.platformio/penv/bin:${PATH}"
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
git \
|
||||||
|
build-essential \
|
||||||
|
ca-certificates \
|
||||||
|
udev \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
RUN python -m pip install --no-cache-dir --upgrade pip \
|
||||||
|
&& pip install --no-cache-dir platformio
|
||||||
|
|
||||||
|
WORKDIR /workspace
|
||||||
|
|
||||||
|
CMD ["pio", "run"]
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"name": "Water Temp Dev Container",
|
||||||
|
"build": {
|
||||||
|
"dockerfile": "./Dockerfile"
|
||||||
|
},
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
|
"settings": {},
|
||||||
|
"extensions": [
|
||||||
|
"platformio.platformio-ide"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef LORA_CONFIG_H
|
||||||
|
#define LORA_CONFIG_H
|
||||||
|
|
||||||
|
struct LoraConfig {
|
||||||
|
float frequency;
|
||||||
|
int spreadingFactor;
|
||||||
|
float signalBandwidth;
|
||||||
|
int codingRate4;
|
||||||
|
int power;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace LoraDefaults {
|
||||||
|
constexpr float frequency = 433.775f;
|
||||||
|
constexpr int spreadingFactor = 12;
|
||||||
|
constexpr float signalBandwidth = 125.0f;
|
||||||
|
constexpr int codingRate4 = 5;
|
||||||
|
constexpr int power = 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* LORA_CONFIG_H */
|
||||||
|
|
@ -15,6 +15,7 @@ framework = arduino
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
build_flags =
|
build_flags =
|
||||||
-D DEBUG
|
-D DEBUG
|
||||||
|
-I../common/include
|
||||||
-D MOCK_LORA
|
-D MOCK_LORA
|
||||||
-D MQTT_MAX_PACKET_SIZE=1024
|
-D MQTT_MAX_PACKET_SIZE=1024
|
||||||
lib_deps =
|
lib_deps =
|
||||||
|
|
|
||||||
|
|
@ -35,9 +35,9 @@ void Config::readFile(fs::FS &fs, const char *fileName)
|
||||||
mqtt.id = data["mqtt"]["id"].as<String>();
|
mqtt.id = data["mqtt"]["id"].as<String>();
|
||||||
|
|
||||||
LoraConfig lora;
|
LoraConfig lora;
|
||||||
lora.frequency = data["lora"]["frequency"].as<long>();
|
lora.frequency = data["lora"]["frequency"].as<float>();
|
||||||
lora.spreadingFactor = data["lora"]["spreadingFactor"].as<int>();
|
lora.spreadingFactor = data["lora"]["spreadingFactor"].as<int>();
|
||||||
lora.signalBandwidth = data["lora"]["signalBandwidth"].as<long>();
|
lora.signalBandwidth = data["lora"]["signalBandwidth"].as<float>();
|
||||||
lora.codingRate4 = data["lora"]["codingRate4"].as<int>();
|
lora.codingRate4 = data["lora"]["codingRate4"].as<int>();
|
||||||
lora.power = data["lora"]["power"].as<int>();
|
lora.power = data["lora"]["power"].as<int>();
|
||||||
logConfigInfo(data);
|
logConfigInfo(data);
|
||||||
|
|
@ -63,11 +63,11 @@ void Config::writeData()
|
||||||
mqttJson["topic"] = this->mqttConfig.topic;
|
mqttJson["topic"] = this->mqttConfig.topic;
|
||||||
|
|
||||||
JsonObject lora = doc["lora"].to<JsonObject>();
|
JsonObject lora = doc["lora"].to<JsonObject>();
|
||||||
lora["frequency"] = 433775000;
|
lora["frequency"] = LoraDefaults::frequency;
|
||||||
lora["spreadingFactor"] = 12;
|
lora["spreadingFactor"] = LoraDefaults::spreadingFactor;
|
||||||
lora["signalBandwidth"] = 125000;
|
lora["signalBandwidth"] = LoraDefaults::signalBandwidth;
|
||||||
lora["codingRate4"] = 5;
|
lora["codingRate4"] = LoraDefaults::codingRate4;
|
||||||
lora["power"] = 20;
|
lora["power"] = LoraDefaults::power;
|
||||||
|
|
||||||
// Delete existing file, otherwise the configuration is appended to the file
|
// Delete existing file, otherwise the configuration is appended to the file
|
||||||
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "CONFIG", "Write DATA to file");
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "CONFIG", "Write DATA to file");
|
||||||
|
|
@ -118,6 +118,8 @@ void Config::logConfigInfo(JsonDocument& doc) {
|
||||||
value = String(jsonValue.as<int>());
|
value = String(jsonValue.as<int>());
|
||||||
} else if (jsonValue.is<long>()) {
|
} else if (jsonValue.is<long>()) {
|
||||||
value = String(jsonValue.as<long>());
|
value = String(jsonValue.as<long>());
|
||||||
|
} else if (jsonValue.is<float>()) {
|
||||||
|
value = String(jsonValue.as<float>(), 3);
|
||||||
} else if (jsonValue.is<bool>()) {
|
} else if (jsonValue.is<bool>()) {
|
||||||
value = jsonValue.as<bool>() ? "true" : "false";
|
value = jsonValue.as<bool>() ? "true" : "false";
|
||||||
} else if (jsonValue.is<JsonArray>() || jsonValue.is<JsonObject>()) {
|
} else if (jsonValue.is<JsonArray>() || jsonValue.is<JsonObject>()) {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <FS.h>
|
#include <FS.h>
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
|
#include "lora_config.hpp"
|
||||||
|
|
||||||
class MqttConfig {
|
class MqttConfig {
|
||||||
public:
|
public:
|
||||||
|
|
@ -17,14 +18,6 @@ class MqttConfig {
|
||||||
void setMqtt(const String& server, const int& port, const String& username, const String& password, const String& topic);
|
void setMqtt(const String& server, const int& port, const String& username, const String& password, const String& topic);
|
||||||
};
|
};
|
||||||
|
|
||||||
class LoraConfig {
|
|
||||||
public:
|
|
||||||
long frequency;
|
|
||||||
int spreadingFactor;
|
|
||||||
long signalBandwidth;
|
|
||||||
int codingRate4;
|
|
||||||
int power;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Config {
|
class Config {
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,8 @@ void LoraHandler::setup()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure LoRa parameters
|
// Configure LoRa parameters
|
||||||
long freq = config.loraConfig.frequency;
|
const float freq = config.loraConfig.frequency;
|
||||||
|
const float bandwidth = config.loraConfig.signalBandwidth;
|
||||||
state = radio->setFrequency(freq);
|
state = radio->setFrequency(freq);
|
||||||
if (state != RADIOLIB_ERR_NONE)
|
if (state != RADIOLIB_ERR_NONE)
|
||||||
{
|
{
|
||||||
|
|
@ -52,7 +53,7 @@ void LoraHandler::setup()
|
||||||
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "LoRa", "setSpreadingFactor failed: %i", state);
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "LoRa", "setSpreadingFactor failed: %i", state);
|
||||||
}
|
}
|
||||||
|
|
||||||
state = radio->setBandwidth(config.loraConfig.signalBandwidth);
|
state = radio->setBandwidth(bandwidth);
|
||||||
if (state != RADIOLIB_ERR_NONE)
|
if (state != RADIOLIB_ERR_NONE)
|
||||||
{
|
{
|
||||||
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "LoRa", "setBandwidth failed: %i", state);
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "LoRa", "setBandwidth failed: %i", state);
|
||||||
|
|
@ -74,7 +75,7 @@ void LoraHandler::setup()
|
||||||
radio->setCRC(true);
|
radio->setCRC(true);
|
||||||
|
|
||||||
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "LoRa", "SX1278 initialized successfully!");
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "LoRa", "SX1278 initialized successfully!");
|
||||||
String currentLoRainfo = "LoRa Freq: " + String(freq) + " / SF:" + String(config.loraConfig.spreadingFactor) + " / CR: " + String(config.loraConfig.codingRate4);
|
String currentLoRainfo = "LoRa Freq: " + String(freq, 3) + " MHz / BW: " + String(bandwidth, 1) + " kHz / SF:" + String(config.loraConfig.spreadingFactor) + " / CR: " + String(config.loraConfig.codingRate4);
|
||||||
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "LoRa", currentLoRainfo.c_str());
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "LoRa", currentLoRainfo.c_str());
|
||||||
}
|
}
|
||||||
ReceivedLoRaPacket LoraHandler::receivePacket()
|
ReceivedLoRaPacket LoraHandler::receivePacket()
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ framework = arduino
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
build_flags =
|
build_flags =
|
||||||
-D DEBUG
|
-D DEBUG
|
||||||
|
-I../common/include
|
||||||
lib_deps =
|
lib_deps =
|
||||||
zinggjm/GxEPD2@^1.5.6
|
zinggjm/GxEPD2@^1.5.6
|
||||||
bblanchon/ArduinoJson@^7.0.4
|
bblanchon/ArduinoJson@^7.0.4
|
||||||
|
|
|
||||||
|
|
@ -28,9 +28,9 @@ void Config::readFile(fs::FS &fs, const char *fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
LoraConfig lora;
|
LoraConfig lora;
|
||||||
lora.frequency = data["lora"]["frequency"].as<long>();
|
lora.frequency = data["lora"]["frequency"].as<float>();
|
||||||
lora.spreadingFactor = data["lora"]["spreadingFactor"].as<int>();
|
lora.spreadingFactor = data["lora"]["spreadingFactor"].as<int>();
|
||||||
lora.signalBandwidth = data["lora"]["signalBandwidth"].as<long>();
|
lora.signalBandwidth = data["lora"]["signalBandwidth"].as<float>();
|
||||||
lora.codingRate4 = data["lora"]["codingRate4"].as<int>();
|
lora.codingRate4 = data["lora"]["codingRate4"].as<int>();
|
||||||
lora.power = data["lora"]["power"].as<int>();
|
lora.power = data["lora"]["power"].as<int>();
|
||||||
logConfigInfo(data);
|
logConfigInfo(data);
|
||||||
|
|
@ -47,11 +47,11 @@ void Config::writeData()
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
|
|
||||||
JsonObject lora = doc["lora"].to<JsonObject>();
|
JsonObject lora = doc["lora"].to<JsonObject>();
|
||||||
lora["frequency"] = 433775000;
|
lora["frequency"] = LoraDefaults::frequency;
|
||||||
lora["spreadingFactor"] = 12;
|
lora["spreadingFactor"] = LoraDefaults::spreadingFactor;
|
||||||
lora["signalBandwidth"] = 125000;
|
lora["signalBandwidth"] = LoraDefaults::signalBandwidth;
|
||||||
lora["codingRate4"] = 5;
|
lora["codingRate4"] = LoraDefaults::codingRate4;
|
||||||
lora["power"] = 20;
|
lora["power"] = LoraDefaults::power;
|
||||||
|
|
||||||
// Delete existing file, otherwise the configuration is appended to the file
|
// Delete existing file, otherwise the configuration is appended to the file
|
||||||
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "CONFIG", "Write DATA to file");
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "CONFIG", "Write DATA to file");
|
||||||
|
|
@ -95,6 +95,8 @@ void Config::logConfigInfo(JsonDocument& doc) {
|
||||||
value = String(jsonValue.as<int>());
|
value = String(jsonValue.as<int>());
|
||||||
} else if (jsonValue.is<long>()) {
|
} else if (jsonValue.is<long>()) {
|
||||||
value = String(jsonValue.as<long>());
|
value = String(jsonValue.as<long>());
|
||||||
|
} else if (jsonValue.is<float>()) {
|
||||||
|
value = String(jsonValue.as<float>(), 3);
|
||||||
} else if (jsonValue.is<bool>()) {
|
} else if (jsonValue.is<bool>()) {
|
||||||
value = jsonValue.as<bool>() ? "true" : "false";
|
value = jsonValue.as<bool>() ? "true" : "false";
|
||||||
} else if (jsonValue.is<JsonArray>() || jsonValue.is<JsonObject>()) {
|
} else if (jsonValue.is<JsonArray>() || jsonValue.is<JsonObject>()) {
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,9 @@
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <FS.h>
|
#include <FS.h>
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
|
#include "lora_config.hpp"
|
||||||
|
|
||||||
|
|
||||||
class LoraConfig {
|
|
||||||
public:
|
|
||||||
long frequency;
|
|
||||||
int spreadingFactor;
|
|
||||||
long signalBandwidth;
|
|
||||||
int codingRate4;
|
|
||||||
int power;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Config {
|
class Config {
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,7 @@
|
||||||
extern logging::Logger logger;
|
extern logging::Logger logger;
|
||||||
extern Config config;
|
extern Config config;
|
||||||
|
|
||||||
LoraHandler::LoraHandler() {
|
LoraHandler::LoraHandler() : radio(nullptr), spi(nullptr) {}
|
||||||
// Initialize with new SX1268 radio
|
|
||||||
}
|
|
||||||
|
|
||||||
void LoraHandler::setup()
|
void LoraHandler::setup()
|
||||||
{
|
{
|
||||||
|
|
@ -19,7 +17,7 @@ void LoraHandler::setup()
|
||||||
spi->begin(RADIO_SCK, RADIO_MISO, RADIO_MOSI, RADIO_CS);
|
spi->begin(RADIO_SCK, RADIO_MISO, RADIO_MOSI, RADIO_CS);
|
||||||
|
|
||||||
// Create SX1268 instance
|
// Create SX1268 instance
|
||||||
radio = new SX1268(new SPIDriver(spi, RADIO_CS));
|
radio = new SX1268(new Module(RADIO_CS, RADIO_IRQ, RADIO_RST, RADIOLIB_NC, *spi));
|
||||||
|
|
||||||
// Configure RXEN/TXEN pins
|
// Configure RXEN/TXEN pins
|
||||||
pinMode(RADIO_RXEN, OUTPUT);
|
pinMode(RADIO_RXEN, OUTPUT);
|
||||||
|
|
@ -27,6 +25,9 @@ void LoraHandler::setup()
|
||||||
digitalWrite(RADIO_RXEN, LOW);
|
digitalWrite(RADIO_RXEN, LOW);
|
||||||
digitalWrite(RADIO_TXEN, LOW);
|
digitalWrite(RADIO_TXEN, LOW);
|
||||||
|
|
||||||
|
const float freq = config.loraConfig.frequency;
|
||||||
|
const float bandwidth = config.loraConfig.signalBandwidth;
|
||||||
|
|
||||||
// Initialize LoRa module
|
// Initialize LoRa module
|
||||||
int state = radio->begin();
|
int state = radio->begin();
|
||||||
if (state != RADIOLIB_ERR_NONE)
|
if (state != RADIOLIB_ERR_NONE)
|
||||||
|
|
@ -38,7 +39,6 @@ void LoraHandler::setup()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure LoRa parameters
|
// Configure LoRa parameters
|
||||||
long freq = config.loraConfig.frequency;
|
|
||||||
state = radio->setFrequency(freq);
|
state = radio->setFrequency(freq);
|
||||||
if (state != RADIOLIB_ERR_NONE)
|
if (state != RADIOLIB_ERR_NONE)
|
||||||
{
|
{
|
||||||
|
|
@ -51,7 +51,7 @@ void LoraHandler::setup()
|
||||||
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "LoRa", "setSpreadingFactor failed: %i", state);
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "LoRa", "setSpreadingFactor failed: %i", state);
|
||||||
}
|
}
|
||||||
|
|
||||||
state = radio->setBandwidth(config.loraConfig.signalBandwidth);
|
state = radio->setBandwidth(bandwidth);
|
||||||
if (state != RADIOLIB_ERR_NONE)
|
if (state != RADIOLIB_ERR_NONE)
|
||||||
{
|
{
|
||||||
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "LoRa", "setBandwidth failed: %i", state);
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "LoRa", "setBandwidth failed: %i", state);
|
||||||
|
|
@ -69,11 +69,15 @@ void LoraHandler::setup()
|
||||||
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "LoRa", "setOutputPower failed: %i", state);
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "LoRa", "setOutputPower failed: %i", state);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable CRC
|
// Enable 2-byte LoRa CRC
|
||||||
radio->setCRC(true);
|
state = radio->setCRC(2);
|
||||||
|
if (state != RADIOLIB_ERR_NONE)
|
||||||
|
{
|
||||||
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_ERROR, "LoRa", "setCRC failed: %i", state);
|
||||||
|
}
|
||||||
|
|
||||||
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "LoRa", "SX1268 initialized successfully!");
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "LoRa", "SX1268 initialized successfully!");
|
||||||
String currentLoRainfo = "LoRa Freq: " + String(freq) + " / SF:" + String(config.loraConfig.spreadingFactor) + " / CR: " + String(config.loraConfig.codingRate4);
|
String currentLoRainfo = "LoRa Freq: " + String(freq, 3) + " MHz / BW: " + String(bandwidth, 1) + " kHz / SF:" + String(config.loraConfig.spreadingFactor) + " / CR: " + String(config.loraConfig.codingRate4);
|
||||||
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "LoRa", currentLoRainfo.c_str());
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "LoRa", currentLoRainfo.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -86,7 +90,8 @@ void LoraHandler::sendPacket(const String& data)
|
||||||
digitalWrite(RADIO_RXEN, LOW);
|
digitalWrite(RADIO_RXEN, LOW);
|
||||||
delay(10);
|
delay(10);
|
||||||
|
|
||||||
int state = radio->transmit(data);
|
String payload = data;
|
||||||
|
int state = radio->transmit(payload);
|
||||||
|
|
||||||
// Disable TX mode
|
// Disable TX mode
|
||||||
digitalWrite(RADIO_TXEN, LOW);
|
digitalWrite(RADIO_TXEN, LOW);
|
||||||
|
|
@ -109,22 +114,19 @@ ReceivedLoRaPacket LoraHandler::receivePacket()
|
||||||
digitalWrite(RADIO_RXEN, HIGH);
|
digitalWrite(RADIO_RXEN, HIGH);
|
||||||
digitalWrite(RADIO_TXEN, LOW);
|
digitalWrite(RADIO_TXEN, LOW);
|
||||||
|
|
||||||
int state = radio->receive(0); // 0 = non-blocking
|
int state = radio->receive(receivedLoraPacket.text);
|
||||||
|
|
||||||
if (state == RADIOLIB_ERR_RX_ONGOING)
|
if (state == RADIOLIB_ERR_RX_TIMEOUT)
|
||||||
{
|
{
|
||||||
// No packet received yet
|
|
||||||
return receivedLoraPacket;
|
return receivedLoraPacket;
|
||||||
}
|
}
|
||||||
else if (state == RADIOLIB_ERR_NONE)
|
else if (state == RADIOLIB_ERR_NONE)
|
||||||
{
|
{
|
||||||
// Packet received!
|
|
||||||
receivedLoraPacket.text = radio->readData();
|
|
||||||
receivedLoraPacket.rssi = radio->getRSSI();
|
receivedLoraPacket.rssi = radio->getRSSI();
|
||||||
receivedLoraPacket.snr = radio->getSNR();
|
receivedLoraPacket.snr = radio->getSNR();
|
||||||
receivedLoraPacket.freqError = radio->getFrequencyError();
|
receivedLoraPacket.freqError = radio->getFrequencyError();
|
||||||
|
|
||||||
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "LoRa Rx", "---> %s (RSSI: %d, SNR: %.1f)",
|
logger.log(logging::LoggerLevel::LOGGER_LEVEL_INFO, "LoRa Rx", "---> %s (RSSI: %.1f, SNR: %.1f)",
|
||||||
receivedLoraPacket.text.c_str(), receivedLoraPacket.rssi, receivedLoraPacket.snr);
|
receivedLoraPacket.text.c_str(), receivedLoraPacket.rssi, receivedLoraPacket.snr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@
|
||||||
|
|
||||||
struct ReceivedLoRaPacket {
|
struct ReceivedLoRaPacket {
|
||||||
String text;
|
String text;
|
||||||
int rssi;
|
float rssi;
|
||||||
float snr;
|
float snr;
|
||||||
int freqError;
|
float freqError;
|
||||||
};
|
};
|
||||||
|
|
||||||
class LoraHandler {
|
class LoraHandler {
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
logging::Logger logger;
|
logging::Logger logger;
|
||||||
|
Config config;
|
||||||
Eink eink;
|
Eink eink;
|
||||||
IO io;
|
IO io;
|
||||||
LoraHandler lora;
|
LoraHandler lora;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue