From 71892d4d5ca247a879cea40fff9c80affbc7a3f5 Mon Sep 17 00:00:00 2001 From: Eduard Iten Date: Tue, 14 Jul 2026 13:34:37 +0200 Subject: [PATCH] Div. Anpassungen --- .vscode/settings.json | 8 + .../ItenEngineering/PoolTemp/Kconfig.PoolTemp | 2 + .../PoolTemp/Kconfig.defconfig | 2 + .../ItenEngineering/PoolTemp/Kconfig.sysbuild | 2 + .../PoolTemp/PoolTemp-pinctrl.dtsi | 1 + .../ItenEngineering/PoolTemp/PoolTemp.dts | 106 +++++ .../ItenEngineering/PoolTemp/PoolTemp.yaml | 10 + .../PoolTemp/PoolTemp_defconfig | 3 + .../ItenEngineering/PoolTemp/board.cmake | 9 + .../boards/ItenEngineering/PoolTemp/board.yml | 6 + .../PoolTemp/pre_dt_board.cmake | 2 + firmware/boards/nrf52840dk_nrf52840.overlay | 28 +- firmware/debug.Kconfig | 23 ++ firmware/prj.conf | 18 +- firmware/src/main.c | 390 ++++++++++++------ gateway/gateway/controller.py | 2 +- 16 files changed, 461 insertions(+), 151 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 firmware/boards/ItenEngineering/PoolTemp/Kconfig.PoolTemp create mode 100644 firmware/boards/ItenEngineering/PoolTemp/Kconfig.defconfig create mode 100644 firmware/boards/ItenEngineering/PoolTemp/Kconfig.sysbuild create mode 100644 firmware/boards/ItenEngineering/PoolTemp/PoolTemp-pinctrl.dtsi create mode 100644 firmware/boards/ItenEngineering/PoolTemp/PoolTemp.dts create mode 100644 firmware/boards/ItenEngineering/PoolTemp/PoolTemp.yaml create mode 100644 firmware/boards/ItenEngineering/PoolTemp/PoolTemp_defconfig create mode 100644 firmware/boards/ItenEngineering/PoolTemp/board.cmake create mode 100644 firmware/boards/ItenEngineering/PoolTemp/board.yml create mode 100644 firmware/boards/ItenEngineering/PoolTemp/pre_dt_board.cmake create mode 100644 firmware/debug.Kconfig diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..5cadcf1 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "nrf-connect.applications": [ + "${workspaceFolder}/firmware" + ], + "nrf-connect.boardRoots": [ + "${workspaceFolder}/firmware" + ] +} \ No newline at end of file diff --git a/firmware/boards/ItenEngineering/PoolTemp/Kconfig.PoolTemp b/firmware/boards/ItenEngineering/PoolTemp/Kconfig.PoolTemp new file mode 100644 index 0000000..e4e9973 --- /dev/null +++ b/firmware/boards/ItenEngineering/PoolTemp/Kconfig.PoolTemp @@ -0,0 +1,2 @@ +config BOARD_POOLTEMP + select SOC_NRF52840_QIAA \ No newline at end of file diff --git a/firmware/boards/ItenEngineering/PoolTemp/Kconfig.defconfig b/firmware/boards/ItenEngineering/PoolTemp/Kconfig.defconfig new file mode 100644 index 0000000..9fa85fd --- /dev/null +++ b/firmware/boards/ItenEngineering/PoolTemp/Kconfig.defconfig @@ -0,0 +1,2 @@ +config HW_STACK_PROTECTION + default ARCH_HAS_STACK_PROTECTION \ No newline at end of file diff --git a/firmware/boards/ItenEngineering/PoolTemp/Kconfig.sysbuild b/firmware/boards/ItenEngineering/PoolTemp/Kconfig.sysbuild new file mode 100644 index 0000000..8895c90 --- /dev/null +++ b/firmware/boards/ItenEngineering/PoolTemp/Kconfig.sysbuild @@ -0,0 +1,2 @@ +config PARTITION_MANAGER + default n diff --git a/firmware/boards/ItenEngineering/PoolTemp/PoolTemp-pinctrl.dtsi b/firmware/boards/ItenEngineering/PoolTemp/PoolTemp-pinctrl.dtsi new file mode 100644 index 0000000..4a9cd13 --- /dev/null +++ b/firmware/boards/ItenEngineering/PoolTemp/PoolTemp-pinctrl.dtsi @@ -0,0 +1 @@ +&pinctrl {}; diff --git a/firmware/boards/ItenEngineering/PoolTemp/PoolTemp.dts b/firmware/boards/ItenEngineering/PoolTemp/PoolTemp.dts new file mode 100644 index 0000000..abffb1f --- /dev/null +++ b/firmware/boards/ItenEngineering/PoolTemp/PoolTemp.dts @@ -0,0 +1,106 @@ +/dts-v1/; + +#include +#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 = ; +}; + +&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 = ; + zephyr,resolution = <12>; + zephyr,input-positive = ; + }; +}; diff --git a/firmware/boards/ItenEngineering/PoolTemp/PoolTemp.yaml b/firmware/boards/ItenEngineering/PoolTemp/PoolTemp.yaml new file mode 100644 index 0000000..b421543 --- /dev/null +++ b/firmware/boards/ItenEngineering/PoolTemp/PoolTemp.yaml @@ -0,0 +1,10 @@ +identifier: PoolTemp/nrf52840 +name: Pool Thermometer +vendor: ItenEngineering +type: mcu +arch: arm +ram: 256 +flash: 472 +toolchain: + - zephyr +supported: [] \ No newline at end of file diff --git a/firmware/boards/ItenEngineering/PoolTemp/PoolTemp_defconfig b/firmware/boards/ItenEngineering/PoolTemp/PoolTemp_defconfig new file mode 100644 index 0000000..b678dfe --- /dev/null +++ b/firmware/boards/ItenEngineering/PoolTemp/PoolTemp_defconfig @@ -0,0 +1,3 @@ +CONFIG_ARM_MPU=y +CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y +CONFIG_CLOCK_CONTROL_NRF_K32SRC_500PPM=y \ No newline at end of file diff --git a/firmware/boards/ItenEngineering/PoolTemp/board.cmake b/firmware/boards/ItenEngineering/PoolTemp/board.cmake new file mode 100644 index 0000000..fe8c3b0 --- /dev/null +++ b/firmware/boards/ItenEngineering/PoolTemp/board.cmake @@ -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) \ No newline at end of file diff --git a/firmware/boards/ItenEngineering/PoolTemp/board.yml b/firmware/boards/ItenEngineering/PoolTemp/board.yml new file mode 100644 index 0000000..f2e61aa --- /dev/null +++ b/firmware/boards/ItenEngineering/PoolTemp/board.yml @@ -0,0 +1,6 @@ +board: + name: PoolTemp + full_name: PoolTemp + vendor: ItenEngineering + socs: + - name: nrf52840 \ No newline at end of file diff --git a/firmware/boards/ItenEngineering/PoolTemp/pre_dt_board.cmake b/firmware/boards/ItenEngineering/PoolTemp/pre_dt_board.cmake new file mode 100644 index 0000000..519d784 --- /dev/null +++ b/firmware/boards/ItenEngineering/PoolTemp/pre_dt_board.cmake @@ -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") diff --git a/firmware/boards/nrf52840dk_nrf52840.overlay b/firmware/boards/nrf52840dk_nrf52840.overlay index 3214d3f..db0ef81 100644 --- a/firmware/boards/nrf52840dk_nrf52840.overlay +++ b/firmware/boards/nrf52840dk_nrf52840.overlay @@ -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 = ; - zephyr,input-positive = ; // Hier greift er intern VDD ab! + zephyr,input-positive = ; // This reads VDD internally. zephyr,resolution = <12>; }; }; diff --git a/firmware/debug.Kconfig b/firmware/debug.Kconfig new file mode 100644 index 0000000..663a036 --- /dev/null +++ b/firmware/debug.Kconfig @@ -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 diff --git a/firmware/prj.conf b/firmware/prj.conf index 5608e30..72e0616 100644 --- a/firmware/prj.conf +++ b/firmware/prj.conf @@ -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_ADC=y \ No newline at end of file +CONFIG_W1=y +CONFIG_DS18B20=y +CONFIG_ADC=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED=y \ No newline at end of file diff --git a/firmware/src/main.c b/firmware/src/main.c index 606f28c..2de4bec 100644 --- a/firmware/src/main.c +++ b/firmware/src/main.c @@ -7,16 +7,22 @@ #include #include #include +#include #include #include +#if defined(CONFIG_SHELL) +#include +#endif + #include +#include + #include -#include #include +#include -// #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 diff --git a/gateway/gateway/controller.py b/gateway/gateway/controller.py index 1749853..92dd267 100644 --- a/gateway/gateway/controller.py +++ b/gateway/gateway/controller.py @@ -144,7 +144,7 @@ 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) else: