embedded_raumsenor_lorawan/src/lora/lorawan.c
xlemmingx 1ca573e8cc Switch to ABP activation and add temperature-based relay control
- Switch from OTAA to ABP for reliable network joining
- Use SHT4X temperature sensor instead of MLX90614 internal temp
- Add automatic relay control based on 21°C threshold
- Add manual override capability via downlink commands
- Update device tree for Rev 2.1 board compatibility
- Improve logging configuration to prevent message drops
2025-10-07 17:40:57 +02:00

349 lines
8.7 KiB
C

#include <zephyr/logging/log.h>
#include <zephyr/settings/settings.h>
#include <zephyr/random/random.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/util.h>
#include <lora/lorawan.h>
#include <gpio.h>
#define SETTINGS_KEY "LORAWAN_DEV_NONCE"
LOG_MODULE_REGISTER(lorawan_class_a);
extern bool relais_state;
extern bool relais_manual_override;
const static struct device *lora_dev;
static struct lorawan_join_config join_cfg;
static uint8_t dev_eui[8];
/* OTAA keys */
static uint8_t app_key[] = LORAWAN_APP_KEY;
static uint8_t join_eui[] = LORAWAN_APP_EUI;
/* ABP keys and address */
static uint32_t dev_addr = 0x5FC69401; // Little endian of {0x01, 0x94, 0xC6, 0x5F}
static uint8_t nwks_key[] = LORAWAN_NWKS_KEY;
static uint8_t apps_key[] = LORAWAN_APPS_KEY;
static void dl_callback(uint8_t port, uint8_t flags, int16_t rssi, int8_t snr, uint8_t len,
const uint8_t *hex_data)
{
LOG_INF("Port %d, Pending %d, RSSI %ddB, SNR %ddBm, Len: %d, Time %d", port,
flags & LORAWAN_DATA_PENDING, rssi, snr, len, !!(flags & LORAWAN_TIME_UPDATED));
if (hex_data)
{
LOG_HEXDUMP_INF(hex_data, len, "Payload: ");
}
/* Could be moved in a separate thread so we only have to set the variable here */
if (len > 3 && hex_data[0] == 'r' && hex_data[1] == '1')
{
uint8_t relais_value = hex_data[3];
LOG_INF("Received relais1 state change: %d", relais_value);
if (get_relais_state() != relais_value)
{
set_relais_state(relais_value);
LOG_INF("Set relais 1 value");
}
relais_state = relais_value;
relais_manual_override = true;
}
}
struct lorawan_downlink_cb downlink_cb = {
.port = LW_RECV_PORT_ANY,
.cb = dl_callback};
static void print_lorawan_ids(void)
{
LOG_INF("=== LoRaWAN Configuration ===");
/* Print DevEUI */
printk("DevEUI: ");
for (int i = 0; i < 8; i++)
{
printk("%02X", dev_eui[i]);
if (i < 7)
printk(":");
}
printk("\n");
/* Print AppEUI (JoinEUI) */
printk("AppEUI: ");
for (int i = 0; i < 8; i++)
{
printk("%02X", join_eui[i]);
if (i < 7)
printk(":");
}
printk("\n");
/* Print AppKey */
printk("AppKey: ");
for (int i = 0; i < 16; i++)
{
printk("%02X", app_key[i]);
if (i < 15)
printk(":");
}
printk("\n");
LOG_INF("=============================");
}
void init_lorawan()
{
/* set dev eui from MCU-ID (UID) of STM32WL */
uint32_t uid_l = HAL_GetUIDw0();
uint32_t uid_h = HAL_GetUIDw1();
/* Debug: Check chip revisions */
uint32_t hal_version = HAL_GetHalVersion();
uint32_t rev_id = HAL_GetREVID();
uint32_t dev_id = HAL_GetDEVID();
LOG_INF("=== STM32WL CHIP REVISION INFO ===");
LOG_INF("HAL Version: 0x%08X", hal_version);
LOG_INF("Revision ID: 0x%08X", rev_id);
LOG_INF("Device ID: 0x%08X", dev_id);
LOG_INF("MCU UID: High=0x%08X, Low=0x%08X", uid_h, uid_l);
LOG_INF("================================");
// Test 3: Completely new DevEUI for ABP test (avoid any conflicts)
dev_eui[0] = 0x46;
dev_eui[1] = 0x33;
dev_eui[2] = 0x50;
dev_eui[3] = 0x04;
dev_eui[4] = 0x00;
dev_eui[5] = 0xAB;
dev_eui[6] = 0xCD;
dev_eui[7] = 0xEF; // Fresh DevEUI for ABP test
LOG_INF("Using HARDCODED DevEUI for testing (not UID-based)");
// Commented out UID-based generation
/*
dev_eui[0] = (uid_h >> 24) & 0xFF;
dev_eui[1] = (uid_h >> 16) & 0xFF;
dev_eui[2] = (uid_h >> 8) & 0xFF;
dev_eui[3] = (uid_h) & 0xFF;
dev_eui[4] = (uid_l >> 24) & 0xFF;
dev_eui[5] = (uid_l >> 16) & 0xFF;
dev_eui[6] = (uid_l >> 8) & 0xFF;
dev_eui[7] = (uid_l) & 0xFF;
*/
int err;
lora_dev = DEVICE_DT_GET(DT_ALIAS(lora0));
if (!device_is_ready(lora_dev))
{
LOG_ERR("%s: device not ready.", lora_dev->name);
return;
}
err = lorawan_start();
if (err < 0)
{
LOG_ERR("lorawan_start failed: %d", err);
return;
}
else
{
LOG_INF("LoraWan started successfully");
}
/* Print all LoRaWAN configuration for debugging */
print_lorawan_ids();
lorawan_register_downlink_callback(&downlink_cb);
join_cfg.mode = LORAWAN_ACT_OTAA;
join_cfg.dev_eui = dev_eui;
join_cfg.otaa.join_eui = join_eui;
join_cfg.otaa.app_key = app_key;
}
static void debug_compute_join_mic(void)
{
LOG_INF("=== ACTUAL IDs USED BY LORAWAN STACK ===");
LOG_HEXDUMP_INF(join_cfg.dev_eui, 8, "join_cfg.dev_eui: ");
LOG_HEXDUMP_INF(join_cfg.otaa.join_eui, 8, "join_cfg.otaa.join_eui: ");
LOG_HEXDUMP_INF(join_cfg.otaa.app_key, 16, "join_cfg.otaa.app_key: ");
LOG_INF("=== COMPARE WITH HARDCODED VALUES ===");
LOG_HEXDUMP_INF(dev_eui, 8, "hardcoded dev_eui: ");
LOG_HEXDUMP_INF(join_eui, 8, "hardcoded join_eui: ");
LOG_HEXDUMP_INF(app_key, 16, "hardcoded app_key: ");
// Check if values match
bool dev_eui_match = (memcmp(join_cfg.dev_eui, dev_eui, 8) == 0);
bool join_eui_match = (memcmp(join_cfg.otaa.join_eui, join_eui, 8) == 0);
bool app_key_match = (memcmp(join_cfg.otaa.app_key, app_key, 16) == 0);
LOG_INF("DevEUI match: %s", dev_eui_match ? "YES" : "NO");
LOG_INF("JoinEUI match: %s", join_eui_match ? "YES" : "NO");
LOG_INF("AppKey match: %s", app_key_match ? "YES" : "NO");
if (!dev_eui_match || !join_eui_match || !app_key_match)
{
LOG_ERR("MISMATCH DETECTED! join_cfg contains different values than expected!");
}
}
void join_network_otaa()
{
int8_t ret = -1;
LOG_INF("Starting OTAA join procedure...");
LOG_INF("Join Config: Mode=%d", join_cfg.mode);
LOG_INF("Using EU868 Region");
while ((ret = lorawan_join(&join_cfg)) < 0)
{
const char *error_msg = "Unknown error";
switch (ret)
{
case -116:
error_msg = "Rx timeout (no network response)";
break;
case -22:
error_msg = "Invalid parameter";
break;
case -11:
error_msg = "Try again";
break;
case -5:
error_msg = "I/O error";
break;
case -16:
error_msg = "Device busy";
break;
}
LOG_ERR("LoRaWAN join failed: %d (%s), retrying in 5 seconds...", ret, error_msg);
// Debug MIC calculation on each retry
debug_compute_join_mic();
LOG_INF("DEBUG: Join attempt made with these parameters:");
LOG_HEXDUMP_INF(join_cfg.dev_eui, 8, "Used DevEUI: ");
LOG_HEXDUMP_INF(join_cfg.otaa.join_eui, 8, "Used JoinEUI: ");
LOG_HEXDUMP_INF(join_cfg.otaa.app_key, 16, "Used AppKey: ");
LOG_ERR("=== Configuration on join failure ===");
printk("DevEUI: ");
for (int i = 0; i < 8; i++)
{
printk("%02X", dev_eui[i]);
if (i < 7)
printk(":");
}
printk("\n");
printk("AppEUI: ");
for (int i = 0; i < 8; i++)
{
printk("%02X", join_eui[i]);
if (i < 7)
printk(":");
}
printk("\n");
printk("AppKey: ");
for (int i = 0; i < 16; i++)
{
printk("%02X", app_key[i]);
if (i < 15)
printk(":");
}
printk("\n");
LOG_ERR("Check: Network server has this DevEUI registered?");
LOG_ERR("Check: AppKey matches network server?");
LOG_ERR("Check: Gateway in range and connected?");
LOG_ERR("====================================");
k_sleep(K_MSEC(5000));
}
LOG_INF("✓ Successfully joined LoRaWAN network via OTAA");
/* Print join success with DevEUI for identification */
printk("Device ");
for (int i = 0; i < 8; i++)
{
printk("%02X", dev_eui[i]);
if (i < 7)
printk(":");
}
printk(" joined network\n");
}
void join_network_abp()
{
LOG_INF("Starting ABP activation...");
LOG_INF("DevAddr: 0x%08X", dev_addr);
LOG_HEXDUMP_INF(nwks_key, 16, "NwkSKey: ");
LOG_HEXDUMP_INF(apps_key, 16, "AppSKey: ");
/* Configure ABP parameters */
join_cfg.mode = LORAWAN_ACT_ABP;
join_cfg.dev_eui = dev_eui;
join_cfg.abp.dev_addr = dev_addr;
join_cfg.abp.nwk_skey = nwks_key;
join_cfg.abp.app_skey = apps_key;
int ret = lorawan_join(&join_cfg);
if (ret < 0)
{
LOG_ERR("ABP activation failed: %d", ret);
return;
}
LOG_INF("✓ Successfully activated LoRaWAN network via ABP");
printk("Device 0x%08X activated via ABP\n", dev_addr);
}
void send_data_packet(char *data, uint8_t data_len)
{
LOG_INF("Sending %d bytes on port %d...", data_len, LORAWAN_PORT);
LOG_HEXDUMP_INF(data, data_len, "Payload: ");
while (1)
{
int8_t ret = lorawan_send(LORAWAN_PORT, (uint8_t *)data, data_len, LORAWAN_MSG_UNCONFIRMED);
if (ret == -EAGAIN)
{
LOG_WRN("LoRaWAN busy (duty cycle), retrying in 1s...");
k_sleep(RETRY_DELAY);
continue;
}
else if (ret < 0)
{
LOG_ERR("LoRaWAN send failed: %d", ret);
k_sleep(RETRY_DELAY);
break;
}
else
{
LOG_INF("✓ Data packet sent successfully!");
LOG_INF("DevAddr: 0x%08X, Port: %d, Length: %d bytes", dev_addr, LORAWAN_PORT, data_len);
break;
}
k_sleep(RETRY_DELAY);
}
}
void create_data_package(char *buffer, float temp_room_mlx, float temp_floor, float humidity, uint8_t relais_state)
{
int16_t temp = (int16_t)(temp_room_mlx * 100);
int16_t floor_temp = (int16_t)(temp_floor * 100);
int16_t hum = (int16_t)(humidity * 100);
// Packen der Daten in das Byte-Array
buffer[0] = (temp >> 8) & 0xFF;
buffer[1] = temp & 0xFF;
buffer[2] = (floor_temp >> 8) & 0xFF;
buffer[3] = floor_temp & 0xFF;
buffer[4] = (hum >> 8) & 0xFF;
buffer[5] = hum & 0xFF;
buffer[6] = relais_state;
}