Adding docker + shared lora settings

This commit is contained in:
Simon Milvert 2026-06-11 07:18:26 +00:00
parent dab36592a6
commit 7bf2947076
13 changed files with 99 additions and 51 deletions

18
.devcontainer/Dockerfile Normal file
View File

@ -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"]

View File

@ -0,0 +1,14 @@
{
"name": "Water Temp Dev Container",
"build": {
"dockerfile": "./Dockerfile"
},
"customizations": {
"vscode": {
"settings": {},
"extensions": [
"platformio.platformio-ide"
]
}
}
}

View File

@ -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 */

View File

@ -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 =

View File

@ -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>()) {

View File

@ -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:

View File

@ -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()

View File

@ -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

View File

@ -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>()) {

View File

@ -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:

View File

@ -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

View File

@ -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 {

View File

@ -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;