various implementations to increase measurement precision and lorawan performance
This commit is contained in:
parent
7be7ef0081
commit
71c0386229
95
setup_framework.sh
Normal file
95
setup_framework.sh
Normal 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"
|
||||||
@ -185,6 +185,29 @@ void init_lorawan()
|
|||||||
LOG_INF("LoraWan started successfully");
|
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 all LoRaWAN configuration for debugging */
|
||||||
print_lorawan_ids();
|
print_lorawan_ids();
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
0x0F, 0x0F}
|
0x0F, 0x0F}
|
||||||
|
|
||||||
#define RETRY_DELAY K_MSEC(1000)
|
#define RETRY_DELAY K_MSEC(1000)
|
||||||
#define SEND_INTERVALL K_MINUTES(5)
|
#define SEND_INTERVALL K_MINUTES(10)
|
||||||
|
|
||||||
void init_lorawan();
|
void init_lorawan();
|
||||||
|
|
||||||
|
|||||||
25
src/main.c
25
src/main.c
@ -17,7 +17,7 @@ LOG_MODULE_REGISTER(g2h_heat_main);
|
|||||||
volatile bool relais_state = false;
|
volatile bool relais_state = false;
|
||||||
volatile bool relais_manual_override = false;
|
volatile bool relais_manual_override = false;
|
||||||
volatile uint8_t temperature_threshold = 21;
|
volatile uint8_t temperature_threshold = 21;
|
||||||
volatile uint8_t floor_temp_threshold = 22;
|
volatile uint8_t floor_temp_threshold = 24;
|
||||||
|
|
||||||
/* MAIN */
|
/* MAIN */
|
||||||
int main(void)
|
int main(void)
|
||||||
@ -37,29 +37,32 @@ int main(void)
|
|||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
/* Get values from SHT4X */
|
/* Get stable values from sensors */
|
||||||
request_sensor_data_sht4x();
|
humidity = get_stable_value_sht4x(SENSOR_CHAN_HUMIDITY);
|
||||||
humidity = get_value_from_current_sample_sht4x(SENSOR_CHAN_HUMIDITY);
|
temp = get_stable_value_sht4x(SENSOR_CHAN_AMBIENT_TEMP);
|
||||||
temp = get_value_from_current_sample_sht4x(SENSOR_CHAN_AMBIENT_TEMP);
|
|
||||||
printk("hum: %d.%02d%%\n", (int)humidity, (int)(humidity * 100) % 100);
|
printk("hum: %d.%02d%%\n", (int)humidity, (int)(humidity * 100) % 100);
|
||||||
printk("temp: %d.%02d °C\n", (int)temp, (int)(temp * 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_stable_value_mlx90614(MLX90614_IR_TEMP_ADDR);
|
||||||
floor_temp = get_temp_from_raw_data_mlx90614();
|
|
||||||
printk("floor_temp: %d.%02d °C\n", (int)floor_temp, (int)(floor_temp * 100) % 100);
|
printk("floor_temp: %d.%02d °C\n", (int)floor_temp, (int)(floor_temp * 100) % 100);
|
||||||
|
|
||||||
/* Set relais based on temperature if not manually overridden */
|
/* Set relais based on temperature if not manually overridden */
|
||||||
if (!relais_manual_override) {
|
if (!relais_manual_override)
|
||||||
|
{
|
||||||
bool temp_condition = temp < temperature_threshold;
|
bool temp_condition = temp < temperature_threshold;
|
||||||
bool floor_condition = true; // Default: ignore floor temp if sensor not available
|
bool floor_condition = true; // Default: ignore floor temp if sensor not available
|
||||||
|
|
||||||
// Only check floor temperature if MLX sensor is working
|
// Only check floor temperature if MLX sensor is working
|
||||||
if (mlx90614_sensor_available) {
|
if (mlx90614_sensor_available)
|
||||||
|
{
|
||||||
floor_condition = floor_temp < floor_temp_threshold;
|
floor_condition = floor_temp < floor_temp_threshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (temp_condition && floor_condition) {
|
if (temp_condition && floor_condition)
|
||||||
|
{
|
||||||
relais_state = 1; // Heat on below thresholds
|
relais_state = 1; // Heat on below thresholds
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
relais_state = 0; // Heat off if any threshold exceeded
|
relais_state = 0; // Heat off if any threshold exceeded
|
||||||
}
|
}
|
||||||
set_relais_state(relais_state);
|
set_relais_state(relais_state);
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
#include <sensors/mlx90614.h>
|
#include <sensors/mlx90614.h>
|
||||||
|
#include <sensors/sensor_utils.h>
|
||||||
|
|
||||||
#include <zephyr/kernel.h>
|
#include <zephyr/kernel.h>
|
||||||
#include <zephyr/drivers/i2c.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
|
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
|
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;
|
||||||
|
}
|
||||||
@ -12,3 +12,5 @@ int init_mlx90614();
|
|||||||
void request_sensor_data_mlx90614(uint8_t target_addr);
|
void request_sensor_data_mlx90614(uint8_t target_addr);
|
||||||
|
|
||||||
float get_temp_from_raw_data_mlx90614();
|
float get_temp_from_raw_data_mlx90614();
|
||||||
|
|
||||||
|
float get_stable_value_mlx90614(uint8_t target_addr);
|
||||||
80
src/sensors/sensor_utils.c
Normal file
80
src/sensors/sensor_utils.c
Normal 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;
|
||||||
|
}
|
||||||
8
src/sensors/sensor_utils.h
Normal file
8
src/sensors/sensor_utils.h
Normal 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
|
||||||
@ -1,4 +1,5 @@
|
|||||||
#include <sensors/sht4x.h>
|
#include <sensors/sht4x.h>
|
||||||
|
#include <sensors/sensor_utils.h>
|
||||||
|
|
||||||
#include <zephyr/kernel.h>
|
#include <zephyr/kernel.h>
|
||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
@ -57,3 +58,30 @@ float get_value_from_current_sample_sht4x(enum sensor_channel sensor)
|
|||||||
}
|
}
|
||||||
return result;
|
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;
|
||||||
|
}
|
||||||
@ -7,3 +7,5 @@ void init_sht4x();
|
|||||||
void request_sensor_data_sht4x();
|
void request_sensor_data_sht4x();
|
||||||
|
|
||||||
float get_value_from_current_sample_sht4x(enum sensor_channel sensor);
|
float get_value_from_current_sample_sht4x(enum sensor_channel sensor);
|
||||||
|
|
||||||
|
float get_stable_value_sht4x(enum sensor_channel sensor);
|
||||||
Loading…
Reference in New Issue
Block a user