- 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
349 lines
8.7 KiB
C
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;
|
|
} |