Compare commits
3 Commits
fa69c30600
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 50987bec90 | |||
| dbee6b8287 | |||
| 71892d4d5c |
8
.vscode/settings.json
vendored
Normal file
8
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"nrf-connect.applications": [
|
||||
"${workspaceFolder}/firmware"
|
||||
],
|
||||
"nrf-connect.boardRoots": [
|
||||
"${workspaceFolder}/firmware"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
config BOARD_POOLTEMP
|
||||
select SOC_NRF52840_QIAA
|
||||
@@ -0,0 +1,2 @@
|
||||
config HW_STACK_PROTECTION
|
||||
default ARCH_HAS_STACK_PROTECTION
|
||||
@@ -0,0 +1,2 @@
|
||||
config PARTITION_MANAGER
|
||||
default n
|
||||
@@ -0,0 +1 @@
|
||||
&pinctrl {};
|
||||
106
firmware/boards/ItenEngineering/PoolTemp/PoolTemp.dts
Normal file
106
firmware/boards/ItenEngineering/PoolTemp/PoolTemp.dts
Normal file
@@ -0,0 +1,106 @@
|
||||
/dts-v1/;
|
||||
|
||||
#include <nordic/nrf52840_qiaa.dtsi>
|
||||
#include "PoolTemp-pinctrl.dtsi"
|
||||
|
||||
/ {
|
||||
model = "Pool Thermometer";
|
||||
compatible = "ItenEngineering,PoolTemp";
|
||||
|
||||
chosen {
|
||||
zephyr,sram = &sram0;
|
||||
zephyr,flash = &flash0;
|
||||
zephyr,code-partition = &slot0_partition;
|
||||
zephyr,ieee802154 = &ieee802154;
|
||||
};
|
||||
|
||||
zephyr,user {
|
||||
io-channels = <&adc 0>;
|
||||
};
|
||||
|
||||
aliases {
|
||||
pooltemp = &ds18b20_sensor;
|
||||
};
|
||||
|
||||
sensor_power: regulator-sensor-power {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "sensor-power";
|
||||
enable-gpios = <&gpio0 24 GPIO_ACTIVE_HIGH>;
|
||||
startup-delay-us = <2000>;
|
||||
regulator-boot-on;
|
||||
};
|
||||
|
||||
w1_0: w1-zephyr-gpio {
|
||||
compatible = "zephyr,w1-gpio";
|
||||
gpios = <&gpio0 13 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
|
||||
|
||||
ds18b20_sensor: ds18b20 {
|
||||
compatible = "maxim,ds18b20";
|
||||
family-code = <0x28>;
|
||||
resolution = <12>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&ieee802154 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
®1 {
|
||||
regulator-initial-mode = <NRF5X_REG_MODE_DCDC>;
|
||||
};
|
||||
|
||||
&gpio0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gpiote {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
/* Battery voltage measurement via the internal VDD channel.
|
||||
* E73 modules are typically powered from VDD (not VDDH).
|
||||
*/
|
||||
&flash0 {
|
||||
partitions {
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
boot_partition: partition@0 {
|
||||
label = "mcuboot";
|
||||
reg = <0x0 DT_SIZE_K(48)>;
|
||||
};
|
||||
|
||||
slot0_partition: partition@c000 {
|
||||
label = "image-0";
|
||||
reg = <0xc000 DT_SIZE_K(472)>;
|
||||
};
|
||||
|
||||
slot1_partition: partition@82000 {
|
||||
label = "image-1";
|
||||
reg = <0x82000 DT_SIZE_K(472)>;
|
||||
};
|
||||
|
||||
storage_partition: partition@f8000 {
|
||||
label = "storage";
|
||||
reg = <0xf8000 DT_SIZE_K(32)>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&adc {
|
||||
status = "okay";
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
channel@0 {
|
||||
reg = <0>;
|
||||
zephyr,gain = "ADC_GAIN_1_6";
|
||||
zephyr,reference = "ADC_REF_INTERNAL";
|
||||
zephyr,acquisition-time = <ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 40)>;
|
||||
zephyr,resolution = <12>;
|
||||
zephyr,input-positive = <NRF_SAADC_VDD>;
|
||||
};
|
||||
};
|
||||
10
firmware/boards/ItenEngineering/PoolTemp/PoolTemp.yaml
Normal file
10
firmware/boards/ItenEngineering/PoolTemp/PoolTemp.yaml
Normal file
@@ -0,0 +1,10 @@
|
||||
identifier: PoolTemp/nrf52840
|
||||
name: Pool Thermometer
|
||||
vendor: ItenEngineering
|
||||
type: mcu
|
||||
arch: arm
|
||||
ram: 256
|
||||
flash: 472
|
||||
toolchain:
|
||||
- zephyr
|
||||
supported: []
|
||||
@@ -0,0 +1,3 @@
|
||||
CONFIG_ARM_MPU=y
|
||||
CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y
|
||||
CONFIG_CLOCK_CONTROL_NRF_K32SRC_500PPM=y
|
||||
9
firmware/boards/ItenEngineering/PoolTemp/board.cmake
Normal file
9
firmware/boards/ItenEngineering/PoolTemp/board.cmake
Normal file
@@ -0,0 +1,9 @@
|
||||
set(OPENOCD_NRF5_SUBFAMILY "nrf52")
|
||||
board_runner_args(jlink "--device=nRF52840_xxAA" "--speed=1000")
|
||||
board_runner_args(pyocd "--target=nrf52840" "--frequency=1000000")
|
||||
|
||||
include(${ZEPHYR_BASE}/boards/common/nrfutil.board.cmake)
|
||||
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
|
||||
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)
|
||||
include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake)
|
||||
include(${ZEPHYR_BASE}/boards/common/openocd-nrf5.board.cmake)
|
||||
6
firmware/boards/ItenEngineering/PoolTemp/board.yml
Normal file
6
firmware/boards/ItenEngineering/PoolTemp/board.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
board:
|
||||
name: PoolTemp
|
||||
full_name: PoolTemp
|
||||
vendor: ItenEngineering
|
||||
socs:
|
||||
- name: nrf52840
|
||||
@@ -0,0 +1,2 @@
|
||||
# Suppress "unique_unit_address_if_enabled" to handle some overlaps
|
||||
list(APPEND EXTRA_DTC_FLAGS "-Wno-unique_unit_address_if_enabled")
|
||||
@@ -2,6 +2,30 @@
|
||||
zephyr,user {
|
||||
io-channels = <&adc 0>;
|
||||
};
|
||||
|
||||
aliases {
|
||||
pooltemp = &ds18b20_sensor;
|
||||
};
|
||||
|
||||
sensor_power: regulator-sensor-power {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "sensor-power";
|
||||
enable-gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>; // Check your supply pin here.
|
||||
startup-delay-us = <2000>;
|
||||
regulator-boot-on;
|
||||
};
|
||||
|
||||
w1_0: w1-zephyr-gpio {
|
||||
compatible = "zephyr,w1-gpio";
|
||||
gpios = <&gpio0 13 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; // Check your data pin here.
|
||||
|
||||
ds18b20_sensor: ds18b20 {
|
||||
compatible = "maxim,ds18b20";
|
||||
family-code = <0x28>;
|
||||
resolution = <12>;
|
||||
// Removed: supply-gpios = <&sensor_power>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&adc {
|
||||
@@ -12,9 +36,9 @@
|
||||
channel@0 {
|
||||
reg = <0>;
|
||||
zephyr,gain = "ADC_GAIN_1_6";
|
||||
zephyr,reference = "ADC_REF_INTERNAL"; // Intern 0.6V
|
||||
zephyr,reference = "ADC_REF_INTERNAL"; // Internal 0.6 V
|
||||
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
|
||||
zephyr,input-positive = <NRF_SAADC_VDD>; // Hier greift er intern VDD ab!
|
||||
zephyr,input-positive = <NRF_SAADC_VDD>; // This reads VDD internally.
|
||||
zephyr,resolution = <12>;
|
||||
};
|
||||
};
|
||||
|
||||
23
firmware/debug.Kconfig
Normal file
23
firmware/debug.Kconfig
Normal file
@@ -0,0 +1,23 @@
|
||||
# Logging
|
||||
CONFIG_LOG=y
|
||||
CONFIG_PM=n
|
||||
CONFIG_NET_LOG=y
|
||||
|
||||
# Networking and OpenThread shells
|
||||
CONFIG_SHELL=y
|
||||
CONFIG_NET_SHELL=y
|
||||
CONFIG_OPENTHREAD_SHELL=y
|
||||
|
||||
# SEGGER RTT Backend (Logging & Shell)
|
||||
CONFIG_USE_SEGGER_RTT=y
|
||||
CONFIG_SEGGER_RTT_INIT_MODE_ALWAYS=y
|
||||
CONFIG_SHELL_BACKEND_RTT=y
|
||||
CONFIG_RTT_CONSOLE=n
|
||||
CONFIG_LOG_BACKEND_RTT=n
|
||||
CONFIG_SHELL_BACKEND_RTT_BUFFER=0
|
||||
CONFIG_SHELL_LOG_BACKEND=y
|
||||
|
||||
# UART Backends deaktivieren
|
||||
CONFIG_LOG_BACKEND_UART=n
|
||||
CONFIG_SHELL_BACKEND_SERIAL=n
|
||||
CONFIG_UART_CONSOLE=n
|
||||
@@ -19,18 +19,14 @@ CONFIG_OPENTHREAD_FTD=n
|
||||
CONFIG_OPENTHREAD_MTD=y
|
||||
CONFIG_OPENTHREAD_MTD_SED=y
|
||||
|
||||
# Logging
|
||||
CONFIG_LOG=y
|
||||
CONFIG_NET_LOG=y
|
||||
|
||||
# Networking and OpenThread shells
|
||||
CONFIG_SHELL=y
|
||||
CONFIG_NET_SHELL=y
|
||||
CONFIG_OPENTHREAD_SHELL=y
|
||||
|
||||
# HW info for Identifier
|
||||
CONFIG_HWINFO=y
|
||||
|
||||
# Interner Temperatursensor
|
||||
# Temperature Sensor and VDD measurement
|
||||
CONFIG_GPIO=y
|
||||
CONFIG_SENSOR=y
|
||||
CONFIG_W1=y
|
||||
CONFIG_DS18B20=y
|
||||
CONFIG_ADC=y
|
||||
CONFIG_REGULATOR=y
|
||||
CONFIG_REGULATOR_FIXED=y
|
||||
@@ -7,16 +7,22 @@
|
||||
#include <zephyr/drivers/adc.h>
|
||||
#include <zephyr/drivers/sensor.h>
|
||||
#include <zephyr/drivers/hwinfo.h>
|
||||
#include <zephyr/drivers/regulator.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/settings/settings.h>
|
||||
#if defined(CONFIG_SHELL)
|
||||
#include <zephyr/shell/shell.h>
|
||||
#endif
|
||||
|
||||
#include <openthread/thread.h>
|
||||
#include <openthread/platform/radio.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// #define FAST_TIMES // use seconds instead of minutes and hours for testing
|
||||
// #define FAST_TIMES
|
||||
|
||||
// --- Konfiguration ---
|
||||
#define TARGET_IP "fd00:10:0:10:be24:11ff:fe12:6196"
|
||||
#define TARGET_PORT 6969
|
||||
#define LISTEN_PORT 6969
|
||||
@@ -25,6 +31,7 @@
|
||||
#define MAX_SEND_INTERVAL_M 20
|
||||
#define BATTERY_MEASURE_INTERVAL_H 24
|
||||
#define UDP_RX_POLL_TIMEOUT_MS 100
|
||||
#define IEEE802154_MAX_TX_POWER_DBM 8
|
||||
|
||||
#define S_TO_MS(s) ((uint64_t)(s) * 1000ULL)
|
||||
#define M_TO_MS(m) ((uint64_t)(m) * 60ULL * 1000ULL)
|
||||
@@ -36,10 +43,9 @@ enum payload_type
|
||||
{
|
||||
PAYLOAD_TYPE_TEMP = 0x00,
|
||||
PAYLOAD_TYPE_BATTERY = 0x01,
|
||||
PAYLOAD_TYPE_CONFIG = 0x10
|
||||
PAYLOAD_TYPE_CONFIG = 0x10,
|
||||
};
|
||||
|
||||
// --- Payload Definition ---
|
||||
struct header
|
||||
{
|
||||
uint8_t proto_version;
|
||||
@@ -49,6 +55,7 @@ struct header
|
||||
} __attribute__((packed));
|
||||
|
||||
int32_t temp_mcelsius;
|
||||
int32_t filtered_temperature_mc = 0xFFFF;
|
||||
int16_t adc_buffer;
|
||||
|
||||
uint16_t measure_interval_m = MEASURE_INTERVAL_M;
|
||||
@@ -56,19 +63,78 @@ uint16_t send_delta_mc = SEND_DELTA_MC;
|
||||
uint16_t max_send_interval_m = MAX_SEND_INTERVAL_M;
|
||||
uint16_t battery_measure_interval_h = BATTERY_MEASURE_INTERVAL_H;
|
||||
|
||||
int sock;
|
||||
int sock = -1;
|
||||
struct sockaddr_in6 dest_addr;
|
||||
struct header header = {.proto_version = 1, .device_id = {0}, .seq_num = 0};
|
||||
|
||||
static const struct adc_dt_spec adc_channel = ADC_DT_SPEC_GET(DT_PATH(zephyr_user));
|
||||
static const struct device *const sensor_power_regulator = DEVICE_DT_GET(DT_NODELABEL(sensor_power));
|
||||
static const struct device *const temp_dev = DEVICE_DT_GET(DT_ALIAS(pooltemp));
|
||||
|
||||
struct adc_sequence sequence = {
|
||||
.buffer = &adc_buffer,
|
||||
.buffer_size = sizeof(adc_buffer),
|
||||
.calibrate = true,
|
||||
};
|
||||
|
||||
static int pool_settings_set(const char *name, size_t len,
|
||||
settings_read_cb read_cb, void *cb_arg)
|
||||
static int sensor_power_init(void)
|
||||
{
|
||||
if (!device_is_ready(sensor_power_regulator))
|
||||
{
|
||||
LOG_ERR("Sensor power regulator is not ready");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int rc = regulator_enable(sensor_power_regulator);
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG_ERR("Failed to enable sensor power regulator (%d)", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
k_msleep(10);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sensor_power_off(void)
|
||||
{
|
||||
int rc = regulator_disable(sensor_power_regulator);
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG_WRN("Failed to disable sensor power regulator (%d)", rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int radio_set_max_tx_power(void)
|
||||
{
|
||||
otInstance *instance;
|
||||
otError err;
|
||||
|
||||
openthread_mutex_lock();
|
||||
instance = openthread_get_default_instance();
|
||||
if (instance == NULL)
|
||||
{
|
||||
openthread_mutex_unlock();
|
||||
LOG_ERR("OpenThread instance not available");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
err = otPlatRadioSetTransmitPower(instance, IEEE802154_MAX_TX_POWER_DBM);
|
||||
openthread_mutex_unlock();
|
||||
|
||||
if (err != OT_ERROR_NONE)
|
||||
{
|
||||
LOG_ERR("Failed to set IEEE 802.15.4 TX power to %d dBm (%d)", IEEE802154_MAX_TX_POWER_DBM, err);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
LOG_INF("IEEE 802.15.4 TX power set to %d dBm", IEEE802154_MAX_TX_POWER_DBM);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pool_settings_set(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg)
|
||||
{
|
||||
const char *next;
|
||||
size_t name_len = settings_name_next(name, &next);
|
||||
@@ -86,43 +152,46 @@ static int pool_settings_set(const char *name, size_t len,
|
||||
rc = read_cb(cb_arg, &measure_interval_m, sizeof(measure_interval_m));
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG_ERR("Fehler beim Lesen von meas_int: %d", rc);
|
||||
LOG_ERR("Failed to read meas_int: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
LOG_DBG("Gelesen: meas_int=%u", measure_interval_m);
|
||||
LOG_DBG("Read meas_int=%u", measure_interval_m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strncmp(name, "delta_mc", name_len) == 0)
|
||||
{
|
||||
rc = read_cb(cb_arg, &send_delta_mc, sizeof(send_delta_mc));
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG_ERR("Fehler beim Lesen von delta_mc: %d", rc);
|
||||
LOG_ERR("Failed to read delta_mc: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
LOG_DBG("Gelesen: delta_mc=%u", send_delta_mc);
|
||||
LOG_DBG("Read delta_mc=%u", send_delta_mc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strncmp(name, "max_int", name_len) == 0)
|
||||
{
|
||||
rc = read_cb(cb_arg, &max_send_interval_m, sizeof(max_send_interval_m));
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG_ERR("Fehler beim Lesen von max_int: %d", rc);
|
||||
LOG_ERR("Failed to read max_int: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
LOG_DBG("Gelesen: max_int=%u", max_send_interval_m);
|
||||
LOG_DBG("Read max_int=%u", max_send_interval_m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strncmp(name, "batt_h", name_len) == 0)
|
||||
{
|
||||
rc = read_cb(cb_arg, &battery_measure_interval_h, sizeof(battery_measure_interval_h));
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG_ERR("Fehler beim Lesen von batt_h: %d", rc);
|
||||
LOG_ERR("Failed to read batt_h: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
LOG_DBG("Gelesen: batt_h=%u", battery_measure_interval_h);
|
||||
LOG_DBG("Read batt_h=%u", battery_measure_interval_h);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -131,7 +200,8 @@ static int pool_settings_set(const char *name, size_t len,
|
||||
|
||||
struct settings_handler pool_conf_handler = {
|
||||
.name = "pool",
|
||||
.h_set = pool_settings_set};
|
||||
.h_set = pool_settings_set,
|
||||
};
|
||||
|
||||
static bool thread_is_attached(void)
|
||||
{
|
||||
@@ -149,37 +219,33 @@ static bool thread_is_attached(void)
|
||||
role = otThreadGetDeviceRole(instance);
|
||||
openthread_mutex_unlock();
|
||||
|
||||
return role == OT_DEVICE_ROLE_CHILD ||
|
||||
role == OT_DEVICE_ROLE_ROUTER ||
|
||||
role == OT_DEVICE_ROLE_LEADER;
|
||||
return role == OT_DEVICE_ROLE_CHILD || role == OT_DEVICE_ROLE_ROUTER || role == OT_DEVICE_ROLE_LEADER;
|
||||
}
|
||||
|
||||
int adc_init(void)
|
||||
{
|
||||
int rc;
|
||||
// ADC-Sequenz konfigurieren
|
||||
|
||||
if (!adc_is_ready_dt(&adc_channel))
|
||||
{
|
||||
printk("Fehler: ADC-Device ist nicht bereit.\n");
|
||||
printk("Error: ADC device is not ready.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
// Kanal initialisieren
|
||||
rc = adc_channel_setup_dt(&adc_channel);
|
||||
if (rc < 0)
|
||||
{
|
||||
printk("Fehler beim Setup des ADC-Kanals (%d)\n", rc);
|
||||
printk("Failed to set up ADC channel (%d)\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Sequence mit den DT-Specs füllen
|
||||
rc = adc_sequence_init_dt(&adc_channel, &sequence);
|
||||
if (rc < 0)
|
||||
{
|
||||
printk("Fehler beim Initialisieren der Sequenz (%d)\n", rc);
|
||||
printk("Failed to initialize ADC sequence (%d)\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -195,17 +261,15 @@ int send_frame(uint8_t type, uint8_t *data, size_t data_len)
|
||||
sys_put_be16(header.seq_num, &buffer[10]);
|
||||
memcpy(&buffer[12], data, data_len);
|
||||
|
||||
rc = zsock_sendto(sock, buffer, sizeof(header) + data_len, 0,
|
||||
(struct sockaddr *)&dest_addr, sizeof(dest_addr));
|
||||
|
||||
rc = zsock_sendto(sock, buffer, sizeof(header) + data_len, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG_ERR("Senden fehlgeschlagen: %d", rc);
|
||||
LOG_ERR("Send failed: %d", rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_INF("Paket gesendet | Typ: 0x%02x | Seq: %u", header.type, header.seq_num);
|
||||
LOG_HEXDUMP_DBG(buffer, sizeof(header) + data_len, "Gesendete Daten:");
|
||||
LOG_INF("Packet sent | type: 0x%02x | seq: %u", header.type, header.seq_num);
|
||||
LOG_HEXDUMP_DBG(buffer, sizeof(header) + data_len, "Sent data:");
|
||||
}
|
||||
|
||||
header.seq_num++;
|
||||
@@ -215,6 +279,7 @@ int send_frame(uint8_t type, uint8_t *data, size_t data_len)
|
||||
int send_config(void)
|
||||
{
|
||||
uint8_t send_buf[8];
|
||||
|
||||
sys_put_be16(measure_interval_m, &send_buf[0]);
|
||||
sys_put_be16(send_delta_mc, &send_buf[2]);
|
||||
sys_put_be16(max_send_interval_m, &send_buf[4]);
|
||||
@@ -228,105 +293,132 @@ int recv_udp(void)
|
||||
uint8_t recv_buf[32];
|
||||
struct sockaddr_in6 from_addr;
|
||||
socklen_t from_addr_len = sizeof(from_addr);
|
||||
|
||||
// Poll-Struktur vorbereiten
|
||||
struct zsock_pollfd fds[1];
|
||||
|
||||
fds[0].fd = sock;
|
||||
fds[0].events = ZSOCK_POLLIN;
|
||||
|
||||
LOG_DBG("Warte kurz auf eingehende Konfigurationsdaten...");
|
||||
LOG_DBG("Waiting briefly for incoming config data...");
|
||||
|
||||
// poll blockiert maximal UDP_RX_POLL_TIMEOUT_MS
|
||||
int ret = zsock_poll(fds, 1, UDP_RX_POLL_TIMEOUT_MS);
|
||||
|
||||
if (ret > 0)
|
||||
{
|
||||
// Daten liegen bereit! recvfrom blockiert JETZT nicht mehr
|
||||
if (fds[0].revents & ZSOCK_POLLIN)
|
||||
{
|
||||
int len = zsock_recvfrom(sock, recv_buf, sizeof(recv_buf), 0,
|
||||
(struct sockaddr *)&from_addr, &from_addr_len);
|
||||
|
||||
int len = zsock_recvfrom(sock, recv_buf, sizeof(recv_buf), 0, (struct sockaddr *)&from_addr, &from_addr_len);
|
||||
if (len < 0)
|
||||
{
|
||||
LOG_ERR("recvfrom fehlgeschlagen: %d (errno: %d)", len, errno);
|
||||
LOG_ERR("recvfrom failed: %d (errno: %d)", len, errno);
|
||||
return len;
|
||||
}
|
||||
|
||||
if (len >= 12 &&
|
||||
recv_buf[0] == header.proto_version &&
|
||||
recv_buf[1] == PAYLOAD_TYPE_CONFIG)
|
||||
if (len >= 12 && recv_buf[0] == header.proto_version && recv_buf[1] == PAYLOAD_TYPE_CONFIG)
|
||||
{
|
||||
/* Kurzes Config-Format ohne UUID:
|
||||
* [ver(1), type(1), seq(2), meas(2), delta(2), max(2), batt(2)]
|
||||
*/
|
||||
uint16_t rx_seq = sys_get_be16(&recv_buf[2]);
|
||||
uint16_t new_meas_int = sys_get_be16(&recv_buf[4]);
|
||||
uint16_t new_delta_mc = sys_get_be16(&recv_buf[6]);
|
||||
uint16_t new_max_int = sys_get_be16(&recv_buf[8]);
|
||||
uint16_t new_batt_int = sys_get_be16(&recv_buf[10]);
|
||||
|
||||
LOG_HEXDUMP_DBG(recv_buf, len, "Empfangene Config-Daten:");
|
||||
LOG_INF("Neue Config erhalten! Seq: %u", rx_seq);
|
||||
LOG_INF(" -> Messintervall: %u min", new_meas_int);
|
||||
LOG_INF(" -> Temp Delta-T: %u m°C", new_delta_mc);
|
||||
LOG_INF(" -> Max Intervall: %u min", new_max_int);
|
||||
LOG_INF(" -> Batt Intervall:%u h", new_batt_int);
|
||||
LOG_HEXDUMP_DBG(recv_buf, len, "Received config data:");
|
||||
LOG_INF("New config received! seq: %u", rx_seq);
|
||||
LOG_INF(" -> measurement interval: %u min", new_meas_int);
|
||||
LOG_INF(" -> temperature delta: %u mC", new_delta_mc);
|
||||
LOG_INF(" -> max interval: %u min", new_max_int);
|
||||
LOG_INF(" -> battery interval: %u h", new_batt_int);
|
||||
|
||||
if (new_max_int < new_meas_int)
|
||||
{
|
||||
LOG_WRN("Empfangenes Max-Intervall (%u) ist kleiner als Messintervall (%u). Ignoriere Max-Intervall.",
|
||||
new_max_int, new_meas_int);
|
||||
new_max_int = new_meas_int; // Behalte alten Wert bei
|
||||
LOG_WRN("Received max interval (%u) is smaller than measurement interval (%u). Ignoring max interval.", new_max_int, new_meas_int);
|
||||
new_max_int = new_meas_int;
|
||||
}
|
||||
|
||||
if (new_meas_int >= 0 && new_meas_int <= 60 && new_meas_int != measure_interval_m)
|
||||
if (new_meas_int <= 60 && new_meas_int != measure_interval_m)
|
||||
{
|
||||
measure_interval_m = new_meas_int;
|
||||
settings_save_one("pool/meas_int", &measure_interval_m, sizeof(measure_interval_m));
|
||||
LOG_INF("Messintervall auf %u min gesetzt und im Flash gespeichert.", measure_interval_m);
|
||||
LOG_INF("Measurement interval set to %u min and saved to flash.", measure_interval_m);
|
||||
}
|
||||
|
||||
if (new_delta_mc > 0 && new_delta_mc <= 2000 && new_delta_mc != send_delta_mc)
|
||||
{
|
||||
send_delta_mc = new_delta_mc;
|
||||
settings_save_one("pool/delta_mc", &send_delta_mc, sizeof(send_delta_mc));
|
||||
LOG_INF("Temp Delta auf %u m°C gesetzt und im Flash gespeichert.", send_delta_mc);
|
||||
LOG_INF("Temperature delta set to %u mC and saved to flash.", send_delta_mc);
|
||||
}
|
||||
|
||||
if (new_max_int >= 5 && new_max_int <= 120 && new_max_int != max_send_interval_m)
|
||||
{
|
||||
max_send_interval_m = new_max_int;
|
||||
settings_save_one("pool/max_int", &max_send_interval_m, sizeof(max_send_interval_m));
|
||||
LOG_INF("Max Intervall auf %u min gesetzt und im Flash gespeichert.", max_send_interval_m);
|
||||
LOG_INF("Max interval set to %u min and saved to flash.", max_send_interval_m);
|
||||
}
|
||||
|
||||
if (new_batt_int >= 2 && new_batt_int <= 72 && new_batt_int != battery_measure_interval_h)
|
||||
{
|
||||
battery_measure_interval_h = new_batt_int;
|
||||
settings_save_one("pool/batt_h", &battery_measure_interval_h, sizeof(battery_measure_interval_h));
|
||||
LOG_INF("Batterie Intervall auf %u h gesetzt und im Flash gespeichert.", battery_measure_interval_h);
|
||||
LOG_INF("Battery interval set to %u h and saved to flash.", battery_measure_interval_h);
|
||||
}
|
||||
LOG_INF("Settings im Flash gespeichert.");
|
||||
|
||||
send_config(); // Sende die neue Config zurück, um zu bestätigen
|
||||
LOG_INF("Settings saved to flash.");
|
||||
send_config();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DBG("UDP Paket ignoriert (len=%d, type=0x%02x)", len,
|
||||
len > 1 ? recv_buf[1] : 0xff);
|
||||
LOG_DBG("UDP packet ignored (len=%d, type=0x%02x)", len, len > 1 ? recv_buf[1] : 0xff);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
// Das ist der Timeout nach 1 Sekunde
|
||||
LOG_DBG("Keine Config-Daten vom Gateway ausstehend (Timeout).");
|
||||
LOG_DBG("No config data pending from the gateway (timeout).");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERR("Fehler beim Pollen des Sockets: %d (errno: %d)", ret, errno);
|
||||
LOG_ERR("Error polling socket: %d (errno: %d)", ret, errno);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SHELL)
|
||||
static int cmd_udp_receive_pending(const struct shell *sh, size_t argc, char **argv)
|
||||
{
|
||||
ARG_UNUSED(argc);
|
||||
ARG_UNUSED(argv);
|
||||
|
||||
if (sock < 0)
|
||||
{
|
||||
shell_error(sh, "UDP socket is not initialized yet.");
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
int rc = send_frame(0xFF, NULL, 0);
|
||||
if (rc < 0)
|
||||
{
|
||||
shell_error(sh, "Failed to send UDP ping frame (%d)", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
k_msleep(300);
|
||||
|
||||
rc = recv_udp();
|
||||
if (rc < 0)
|
||||
{
|
||||
shell_error(sh, "UDP receive failed (%d)", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
shell_print(sh, "UDP ping sent, waited 300 ms, receive poll done.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
SHELL_CMD_REGISTER(udp_recv, NULL,
|
||||
"Poll pending UDP config frames once",
|
||||
cmd_udp_receive_pending);
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
static int rc;
|
||||
@@ -337,65 +429,70 @@ int main(void)
|
||||
static uint64_t last_temp_send_time = 0;
|
||||
static int32_t last_temp_send_mc = 0;
|
||||
static uint64_t last_battery_send_time = 0;
|
||||
uint32_t temperature_mc;
|
||||
|
||||
const struct device *const temp_dev = DEVICE_DT_GET_ANY(nordic_nrf_temp);
|
||||
|
||||
if (temp_dev == NULL)
|
||||
rc = sensor_power_init();
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG_ERR("Fehler: Kein nRF-Temperatursensor gefunden.");
|
||||
return -ENODEV;
|
||||
return rc;
|
||||
}
|
||||
sensor_power_off();
|
||||
|
||||
if (!device_is_ready(temp_dev))
|
||||
{
|
||||
LOG_ERR("Fehler: Temperatursensor-Device ist nicht bereit.");
|
||||
LOG_ERR("Error: Temperature sensor device is not ready.");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
LOG_INF("Temperatursensor (%s) erfolgreich initialisiert.", temp_dev->name);
|
||||
LOG_INF("Temperature sensor (%s) successfully initialized.", temp_dev->name);
|
||||
|
||||
rc = adc_init();
|
||||
if (rc < 0)
|
||||
{
|
||||
printk("Fehler beim Initialisieren des ADC (%d)\n", rc);
|
||||
printk("Failed to initialize ADC (%d)\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = settings_subsys_init();
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG_ERR("Settings Subsystem Init fehlgeschlagen: %d", rc);
|
||||
LOG_ERR("Settings subsystem init failed: %d", rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = settings_register(&pool_conf_handler);
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG_ERR("Settings Register fehlgeschlagen: %d", rc);
|
||||
LOG_ERR("Settings register failed: %d", rc);
|
||||
}
|
||||
// Lädt alle gespeicherten Werte aus dem NVS-Flash und triggert den Handler
|
||||
|
||||
rc = settings_load();
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG_ERR("Settings Load fehlgeschlagen: %d", rc);
|
||||
LOG_ERR("Settings load failed: %d", rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_INF("Settings erfolgreich aus dem Flash geladen.");
|
||||
LOG_INF("Settings successfully loaded from flash.");
|
||||
}
|
||||
}
|
||||
|
||||
LOG_INF("Starte UDP Sensor Node...");
|
||||
|
||||
LOG_INF("Starting UDP sensor node...");
|
||||
k_sleep(K_SECONDS(1));
|
||||
|
||||
LOG_INF("Warte auf OpenThread Attach...");
|
||||
rc = radio_set_max_tx_power();
|
||||
if (rc < 0)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
LOG_INF("Waiting for OpenThread attach...");
|
||||
for (int i = 0; i < 15; i++)
|
||||
{
|
||||
if (thread_is_attached())
|
||||
{
|
||||
was_connected = true;
|
||||
LOG_INF("OpenThread verbunden. UDP wird gestartet.");
|
||||
LOG_INF("OpenThread connected. UDP will start.");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -404,13 +501,13 @@ int main(void)
|
||||
|
||||
if (!was_connected)
|
||||
{
|
||||
LOG_WRN("Noch nicht attached, starte im Pause-Modus und warte auf Re-Attach.");
|
||||
LOG_WRN("Not attached yet; starting in pause mode and waiting for re-attach.");
|
||||
}
|
||||
|
||||
sock = zsock_socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (sock < 0)
|
||||
{
|
||||
LOG_ERR("Fehler beim Erstellen des Sockets: %d", sock);
|
||||
LOG_ERR("Failed to create socket: %d", sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -420,7 +517,7 @@ int main(void)
|
||||
rc = zsock_inet_pton(AF_INET6, TARGET_IP, &dest_addr.sin6_addr);
|
||||
if (rc != 1)
|
||||
{
|
||||
LOG_ERR("Ungueltige Ziel-IP: %s", TARGET_IP);
|
||||
LOG_ERR("Invalid destination IP: %s", TARGET_IP);
|
||||
zsock_close(sock);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -428,33 +525,32 @@ int main(void)
|
||||
struct sockaddr_in6 local_addr;
|
||||
memset(&local_addr, 0, sizeof(local_addr));
|
||||
local_addr.sin6_family = AF_INET6;
|
||||
local_addr.sin6_port = htons(LISTEN_PORT); // Höre genau auf Port 6969!
|
||||
local_addr.sin6_addr = in6addr_any; // Akzeptiere Pakete auf allen lokalen IPs
|
||||
local_addr.sin6_port = htons(LISTEN_PORT);
|
||||
local_addr.sin6_addr = in6addr_any;
|
||||
|
||||
rc = zsock_bind(sock, (struct sockaddr *)&local_addr, sizeof(local_addr));
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG_ERR("Fehler beim Binden des Sockets (bind): %d", errno);
|
||||
LOG_ERR("Failed to bind socket: %d", errno);
|
||||
zsock_close(sock);
|
||||
return -1;
|
||||
}
|
||||
LOG_INF("Socket erfolgreich an lokalen Port %d gebunden.", LISTEN_PORT);
|
||||
|
||||
LOG_INF("Ziel: [%s]:%d", TARGET_IP, TARGET_PORT);
|
||||
LOG_INF("Socket successfully bound to local port %d.", LISTEN_PORT);
|
||||
LOG_INF("Target: [%s]:%d", TARGET_IP, TARGET_PORT);
|
||||
|
||||
hwinfo_get_device_id(header.device_id, sizeof(header.device_id));
|
||||
LOG_INF("Device ID: %02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
header.device_id[0], header.device_id[1], header.device_id[2], header.device_id[3],
|
||||
header.device_id[4], header.device_id[5], header.device_id[6], header.device_id[7]);
|
||||
|
||||
|
||||
#ifdef FAST_TIMES
|
||||
last_temp_send_time = -S_TO_MS(measure_interval_m);
|
||||
last_battery_send_time = -S_TO_MS(battery_measure_interval_h);
|
||||
#else
|
||||
last_temp_send_time = -M_TO_MS(measure_interval_m);
|
||||
last_battery_send_time = -H_TO_MS(battery_measure_interval_h);
|
||||
#endif
|
||||
#ifdef FAST_TIMES
|
||||
last_temp_send_time = -S_TO_MS(measure_interval_m);
|
||||
last_battery_send_time = -S_TO_MS(battery_measure_interval_h);
|
||||
#else
|
||||
last_temp_send_time = -M_TO_MS(measure_interval_m);
|
||||
last_battery_send_time = -H_TO_MS(battery_measure_interval_h);
|
||||
#endif
|
||||
|
||||
send_config();
|
||||
|
||||
@@ -467,12 +563,12 @@ int main(void)
|
||||
{
|
||||
if (connected)
|
||||
{
|
||||
LOG_INF("OpenThread wieder verbunden, sende weiter.");
|
||||
LOG_INF("OpenThread reconnected, continuing to send.");
|
||||
send_config();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_WRN("OpenThread getrennt, Senden pausiert.");
|
||||
LOG_WRN("OpenThread disconnected, sending paused.");
|
||||
}
|
||||
|
||||
was_connected = connected;
|
||||
@@ -484,46 +580,68 @@ int main(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Temparaturpaket (Simulation mit die temp anstatt DS18B20)
|
||||
rc = sensor_power_init();
|
||||
if (rc < 0)
|
||||
{
|
||||
k_sleep(K_SECONDS(2));
|
||||
continue;
|
||||
}
|
||||
|
||||
rc = sensor_sample_fetch(temp_dev);
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG_ERR("Fehler beim Abrufen der Temperaturdaten (%d)", rc);
|
||||
LOG_ERR("Error fetching temperature data (%d)", rc);
|
||||
sensor_power_off();
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = sensor_channel_get(temp_dev, SENSOR_CHAN_DIE_TEMP, &temp_val);
|
||||
rc = sensor_channel_get(temp_dev, SENSOR_CHAN_AMBIENT_TEMP, &temp_val);
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG_ERR("Fehler beim Lesen des Temperaturkanals (%d)", rc);
|
||||
LOG_ERR("Error reading temperature channel (%d)", rc);
|
||||
sensor_power_off();
|
||||
k_msleep(2000);
|
||||
continue;
|
||||
}
|
||||
|
||||
temp_mcelsius = (uint32_t)(temp_val.val1 * 1000 + temp_val.val2 / 1000); // Umrechnung in Milligrad Celsius
|
||||
temp_mcelsius = temp_val.val1 * 1000 + temp_val.val2 / 1000;
|
||||
temperature_mc = (uint32_t)temp_mcelsius;
|
||||
|
||||
LOG_DBG("Die-Temperatur: %u.%03u °C", temp_mcelsius / 1000, temp_mcelsius % 1000);
|
||||
if (filtered_temperature_mc == 0xFFFF)
|
||||
{
|
||||
filtered_temperature_mc = temperature_mc;
|
||||
}
|
||||
else
|
||||
{
|
||||
filtered_temperature_mc = (temperature_mc + (filtered_temperature_mc * 3)) / 4;
|
||||
}
|
||||
|
||||
LOG_DBG("Temperature: %u.%03u C (filtered: %u.%03u C)",
|
||||
temperature_mc / 1000, temperature_mc % 1000,
|
||||
filtered_temperature_mc / 1000, filtered_temperature_mc % 1000);
|
||||
|
||||
#ifdef FAST_TIMES
|
||||
if (abs(temp_mcelsius - last_temp_send_mc) >= send_delta_mc || current_time - last_temp_send_time >= S_TO_MS(max_send_interval_m))
|
||||
{
|
||||
if (abs((int32_t)filtered_temperature_mc - last_temp_send_mc) >= send_delta_mc ||
|
||||
current_time - last_temp_send_time >= S_TO_MS(max_send_interval_m))
|
||||
#else
|
||||
if (abs(temp_mcelsius - last_temp_send_mc) >= send_delta_mc || current_time - last_temp_send_time >= M_TO_MS(max_send_interval_m))
|
||||
{
|
||||
if (abs((int32_t)filtered_temperature_mc - last_temp_send_mc) >= send_delta_mc ||
|
||||
current_time - last_temp_send_time >= M_TO_MS(max_send_interval_m))
|
||||
#endif
|
||||
sys_put_be32(temp_mcelsius, &send_buf[0]);
|
||||
rc = send_frame(PAYLOAD_TYPE_TEMP, send_buf, sizeof(temp_mcelsius));
|
||||
{
|
||||
sys_put_be32(filtered_temperature_mc, &send_buf[0]);
|
||||
rc = send_frame(PAYLOAD_TYPE_TEMP, send_buf, sizeof(filtered_temperature_mc));
|
||||
|
||||
if (rc >= 0)
|
||||
{
|
||||
recv_udp();
|
||||
last_temp_send_mc = temp_mcelsius;
|
||||
last_temp_send_mc = (int32_t)filtered_temperature_mc;
|
||||
last_temp_send_time = current_time;
|
||||
}
|
||||
}
|
||||
|
||||
sensor_power_off();
|
||||
}
|
||||
|
||||
// Batteriepaket
|
||||
#ifdef FAST_TIMES
|
||||
if (current_time - last_battery_send_time >= S_TO_MS(battery_measure_interval_h))
|
||||
#else
|
||||
@@ -535,33 +653,31 @@ int main(void)
|
||||
rc = adc_read(adc_channel.dev, &sequence);
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG_ERR("Fehler beim Lesen des ADC-Kanals (%d)", rc);
|
||||
LOG_ERR("Error reading ADC channel (%d)", rc);
|
||||
break;
|
||||
}
|
||||
|
||||
battery_mv = adc_buffer;
|
||||
rc = adc_raw_to_millivolts_dt(&adc_channel, &battery_mv);
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG_ERR("Error in mV conversion (%d)", rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
battery_mv = adc_buffer;
|
||||
// Umrechnung des ADC-Werts in Millivolt (abhängig von der Referenzspannung und dem ADC-Auflösungsbereich)
|
||||
rc = adc_raw_to_millivolts_dt(&adc_channel, &battery_mv);
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG_ERR("Fehler bei der mV-Konvertierung (%d)\n", rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DBG("VDD Spannung: %d mV ", battery_mv);
|
||||
}
|
||||
LOG_DBG("VDD voltage: %d mV", battery_mv);
|
||||
}
|
||||
|
||||
uint16_t battery_mv_u16 = (uint16_t)battery_mv; // Konvertierung in uint16_t, falls nötig
|
||||
sys_put_be16(battery_mv_u16, &send_buf[0]);
|
||||
uint16_t battery_mv_u16 = (uint16_t)battery_mv;
|
||||
sys_put_be16(battery_mv_u16, &send_buf[0]);
|
||||
|
||||
rc = send_frame(PAYLOAD_TYPE_BATTERY, send_buf, sizeof(battery_mv_u16));
|
||||
if (rc >= 0)
|
||||
{
|
||||
last_battery_send_time = current_time;
|
||||
}
|
||||
rc = send_frame(PAYLOAD_TYPE_BATTERY, send_buf, sizeof(battery_mv_u16));
|
||||
if (rc >= 0)
|
||||
{
|
||||
last_battery_send_time = current_time;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FAST_TIMES
|
||||
k_sleep(K_SECONDS(measure_interval_m));
|
||||
#else
|
||||
|
||||
@@ -144,10 +144,15 @@ class Controller:
|
||||
node["config_shadow"]["max_interval"] = max_interval
|
||||
|
||||
self.mqtt_client.publish_sensor_value(uuid, "meas_interval", meas_interval)
|
||||
self.mqtt_client.publish_sensor_value(uuid, "temp_delta", temp_delta / 100.0)
|
||||
self.mqtt_client.publish_sensor_value(uuid, "temp_delta", temp_delta / 1000.0)
|
||||
self.mqtt_client.publish_sensor_value(uuid, "max_interval", max_interval)
|
||||
self.mqtt_client.publish_sensor_value(uuid, "batt_interval", batt_interval / 60.0)
|
||||
self.mqtt_client.publish_sensor_value(uuid, "batt_interval", batt_interval)
|
||||
elif msg_type == "ping":
|
||||
self.logger.debug(f"[{uuid}] Ping frame received (seq={seq_counter})")
|
||||
else:
|
||||
if msg_type == "ping":
|
||||
self.logger.debug(f"[{uuid}] Ping frame received before MQTT sync (seq={seq_counter})")
|
||||
return
|
||||
self.logger.info(f"[{uuid}] Wert geparkt ({msg_type}, warte auf MQTT Sync)...")
|
||||
|
||||
def handle_mqtt_sync(self, uuid, retained_lost_packets):
|
||||
|
||||
@@ -115,7 +115,7 @@ class MQTTDiscovery:
|
||||
"name": "Temperatur Delta-T [°C]",
|
||||
"state_topic": f"{self.sensor_topic}/{uuid}/temp_delta/state",
|
||||
"command_topic": f"{self.sensor_topic}/{uuid}/temp_delta/set",
|
||||
"min": 0.1, "max": 2.0, "step": 0.05,
|
||||
"min": 0.1, "max": 2.0, "step": 0.1,
|
||||
"unit_of_measurement": "°C",
|
||||
"unique_id": f"{uuid}_temp_delta",
|
||||
"icon": "mdi:thermometer",
|
||||
|
||||
@@ -38,14 +38,17 @@ class UDPListener:
|
||||
# Header (12 Bytes): 1B Version, 1B Type, 8s Device-ID, 1H Sequence Counter
|
||||
# Payload Temp: 1i (4 Bytes Signed Int) -> Gesamtlänge 16
|
||||
# Payload Batt: 1H (2 Bytes Unsigned Short) -> Gesamtlänge 14
|
||||
# Payload Ping: leer -> Gesamtlänge 12 (nur Header)
|
||||
|
||||
FORMAT_TEMP = "!BB8sHi"
|
||||
FORMAT_BATT = "!BB8sHH"
|
||||
FORMAT_CONFIG = "!BB8sHHHHH"
|
||||
FORMAT_PING = "!BB8sH"
|
||||
|
||||
SIZE_TEMP = struct.calcsize(FORMAT_TEMP) # 16 Bytes
|
||||
SIZE_BATT = struct.calcsize(FORMAT_BATT) # 14 Bytes
|
||||
SIZE_CONFIG = struct.calcsize(FORMAT_CONFIG) # 12 Bytes
|
||||
SIZE_PING = struct.calcsize(FORMAT_PING) # 12 Bytes
|
||||
|
||||
|
||||
|
||||
@@ -114,6 +117,24 @@ class UDPListener:
|
||||
ip_address=addr[0] # Die IPv6-Adresse des nRF52
|
||||
)
|
||||
|
||||
elif payload_type == 0xFF: # PAYLOAD_TYPE_PING
|
||||
if len(data) != SIZE_PING:
|
||||
self.logger.warning(f"Ungültige Größe für Ping-Paket: {len(data)} statt {SIZE_PING}")
|
||||
continue
|
||||
|
||||
version, p_type, device_id_raw, seq = struct.unpack(FORMAT_PING, data)
|
||||
|
||||
if version != 1:
|
||||
continue
|
||||
|
||||
self.controller.process_udp_packet(
|
||||
msg_type="ping",
|
||||
seq_counter=seq,
|
||||
value=None,
|
||||
uuid=device_id_raw.hex(),
|
||||
ip_address=addr[0] # Die IPv6-Adresse des nRF52
|
||||
)
|
||||
|
||||
else:
|
||||
self.logger.warning(f"Unbekannter Payload-Typ 0x{payload_type:02x} von {addr[0]}")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user