From 71c038622985a5c4c85d7a5debd2a6cb71b0a95a Mon Sep 17 00:00:00 2001 From: xlemmingx Date: Mon, 3 Nov 2025 13:38:12 +0100 Subject: [PATCH] various implementations to increase measurement precision and lorawan performance --- setup_framework.sh | 95 ++++++++++++++++++++++++++++++++++++++ src/lora/lorawan.c | 23 +++++++++ src/lora/lorawan.h | 2 +- src/main.c | 31 +++++++------ src/sensors/mlx90614.c | 40 ++++++++++++++++ src/sensors/mlx90614.h | 4 +- src/sensors/sensor_utils.c | 80 ++++++++++++++++++++++++++++++++ src/sensors/sensor_utils.h | 8 ++++ src/sensors/sht4x.c | 28 +++++++++++ src/sensors/sht4x.h | 4 +- 10 files changed, 298 insertions(+), 17 deletions(-) create mode 100644 setup_framework.sh create mode 100644 src/sensors/sensor_utils.c create mode 100644 src/sensors/sensor_utils.h diff --git a/setup_framework.sh b/setup_framework.sh new file mode 100644 index 0000000..b1fcff8 --- /dev/null +++ b/setup_framework.sh @@ -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" \ No newline at end of file diff --git a/src/lora/lorawan.c b/src/lora/lorawan.c index 0207027..0ccbd1c 100644 --- a/src/lora/lorawan.c +++ b/src/lora/lorawan.c @@ -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(); diff --git a/src/lora/lorawan.h b/src/lora/lorawan.h index ff135f4..d75d1cc 100644 --- a/src/lora/lorawan.h +++ b/src/lora/lorawan.h @@ -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(); diff --git a/src/main.c b/src/main.c index cc80231..d8c6e7d 100644 --- a/src/main.c +++ b/src/main.c @@ -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]; diff --git a/src/sensors/mlx90614.c b/src/sensors/mlx90614.c index 9f77677..b613a91 100644 --- a/src/sensors/mlx90614.c +++ b/src/sensors/mlx90614.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -51,4 +52,43 @@ 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; } \ No newline at end of file diff --git a/src/sensors/mlx90614.h b/src/sensors/mlx90614.h index 179a33f..e894671 100644 --- a/src/sensors/mlx90614.h +++ b/src/sensors/mlx90614.h @@ -11,4 +11,6 @@ int init_mlx90614(); void request_sensor_data_mlx90614(uint8_t target_addr); -float get_temp_from_raw_data_mlx90614(); \ No newline at end of file +float get_temp_from_raw_data_mlx90614(); + +float get_stable_value_mlx90614(uint8_t target_addr); \ No newline at end of file diff --git a/src/sensors/sensor_utils.c b/src/sensors/sensor_utils.c new file mode 100644 index 0000000..c66ae42 --- /dev/null +++ b/src/sensors/sensor_utils.c @@ -0,0 +1,80 @@ +#include "sensor_utils.h" +#include +#include +#include + +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; +} \ No newline at end of file diff --git a/src/sensors/sensor_utils.h b/src/sensors/sensor_utils.h new file mode 100644 index 0000000..44e6d79 --- /dev/null +++ b/src/sensors/sensor_utils.h @@ -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 \ No newline at end of file diff --git a/src/sensors/sht4x.c b/src/sensors/sht4x.c index 4a6247a..7b45f3e 100644 --- a/src/sensors/sht4x.c +++ b/src/sensors/sht4x.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -56,4 +57,31 @@ float get_value_from_current_sample_sht4x(enum sensor_channel sensor) return 0.0; } 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; } \ No newline at end of file diff --git a/src/sensors/sht4x.h b/src/sensors/sht4x.h index e701722..ddd513c 100644 --- a/src/sensors/sht4x.h +++ b/src/sensors/sht4x.h @@ -6,4 +6,6 @@ void init_sht4x(); void request_sensor_data_sht4x(); -float get_value_from_current_sample_sht4x(enum sensor_channel sensor); \ No newline at end of file +float get_value_from_current_sample_sht4x(enum sensor_channel sensor); + +float get_stable_value_sht4x(enum sensor_channel sensor); \ No newline at end of file