various implementations to increase measurement precision and lorawan performance

This commit is contained in:
xlemmingx 2025-11-03 13:38:12 +01:00
parent 7be7ef0081
commit 71c0386229
10 changed files with 298 additions and 17 deletions

95
setup_framework.sh Normal file
View File

@ -0,0 +1,95 @@
#!/bin/bash
# Script to setup framework modifications for STM32WL LoRaWAN project
# Usage: ./setup_framework.sh
set -e
echo "Setting up framework modifications for STM32WL LoRaWAN build..."
# Find PlatformIO packages directory
if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" ]]; then
# Windows
PIO_PACKAGES="$HOME/.platformio/packages"
else
# Linux/macOS
PIO_PACKAGES="$HOME/.platformio/packages"
fi
FRAMEWORK_ZEPHYR="$PIO_PACKAGES/framework-zephyr"
LORAMAC_NODE="$FRAMEWORK_ZEPHYR/_pio/modules/lib/loramac-node"
echo "PlatformIO packages: $PIO_PACKAGES"
echo "Framework Zephyr: $FRAMEWORK_ZEPHYR"
# Check if framework exists
if [ ! -d "$FRAMEWORK_ZEPHYR" ]; then
echo "Error: Zephyr framework not found at $FRAMEWORK_ZEPHYR"
echo "Please run 'pio run' first to download the framework"
exit 1
fi
if [ ! -d "$LORAMAC_NODE" ]; then
echo "Error: LoRaMAC-Node not found at $LORAMAC_NODE"
exit 1
fi
echo "✓ Framework directories found"
# 1. Remove conflicting sx126x.c from LoRaMAC-Node
CONFLICTING_FILE="$LORAMAC_NODE/src/radio/sx126x/sx126x.c"
if [ -f "$CONFLICTING_FILE" ]; then
echo "Removing conflicting sx126x.c..."
rm "$CONFLICTING_FILE"
echo "✓ Removed $CONFLICTING_FILE"
else
echo "✓ sx126x.c already removed"
fi
# 2. Create radio_sx126x.c from original sx126x.c
RADIO_SX126X="$LORAMAC_NODE/src/radio/sx126x/radio_sx126x.c"
if [ ! -f "$RADIO_SX126X" ]; then
echo "Creating radio_sx126x.c from git repository..."
cd "$LORAMAC_NODE"
git show HEAD:src/radio/sx126x/sx126x.c > src/radio/sx126x/radio_sx126x.c
echo "✓ Created radio_sx126x.c"
else
echo "✓ radio_sx126x.c already exists"
fi
# 3. Update CMakeLists.txt
CMAKE_FILE="$FRAMEWORK_ZEPHYR/modules/loramac-node/CMakeLists.txt"
echo "Updating CMakeLists.txt..."
# Create backup
cp "$CMAKE_FILE" "$CMAKE_FILE.backup"
# Replace the CONFIG_HAS_SEMTECH_SX126X section
sed -i '/zephyr_library_sources_ifdef(CONFIG_HAS_SEMTECH_SX126X/,/^)/{
/zephyr_library_sources_ifdef(CONFIG_HAS_SEMTECH_SX126X/!{
/^)/!d
}
}' "$CMAKE_FILE"
# Insert the new configuration
sed -i '/zephyr_library_sources_ifdef(CONFIG_HAS_SEMTECH_SX126X/a\
${ZEPHYR_LORAMAC_NODE_MODULE_DIR}/src/radio/sx126x/radio.c\
${ZEPHYR_LORAMAC_NODE_MODULE_DIR}/src/radio/sx126x/radio_sx126x.c' "$CMAKE_FILE"
echo "✓ Updated $CMAKE_FILE"
echo ""
echo "🎉 Framework setup complete!"
echo ""
echo "Summary of changes:"
echo " - Removed: $CONFLICTING_FILE"
echo " - Created: $RADIO_SX126X"
echo " - Updated: $CMAKE_FILE"
echo ""
echo "You can now run 'pio run' to build the project."
echo ""
echo "To restore original framework:"
echo " git restore $CONFLICTING_FILE"
echo " rm $RADIO_SX126X"
echo " mv $CMAKE_FILE.backup $CMAKE_FILE"

View File

