diff --git a/README.de.md b/README.de.md new file mode 100644 index 0000000..e0349ea --- /dev/null +++ b/README.de.md @@ -0,0 +1,16 @@ +# Modulares Bewässerungssystem + +Dieses Projekt realisiert ein smartes, modulares Bewässerungssystem, das über Home Assistant gesteuert wird. + +## Dokumentation + +Die detaillierte Dokumentation befindet sich im Verzeichnis [`docs/`](./docs/): + +* **[Konzept](./docs/concept.de.md)**: Beschreibt die Systemarchitektur, die verwendeten Komponenten und die grundlegenden Design-Entscheidungen. +* **[MODBUS Register](./docs/modbus-registers.de.md)**: Definiert die Register-Map für die Kommunikation mit den Slave-Nodes. +* **[Projektplan](./docs/planning.de.md)**: Enthält den Entwicklungs- und Implementierungsplan. + +## Schnellstart + +* **Hardware**: Die KiCad-Dateien für die Hardware befinden sich im Verzeichnis [`hardware/`](./hardware/). +* **Software**: Die Zephyr-basierte Firmware für die Slave-Nodes befindet sich im Verzeichnis [`software/`](./software/). diff --git a/README.md b/README.md index a5dbda4..9606e2c 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,18 @@ -# Home assistant irrigation system -This is a home assistant irrigation system +[🇩🇪 Deutsch](README.de.md) | [🇬🇧 English](README.md) + +# Modular Irrigation System + +This project implements a smart, modular irrigation system controlled via Home Assistant. + +## Documentation + +The detailed documentation can be found in the [`docs/`](./docs/) directory: + +* **[Concept](./docs/concept.en.md)**: Describes the system architecture, the components used, and the basic design decisions. +* **[MODBUS Registers](./docs/modbus-registers.en.md)**: Defines the register map for communication with the slave nodes. +* **[Project Plan](./docs/planning.en.md)**: Contains the development and implementation plan. + +## Quick Start + +* **Hardware**: The KiCad files for the hardware are located in the [`hardware/`](./hardware/) directory. +* **Software**: The Zephyr-based firmware for the slave nodes is located in the [`software/`](./software/) directory. diff --git a/Concept.de.md b/docs/concept.de.md similarity index 98% rename from Concept.de.md rename to docs/concept.de.md index 6919f3e..7bca333 100644 --- a/Concept.de.md +++ b/docs/concept.de.md @@ -1,3 +1,5 @@ +[🇩🇪 Deutsch](concept.de.md) | [🇬🇧 English](concept.en.md) + # Konzept: Modulares Bewässerungssystem Dieses Dokument beschreibt das Konzept für ein modulares, smartes Bewässerungssystem, das zentral über Home Assistant gesteuert wird. diff --git a/docs/concept.en.md b/docs/concept.en.md new file mode 100644 index 0000000..d534d40 --- /dev/null +++ b/docs/concept.en.md @@ -0,0 +1,75 @@ +[🇩🇪 Deutsch](concept.de.md) | [🇬🇧 English](concept.en.md) + +# Concept: Modular Irrigation System + +This document describes the concept for a modular, smart irrigation system that is centrally controlled via Home Assistant. + +## 1. Architecture Overview + +The system is divided into three logical layers to ensure high flexibility and maintainability: + +1. **Control Layer (Home Assistant):** All logic, automations, and the user interface reside in Home Assistant. This is the "brain" of the system. +2. **Gateway Layer (ESP32):** A pure protocol translator that acts as a bridge between the home network (WLAN/Thread) and the physical bus system of the plant. It contains no control logic of its own. +3. **Actor/Sensor Layer (Slave Nodes):** Robust, specialized modules that are controlled via a bus and perform the actual tasks (switching valves, reading sensors). + +![System Architecture](./img/architecture.en.svg) + +## 2. System Components + +* **Water Tank:** An IBC container serves as a water reservoir. +* **Water Supply:** A "rain thief" on the downpipe directs rainwater into the tank. +* **Pump:** A pump with an integrated pressure expansion tank provides the necessary water pressure. +* **Actuators:** Motorized 12V ball valves to control the water outlets. +* **Level Sensor (precise):** A `QDY30A` with 4-20mA output and RS485/MODBUS interface for continuous measurement of the water level. +* **Level Sensors (Min/Max):** Optional capacitive sensors (`XKC-Y25-NPN` or similar) as redundant protection against running dry and overflowing. + +## 3. Gateway + +The central communication interface is implemented as a "dumb" gateway. + +* **Hardware:** An `ESP32C6`-based board. +* **Function:** The gateway acts as a transparent **MODBUS TCP/IP to MODBUS RTU converter**. It receives commands from the home network and forwards them to the RS485 bus and vice versa. It does not execute its own control logic. +* **Connection to Home Assistant:** The connection is made via the home network, either via WLAN or in the future possibly via Thread/Matter. In Home Assistant, the official MODBUS integration is used to address the gateway and the slaves behind it directly. + +## 4. Slave Nodes + +The slave nodes are the working units in the field. To keep the effort low for small series production (e.g. at JLCPCB), a universal board design for all slave types is sought. + +* **Microcontroller:** An `STM32G431PB`. Although powerful, it offers all the necessary peripherals (multiple UARTs, ADCs, CAN) and enables a uniform hardware and software design. +* **Peripherals per Node:** + * **Two High-Side Outputs (+12V):** Realized via a `VND7050AJ`. Perfect for controlling the 12V motor valves (`Open`/`Close`). The `Sense` line of the driver is read out via an AD converter to realize an end position detection without physical limit switches by measuring the motor current (motor current at standstill ≈ 0). + * **Two Low-Side Outputs (0V):** Outputs switched via N-channel MOSFETs. Can be used to control 12V LEDs in buttons or to switch the solid-state relay for the pump. + * **Two digital inputs:** Direct, protected inputs on the controller for connecting buttons or the capacitive NPN sensors. + +## 5. Bus System: MODBUS-RTU via RS485 + +MODBUS-RTU is consistently used as the bus system. + +* **Reasoning:** This choice is pragmatic, as the level sensor already requires MODBUS. This means that only a single, simple and widespread protocol is required for the entire system. +* **Physical Layer:** The cabling is done via RS485. Commercially available Cat-7 Ethernet cable with RJ45 plugs is used: + * 1 twisted pair for the bus signals `A` and `B`. + * 3 pairs of wires in parallel for `+12V` and `GND` to supply power to the slaves. + +## 6. Software + +* **Operating System (Slaves):** `Zephyr OS`. It is a modern, powerful real-time operating system that enables a clean and maintainable firmware structure. +* **Logic Implementation:** The entire control logic (e.g. "If level < 20% and day of the week = Monday, then switch on valve 3 for 10 minutes") is mapped exclusively in **Home Assistant** via its automation engine. + +### 6.1. Firmware Update of the Slaves (OTA) + +The firmware of the slaves can be updated during operation via the bus without the need for direct physical access. + +* **Concept:** The `MCUBoot` bootloader is used. This is decoupled from the communication protocol. +* **Procedure:** + 1. A script in Home Assistant reads the new firmware file (`firmware.bin`). + 2. The script breaks the file down into small data packets and sends them one after the other to the target slave via MODBUS command. + 3. The running application on the slave receives these packets and writes them directly to the secondary flash memory ("update slot"). + 4. After successful transmission, the slave is restarted by command. + 5. `MCUBoot` checks the signature of the new image, copies it to the primary slot and starts it. +* **Security:** The new firmware must mark itself as "functional" after starting. If it does not do this (e.g. due to a crash), the previous, stable firmware version is automatically restored by `MCUBoot` on the next restart by the watchdog. + +## 7. Safety and Robustness Concepts + +* **Fail-Safe Behavior:** Each slave node implements a watchdog. If no valid MODBUS query is received from the gateway over a defined period of time (e.g. 15 seconds), the slave goes into a safe state: all valves are closed and relays (e.g. for the pump) are switched off. +* **Electrical Protection Circuits:** All external interfaces are protected. The RS485 bus lines (`A`/`B`) are protected against overvoltages with TVS diodes on each board. Inputs and outputs receive basic ESD protection. +* **Power Supply:** The 12V bus voltage is regulated on each slave node with an efficient `TPS5430DDAR` step-down converter to the required 3.3V for the microcontroller and the bus drivers. diff --git a/img/architecture.de.svg b/docs/img/architecture.de.svg similarity index 100% rename from img/architecture.de.svg rename to docs/img/architecture.de.svg diff --git a/docs/img/architecture.en.svg b/docs/img/architecture.en.svg new file mode 100644 index 0000000..ac1b637 --- /dev/null +++ b/docs/img/architecture.en.svg @@ -0,0 +1,78 @@ + + + + + + + + + + Control Layer + (Home Assistant) + + + Gateway Layer + (ESP32) + + + Actor/Sensor Layer + (Slaves) + + + + + + + + + + + + + + Level Sensor + (MODBUS Slave) + + + Valve Control 1 + (MODBUS Slave) + + + Valve Control n + (MODBUS Slave) + + + Pump + (switched via Slave) + + + + + + + + + + + + + + + Home Network + (WLAN / Thread) + + + MODBUS TCP/IP + + + + Gateway + (Protocol Translator) + + + MODBUS RTU + (RS485 Bus) + + + + \ No newline at end of file diff --git a/modbus_registers.de.md b/docs/modbus-registers.de.md similarity index 97% rename from modbus_registers.de.md rename to docs/modbus-registers.de.md index 0430c9a..ca04888 100644 --- a/modbus_registers.de.md +++ b/docs/modbus-registers.de.md @@ -1,8 +1,6 @@ -Gerne, hier ist die finale Version der MODBUS-Register-Definition, die alle unsere Diskussionen und Verfeinerungen berücksichtigt, als kompletter Markdown-Block. +[🇩🇪 Deutsch](modbus-registers.de.md) | [🇬🇧 English](modbus-registers.en.md) -Markdown - -# MODBUS Register Map Definition v2.0 +# MODBUS Register Map Definition v1.0 ## 1. Einleitung diff --git a/docs/modbus-registers.en.md b/docs/modbus-registers.en.md new file mode 100644 index 0000000..5cecd36 --- /dev/null +++ b/docs/modbus-registers.en.md @@ -0,0 +1,85 @@ +[🇩🇪 Deutsch](modbus-registers.de.md) | [🇬🇧 English](modbus-registers.en.md) + +# MODBUS Register Map Definition v1.0 + +## 1. Introduction + +This document defines the MODBUS registers for the universal slave nodes of the irrigation system. + +### 1.1. Addressing Philosophy + +All registers are defined in a single, continuous list per register type (`Input` or `Holding`). A "Category" column logically assigns the function. The addresses are grouped in blocks to leave room for future extensions and to increase readability. + +* **`0x0000 - 0x000F`**: Valve control & status +* **`0x0010 - 0x001F`**: Digital outputs (LEDs / relays) +* **`0x0020 - 0x002F`**: Digital inputs (buttons / sensors) +* **`0x00F0 - 0x00FF`**: General device configuration & status +* **`0x0100 - 0x01FF`**: Firmware update mechanism + +### 1.2. Used Function Codes + +* **`0x03` (Read Holding Registers):** For reading `4xxxx` registers. +* **`0x04` (Read Input Registers):** For reading `3xxxx` registers. +* **`0x06` (Write Single Register):** For writing a single `4xxxx` register. +* **`0x10` (Write Multiple Registers):** For writing multiple `4xxxx` registers at once. + +## 2. Input Registers (3xxxx, Read-Only) + +| Address (hex) | Name | Category | Description | +| :--- | :--- | :--- | :--- | +| **0x0000** | `VALVE_STATE_MOVEMENT` | Valve | Combined status register. **High-Byte**: Movement (`0`=Idle, `1`=Opening, `2`=Closing, `3`=Error). **Low-Byte**: State (`0`=Closed, `1`=Open). | +| **0x0001** | `MOTOR_CURRENT_MA` | Valve | Current motor current in milliamperes (mA). | +| **0x0020** | `DIGITAL_INPUTS_STATE` | Inputs | Bitmask of the digital inputs. Bit 0: Input 1, Bit 1: Input 2. `1`=Active. | +| **0x0021** | `BUTTON_EVENTS` | Inputs | Event flags for buttons (Clear-on-Read). Bit 0: Button 1 pressed. Bit 1: Button 2 pressed. | +| **0x00F0** | `FIRMWARE_VERSION_MAJOR_MINOR` | System | e.g. `0x0102` for v1.2. | +| **0x00F1** | `FIRMWARE_VERSION_PATCH` | System | e.g. `3` for v1.2.3. | +| **0x00F2** | `DEVICE_STATUS` | System | `0`=OK, `1`=General error. | +| **0x00F3** | `UPTIME_SECONDS_LOW` | System | Lower 16 bits of the uptime in seconds. | +| **0x00F4** | `UPTIME_SECONDS_HIGH` | System | Upper 16 bits of the uptime. | +| **0x0100** | `FWU_LAST_CHUNK_CRC` | Firmware-Update | Contains the CRC16 of the last data chunk received in the buffer. | + +## 3. Holding Registers (4xxxx, Read/Write) + +| Address (hex) | Name | Category | Description | +| :--- | :--- | :--- | :--- | +| **0x0000** | `VALVE_COMMAND` | Valve | `1`=Open, `2`=Close, `0`=Stop movement. | +| **0x0001** | `MAX_OPENING_TIME_S` | Valve | Safety timeout in seconds for the opening process. | +| **0x0002** | `MAX_CLOSING_TIME_S` | Valve | Safety timeout in seconds for the closing process. | +| **0x0010** | `DIGITAL_OUTPUTS_STATE` | Outputs | Bitmask for reading and writing the outputs. Bit 0: Output 1, Bit 1: Output 2. `1`=ON, `0`=OFF. | +| **0x00F0** | `WATCHDOG_TIMEOUT_S` | System | Timeout of the fail-safe watchdog in seconds. `0`=Disabled. | +| **0x0100** | `FWU_COMMAND` | Firmware-Update | `1`: **Verify Chunk**: The last transmitted chunk was found to be valid by the client. The slave should now write it to flash. `2`: **Finalize Update**: All chunks have been transmitted. Finalize installation and restart. | +| **0x0101** | `FWU_CHUNK_OFFSET_LOW` | Firmware-Update | Lower 16 bits of the 32-bit offset to which the next chunk is to be written. | +| **0x0102** | `FWU_CHUNK_OFFSET_HIGH` | Firmware-Update | Upper 16 bits of the 32-bit offset. | +| **0x0103** | `FWU_CHUNK_SIZE` | Firmware-Update | Size of the next chunk in bytes (max. 256). | +| **0x0180** | `FWU_DATA_BUFFER` | Firmware-Update | **Start address** of a 128x16-bit buffer (256 bytes). Corresponds to registers `40384` to `40511`. | + +## 4. Detailed Firmware Update Process + +This process is stateless and robust against transmission errors. + +1. **Client:** Selects a chunk (max. 256 bytes) from the firmware file and calculates its CRC16. +2. **Client:** Writes the target offset (e.g. `0`) to `FWU_CHUNK_OFFSET_...` and the size to `FWU_CHUNK_SIZE`. +3. **Client:** Writes the chunk data to the `FWU_DATA_BUFFER` (from address `0x0180`). +4. **Slave:** Receives the data, places it in the RAM buffer and calculates the CRC. The result is provided in `FWU_LAST_CHUNK_CRC` (`30256`). +5. **Client:** Reads `FWU_LAST_CHUNK_CRC` and compares the value with the self-calculated CRC. + * **Error:** Go back to step 3 to send the same chunk again. + * **Success:** Continues with the next step. +6. **Client:** Writes the command `1` ("Verify Chunk") to `FWU_COMMAND` (`40256`). +7. **Slave:** Receives the command, takes the verified chunk from the RAM buffer and writes it to the correct location in the flash memory. +8. **Client:** Continues with the next chunk (back to step 1 with new offset and data). +9. **Last Chunk:** After the last chunk has been transferred and written to flash with command `1`, the client writes the command `2` ("Finalize Update") to `FWU_COMMAND`. +10. **Slave:** Performs final checks and restarts so that MCUBoot can perform the installation. + +## Appendix: QDY30A Level Sensor Registers + +These registers belong to the external level sensor and can also be addressed on the bus. According to the manufacturer, these are Holding Registers (`4xxxx`) that are read with function code `0x03`. + +| Address (hex) | Name | R/W | Description | +| :--- | :--- | :-- | :--- | +| **0x0000** | `NODE_ADDRESS` | R/W | Device address of the sensor (1-255). | +| **0x0001** | `BAUDRATE` | R/W | `0`=1200, `1`=2400, `2`=4800, `3`=9600, `4`=19200, `5`=38400, `6`=57600, `7`=115200. | +| **0x0002** | `UNIT` | R/W | `0`=None, `1`=cm, `2`=mm, `3`=MPa, `4`=Pa, `5`=kPa. | +| **0x0003** | `DECIMAL_PLACES` | R/W | Number of decimal places for the measured value (0-3). | +| **0x0004** | `CURRENT_MEASUREMENT` | R | The scaled measured value as a signed 16-bit integer. | +| **0x0005** | `MEASURING_RANGE_ZERO_POINT` | R/W | Raw value for the zero point of the scale. | +| **0x0006** | `MEASURING_RANGE_END_POINT` | R/W | Raw value for the end point of the scale. | diff --git a/planning.de.md b/docs/planning.de.md similarity index 98% rename from planning.de.md rename to docs/planning.de.md index c9f63b5..450207f 100644 --- a/planning.de.md +++ b/docs/planning.de.md @@ -1,3 +1,5 @@ +[🇩🇪 Deutsch](planning.de.md) | [🇬🇧 English](planning.en.md) + # Projektplan: Modulares Bewässerungssystem | Abgehakt | Aufgabe | Datum | Bemerkungen | diff --git a/docs/planning.en.md b/docs/planning.en.md new file mode 100644 index 0000000..b585d5e --- /dev/null +++ b/docs/planning.en.md @@ -0,0 +1,33 @@ +[🇩🇪 Deutsch](planning.de.md) | [🇬🇧 English](planning.en.md) + +# Project Plan: Modular Irrigation System + +| Done | Task | Date | Remarks | +| :---: | :--- | :--- | :--- | +| ✅ | **Phase 0: Planning & Definition** | | | +| ✅ | Create and finalize concept | 2025-06-30 | Architecture, components and basic architecture are defined. | +| ✅ | Define MODBUS Register Map | 2025-06-30 | The "API" of the slaves is defined and forms the basis for software development. | +| ☐ | **Phase 1: Slave Node Prototype (STM32 Eval-Board)** | | **Goal:** A single slave is brought to life on the eval board. | +| ☐ | 1.1 Set up development environment for STM32/Zephyr | | Install toolchain, VS Code, Zephyr-SDK, MCUBoot etc. and get a "Hello World" running. | +| ☐ | 1.2 Create basic firmware for slave node | | Implement hardware abstraction (GPIOs, ADC, UART for RS485). | +| ☐ | 1.3 Implement MODBUS-RTU stack on the slave | | Based on the defined register map. Initially only read functions (status, version). | +| ☐ | 1.4 Implement core logic (e.g. valve control) | | Implementation of the `VALVE_STATE_MOVEMENT` logic, current measurement for end positions etc. | +| ☐ | **Phase 2: Verification of the Slave Firmware** | | **Goal:** Prove that the slave adheres exactly to the MODBUS specification. | +| ☐ | 2.1 Test slave node with PC via USB-MODBUS adapter | | **Critical milestone.** Read & write the registers with tools like "QModMaster" or a Python script. The slave firmware is thus validated independently of the gateway. | +| ☐ | 2.2 Test firmware update mechanism | | Test the complete update process (chunking, CRC check) with a script from the PC. The slave initially only writes the firmware to an unused RAM area. | +| ☐ | **Phase 3: Hardware Design and Prototype Construction** | | **Goal:** From development on the eval board to a customized PCB. | +| ☐ | 3.1 Design schematic and PCB layout for slave node | | Based on the experience with the eval board. | +| ☐ | 3.2 Order and assemble prototype boards | | E.g. at JLCPCB. Solder THT components (connectors etc.) yourself. | +| ☐ | 3.3 Hardware commissioning of the first prototype | | Check voltages, upload firmware and repeat the tests from phase 2 to validate the hardware. | +| ☐ | 3.4 Implement flash write routine for firmware update | | Apply the process validated in RAM in step 2.2 to the real flash memory. | +| ☐ | **Phase 4: Gateway Development (ESP32 Eval-Board)** | | **Goal:** Build the bridge from the RS485 world to the home network. | +| ☐ | 4.1 Create gateway firmware (ESPHome) | | Set up a simple MODBUS TCP to RTU gateway on the ESP32C6 eval board. | +| ☐ | 4.2 Connect and test gateway with slave node prototype | | Test the chain: PC (as MODBUS TCP client) -> WLAN -> Gateway -> RS485 -> Slave. | +| ☐ | **Phase 5: System Integration in Home Assistant** | | **Goal:** Make the system "smart". | +| ☐ | 5.1 Configure MODBUS integration in Home Assistant | | Create the sensors and entities for the slave node in `configuration.yaml` or via the UI. | +| ☐ | 5.2 Create dashboards and automations in HA | | Visualization of the states (valve, pump etc.) and creation of the actual irrigation logic. | +| ☐ | 5.3 Develop Python script for firmware update in HA | | Implementation of the chunk-based upload as a script that can be called from HA. | +| ☐ | **Phase 6: Setup and Commissioning** | | **Goal:** Install the finished system. | +| ☐ | 6.1 Build and test all required slave nodes | | Test each slave individually with the PC via USB adapter and configure the MODBUS address. | +| ☐ | 6.2 Final installation and cabling of the system | | Installation of the components in the shed, cabling of the RS485 bus. | +| ☐ | 6.3 Overall system test and calibration | | Calibrate level sensor, check valve running times, test fail-safe behavior. |