@ -185,6 +185,29 @@ void init_lorawan()
LOG_INF("LoraWan started successfully");
}
/* Apply LoRaWAN performance optimizations */
LOG_INF("Applying LoRaWAN performance optimizations...");
/* Enable ADR for automatic datarate optimization */
lorawan_enable_adr(true);
LOG_INF("✓ ADR (Adaptive Data Rate) enabled");
/* Set to SF12 (DR0) for maximum range - good for 5-10min intervals */
int ret = lorawan_set_datarate(LORAWAN_DR_0);
if (ret == 0) {
LOG_INF("✓ Datarate set to DR0 (SF12) for maximum range");
} else {
LOG_WRN("Could not set datarate (ADR may override): %d", ret);
}
/* Increase confirmation retries for better reliability */
ret = lorawan_set_conf_msg_tries(8);
if (ret == 0) {
LOG_INF("✓ Confirmation retries set to 8 for better reliability");
} else {
LOG_WRN("Could not set confirmation retries: %d", ret);
}
/* Print all LoRaWAN configuration for debugging */
print_lorawan_ids();

View File

@ -20,7 +20,7 @@
0x0F, 0x0F}
#define RETRY_DELAY K_MSEC(1000)
#define SEND_INTERVALL K_MINUTES(5)
#define SEND_INTERVALL K_MINUTES(10)
void init_lorawan();

View File

@ -17,7 +17,7 @@ LOG_MODULE_REGISTER(g2h_heat_main);
volatile bool relais_state = false;
volatile bool relais_manual_override = false;
volatile uint8_t temperature_threshold = 21;
volatile uint8_t floor_temp_threshold = 22;
volatile uint8_t floor_temp_threshold = 24;
/* MAIN */
int main(void)
@ -37,35 +37,38 @@ int main(void)
while (true)
{
/* Get values from SHT4X */
request_sensor_data_sht4x();
humidity = get_value_from_current_sample_sht4x(SENSOR_CHAN_HUMIDITY);
temp = get_value_from_current_sample_sht4x(SENSOR_CHAN_AMBIENT_TEMP);
/* Get stable values from sensors */
humidity = get_stable_value_sht4x(SENSOR_CHAN_HUMIDITY);
temp = get_stable_value_sht4x(SENSOR_CHAN_AMBIENT_TEMP);
printk("hum: %d.%02d%%\n", (int)humidity, (int)(humidity * 100) % 100);
printk("temp: %d.%02d °C\n", (int)temp, (int)(temp * 100) % 100);
request_sensor_data_mlx90614(MLX90614_IR_TEMP_ADDR);
floor_temp = get_temp_from_raw_data_mlx90614();
floor_temp = get_stable_value_mlx90614(MLX90614_IR_TEMP_ADDR);
printk("floor_temp: %d.%02d °C\n", (int)floor_temp, (int)(floor_temp * 100) % 100);
/* Set relais based on temperature if not manually overridden */
if (!relais_manual_override) {
if (!relais_manual_override)
{
bool temp_condition = temp < temperature_threshold;
bool floor_condition = true; // Default: ignore floor temp if sensor not available
// Only check floor temperature if MLX sensor is working
if (mlx90614_sensor_available) {
if (mlx90614_sensor_available)
{
floor_condition = floor_temp < floor_temp_threshold;
}
if (temp_condition && floor_condition) {
relais_state = 1; // Heat on below thresholds
} else {
relais_state = 0; // Heat off if any threshold exceeded
if (temp_condition && floor_condition)
{
relais_state = 1; // Heat on below thresholds
}
else
{
relais_state = 0; // Heat off if any threshold exceeded
}
set_relais_state(relais_state);
}
printk("relais: %d (manual: %d, temp_th: %d°C, floor_th: %d°C)\n",
relais_state, relais_manual_override, temperature_threshold, floor_temp_threshold);
relais_state, relais_manual_override, temperature_threshold, floor_temp_threshold);
/* Pack and send values */
char data[7];

View File

@ -1,4 +1,5 @@
#include <sensors/mlx90614.h>
#include <sensors/sensor_utils.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/i2c.h>
@ -52,3 +53,42 @@ float get_temp_from_raw_data_mlx90614()
int16_t temperature = (read_data_buffer[1] << 8) | read_data_buffer[0]; // Temperaturwert aus den empfangenen Daten
return temperature * 0.02 - 273.15; // Umrechnung in Celsius
}
static float read_mlx_ambient_temp(void)
{
// Schnell-Check: wenn bereits bekannt dass Sensor nicht verfügbar ist
if (!mlx90614_sensor_available) return 0.0;
request_sensor_data_mlx90614(MLX90614_INTERNAL_TEMP_ADDR);
if (!mlx90614_sensor_available) return 0.0;
return get_temp_from_raw_data_mlx90614();
}
static float read_mlx_object_temp(void)
{
// Schnell-Check: wenn bereits bekannt dass Sensor nicht verfügbar ist
if (!mlx90614_sensor_available) return 0.0;
request_sensor_data_mlx90614(MLX90614_IR_TEMP_ADDR);
if (!mlx90614_sensor_available) return 0.0;
return get_temp_from_raw_data_mlx90614();
}
float get_stable_value_mlx90614(uint8_t target_addr)
{
// Früher Ausstieg wenn Sensor nicht verfügbar
if (!mlx90614_sensor_available) {
LOG_DBG("MLX90614 not available, returning 0.0");
return 0.0;
}
const float TEMP_THRESHOLD = 2.0; // °C
if (target_addr == MLX90614_INTERNAL_TEMP_ADDR) {
return get_stable_sensor_value(read_mlx_ambient_temp, TEMP_THRESHOLD);
} else if (target_addr == MLX90614_IR_TEMP_ADDR) {
return get_stable_sensor_value(read_mlx_object_temp, TEMP_THRESHOLD);
}
return 0.0;
}

View File

@ -12,3 +12,5 @@ int init_mlx90614();
void request_sensor_data_mlx90614(uint8_t target_addr);
float get_temp_from_raw_data_mlx90614();
float get_stable_value_mlx90614(uint8_t target_addr);

View File

@ -0,0 +1,80 @@
#include "sensor_utils.h"
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <math.h>
LOG_MODULE_REGISTER(sensor_utils);
float get_stable_sensor_value(sensor_read_func_t read_func, float outlier_threshold)
{
const int MAX_SAMPLES = 5;
float measurements[MAX_SAMPLES];
int valid_count = 0;
// Sammle bis zu 5 Messungen
for (int i = 0; i < MAX_SAMPLES && valid_count < 3; i++) {
if (i > 0) {
k_sleep(K_MSEC(500)); // Pause gegen Selbsterhitzung
}
float value = read_func();
if (value != 0.0) {
measurements[valid_count] = value;
valid_count++;
}
}
if (valid_count == 0) {
return 0.0;
}
// Bei nur 1-2 Messungen, einfach mitteln
if (valid_count <= 2) {
float sum = 0;
for (int i = 0; i < valid_count; i++) {
sum += measurements[i];
}
return sum / valid_count;
}
// Ausreißer entfernen: Median-basierte Filterung
// Sortiere die Messungen
for (int i = 0; i < valid_count - 1; i++) {
for (int j = i + 1; j < valid_count; j++) {
if (measurements[i] > measurements[j]) {
float temp = measurements[i];
measurements[i] = measurements[j];
measurements[j] = temp;
}
}
}
// Median berechnen
float median = measurements[valid_count / 2];
// Werte filtern die zu weit vom Median entfernt sind
float sum = 0;
int filtered_count = 0;
for (int i = 0; i < valid_count; i++) {
if (fabs(measurements[i] - median) <= outlier_threshold) {
sum += measurements[i];
filtered_count++;
}
}
if (filtered_count > 0) {
float result = sum / filtered_count;
LOG_INF("Stable sensor value: %.2f (filtered %d/%d samples)",
result, filtered_count, valid_count);
return result;
}
// Fallback: einfacher Mittelwert wenn alle gefiltert wurden
float fallback = 0;
for (int i = 0; i < valid_count; i++) {
fallback += measurements[i];
}
return fallback / valid_count;
}

View File

@ -0,0 +1,8 @@
#ifndef SENSOR_UTILS_H
#define SENSOR_UTILS_H
typedef float (*sensor_read_func_t)(void);
float get_stable_sensor_value(sensor_read_func_t read_func, float outlier_threshold);
#endif

View File

@ -1,4 +1,5 @@
#include <sensors/sht4x.h>
#include <sensors/sensor_utils.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
@ -57,3 +58,30 @@ float get_value_from_current_sample_sht4x(enum sensor_channel sensor)
}
return result;
}
static float read_sht4x_temp(void)
{
request_sensor_data_sht4x();
return get_value_from_current_sample_sht4x(SENSOR_CHAN_AMBIENT_TEMP);
}
static float read_sht4x_humidity(void)
{
request_sensor_data_sht4x();
return get_value_from_current_sample_sht4x(SENSOR_CHAN_HUMIDITY);
}
float get_stable_value_sht4x(enum sensor_channel sensor)
{
const float TEMP_THRESHOLD = 2.0; // °C
const float HUMIDITY_THRESHOLD = 2.0; // %RH
if (sensor == SENSOR_CHAN_AMBIENT_TEMP) {
return get_stable_sensor_value(read_sht4x_temp, TEMP_THRESHOLD);
} else if (sensor == SENSOR_CHAN_HUMIDITY) {
return get_stable_sensor_value(read_sht4x_humidity, HUMIDITY_THRESHOLD);
}
return 0.0;
}

View File

@ -7,3 +7,5 @@ void init_sht4x();
void request_sensor_data_sht4x();
float get_value_from_current_sample_sht4x(enum sensor_channel sensor);
float get_stable_value_sht4x(enum sensor_channel sensor);