From ff22483f8b89f402ba2769579a7e64003fd4e45e Mon Sep 17 00:00:00 2001 From: Vladimir Zagainov Date: Sat, 11 Jul 2026 19:31:38 +0300 Subject: [PATCH] feat: finalize documentation and validation (Task 7) - Rewrite project CLAUDE.md to match actual C/Unity implementation and modules - Add docs/hardware_connection_diagram.md (ESP32-C6 <-> Ballu AC wiring) - Add docs/home_assistant_integration.md (HA usage examples) - Update Readme.md doc index and fix unclosed code fence - Validate docs against implementation (build + all tests pass) Co-Authored-By: Claude Opus 4.8 --- Claude.md | 129 +++++++++++----- Readme.md | 20 ++- docs/hardware_connection_diagram.md | 98 ++++++++++++ docs/home_assistant_integration.md | 144 ++++++++++++++++++ ...lu-ac-esp32c6-controller-implementation.md | 12 +- 5 files changed, 355 insertions(+), 48 deletions(-) create mode 100644 docs/hardware_connection_diagram.md create mode 100644 docs/home_assistant_integration.md diff --git a/Claude.md b/Claude.md index ac8d657..ccc6141 100644 --- a/Claude.md +++ b/Claude.md @@ -3,36 +3,61 @@ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Common Development Commands -1. **Build**: `make build` - Compiles firmware for ESP32-C6 -2. **Upload**: `make upload` - Flashes firmware to device (requires USB connection) -3. **Test**: `make test` - Runs all unit/integration tests using Vitest -4. **Single Test**: `make test TEST_NAME="test_module_name"` - Runs specific test -5. **Debug**: `make debug` - Starts debug mode with serial console +The project is plain C compiled with `gcc` and tested with the vendored Unity +framework (see `Makefile`). There is no ESP-IDF dependency for the host build/test +flow; the firmware entry point in `src/main.c` is excluded from test binaries via +the `UNIT_TEST` define. + +1. **Build (host)**: `make build` - Compiles all `src/*.c` into `build/app` +2. **Run all tests**: `make test` - Builds and runs every Unity test suite +3. **Single Test**: `make test-` - e.g. `make test-app-controller`, + `make test-midea-protocol`, `make test-uart`, `make test-zigbee-zcl`, + `make test-integration-layer`, `make test-status-monitor` +4. **Clean**: `make clean` - Removes `build/` and compiled test binaries +5. **Help**: `make help` - Lists all available targets + +> Note: `make upload`/`make debug` (flashing to real ESP32-C6 hardware) are +> hardware steps performed with the ESP-IDF toolchain and are not part of the +> host test flow. ## Code Architecture -The system implements a layered architecture for AC controller control: +The system implements a layered architecture, top to bottom. Each layer is a +`src/.c` + `.h` pair with a matching `test/_test.c` suite: -1. **Zigbee Interface Module** - - Receives and decodes Zigbee messages from Home Assistant or similar - - Translates commands to UART format - - Key files: `zigbee-handler.c`, `zigbee-decoder.h` +1. **Application Controller** (`app_controller.c/h`, entry: `main.c`) + - Owns every subsystem and wires the two end-to-end data flows. + - Command path: HA → Zigbee → Integration → UART → AC. + - Feedback path: AC → UART → Status → Integration → Zigbee → HA. + - Provides reset/recovery, health check, and the firmware service loop. -2. **Command Processing Core** - - Implements MideaUART protocol (based on cloned MideaUART repository) - - Parses UART commands and converts to AC control signals - - Key files: `uart-controller.c`, `midea-parser.h` +2. **Integration Layer** (`integration_layer.c/h`) + - Bridges Zigbee ZCL and MideaUART: maps `system_mode` ↔ MideaUART modes, + converts temperatures, enforces 50ms command spacing / rate limiting. -3. **Hardware Abstraction Layer** - - Manages ESP32-C6 GPIO and UART operations - - Handles precise timing for AC communication protocol - - Key files: `hardware-abstraction.c` +3. **Zigbee ZCL Cluster** (`zigbee_zcl.c/h`) + - ZCL Thermostat cluster server: `local_temperature`, `system_mode`, and + weekly schedule command handling. + +4. **Status Monitor** (`status_monitor.c/h`) + - Periodic AC status polling, ZCL attribute mapping, fault detection + (`error_code` / `alarm_mask`), and the communication watchdog. + +5. **MideaUART Protocol** (`midea_protocol.c/h`) + - `midea_control_t` / `midea_status_t` structures and encode/decode of AC + frames; timing helpers (50ms command spacing). + +6. **UART Driver** (`uart_driver.c/h`) + - Hardware abstraction for ESP32-C6 UART: init at 9600 baud 8N1, + send/receive with timeout handling. ## Development Notes -- Protocol implementation must strictly follow MideaUART specifications -- UART communication requires 50ms baud rate timing -- Testing should focus on edge cases for time-sensitive operations -- Dependencies managed via Makefile - do not modify directly -- MideaUART implementation: https://github.com/dudanov/MideaUART +- Protocol implementation must strictly follow MideaUART specifications. +- UART runs at 9600 baud 8N1; MideaUART commands are spaced at least 50ms apart + (`command_spacing_ms`, default 50 in `app_controller`/`integration_layer`). +- Testing should focus on edge cases for time-sensitive operations. +- Tests link every `src/*.c` together, so exactly one `main()` may exist per test + binary — the firmware `main()` in `src/main.c` is guarded by `#ifndef UNIT_TEST`. +- MideaUART reference implementation: https://github.com/dudanov/MideaUART ## Zigbee ZCL HVAC Integration (Thermostat Cluster) @@ -49,14 +74,19 @@ The system implements a layered architecture for AC controller control: - `EZB_ZCL_HVAC_SYSTEM_TYPE_CONFIGURATION_COOLING_SYSTEM_STAGE = 0x03` ### 3. Temperature Control -- Temperature range: -1°C to 32767°C (0.01°C resolution) -- Convert to MideaUART format: divide by 100 (e.g., 2500 → 25.0°C) -- Command structure: +- ZCL `local_temperature` / target temperature are in 0.01°C units (int16_t). +- MideaUART `target_temp` is also stored in 0.01°C units (`* 100`), so the + integration layer passes the value through (see + `integration_layer_convert_zcl_temperature`). +- The MideaUART setter takes Celsius as a float: + `midea_control_set_temperature(&control, 25.0f)` for a 25°C target. +- Command structure (actual C API): ```c - control.mode = MODE_COOL; // Zigbee mode: 0x03 (Cooling) - control.targetTemp = 25.0f; // 25°C target - control.modeChange = true; - ac.control(control); + midea_control_t control; + midea_control_init(&control); + midea_control_set_mode(&control, MODE_COOL); // MideaUART cool mode + midea_control_set_temperature(&control, 25.0f);// 25°C target + integration_layer_send_midea_command(&layer, &control); ``` ### 4. Schedule Management @@ -68,14 +98,37 @@ The system implements a layered architecture for AC controller control: - Track `ACErrorCode` for system fault detection - Implement status callbacks for UI updates -### 6. Mapping Example +### 6. Mode Mapping (ZCL ↔ MideaUART) +ZCL `system_mode` and MideaUART `midea_mode_t` use different numeric values; the +integration layer translates between them +(`integration_layer_map_zcl_to_midea_mode` / `integration_layer_map_midea_to_zcl_mode`): + +| ZCL system_mode | MideaUART midea_mode_t | +| :-- | :-- | +| 0 Off | MODE_OFF (0) | +| 1 Auto | MODE_AUTO (3) | +| 3 Cool | MODE_COOL (1) | +| 4 Heat | MODE_HEAT (2) | + +`midea_mode_t` additionally defines MODE_DRY (4), MODE_FAN (5), MODE_SLEEP (6), +MODE_TURBO (7). See `src/midea_protocol.h` for the authoritative enum. + +### 7. Mapping Example (feedback path) ```c -// When Zigbee reports mode = 0x03 (Cooling) and target temp = 2500 (25.00°C) -Control control; -control.mode = MODE_COOL; -control.targetTemp = 25.0f; // Convert from 0.01°C units -control.modeChange = true; -ac.control(control); +// An AC status frame decoded to midea_status_t is mapped to ZCL attributes +// and pushed into the cluster for Home Assistant to read: +zcl_thermostat_attrs_t attrs; +status_monitor_map_to_zcl(&status, &attrs); +zigbee_zcl_set_local_temperature(attrs.local_temperature); +zigbee_zcl_set_system_mode(attrs.system_mode); ``` -This documentation covers both the core Midea UART protocol for device communication and the Zigbee ZCL thermostat cluster integration for smart home control. \ No newline at end of file +This documentation covers both the core Midea UART protocol for device communication and the Zigbee ZCL thermostat cluster integration for smart home control. + +## Additional Documentation +- `docs/protocol.md` — MideaUART protocol details +- `docs/zcl_hvac.md` — Zigbee ZCL Thermostat cluster details +- `docs/hardware_connection_diagram.md` — ESP32-C6 ↔ Ballu AC wiring diagram +- `docs/home_assistant_integration.md` — Home Assistant usage examples +- `docs/Hardware integration guide.md` — ESP32-C6 hardware integration (RU) +- `docs/Build system details.md` — Build system and dependencies \ No newline at end of file diff --git a/Readme.md b/Readme.md index cb5f967..b59ca78 100644 --- a/Readme.md +++ b/Readme.md @@ -36,10 +36,22 @@ test/ app_controller_test.c - End-to-end integration tests (full command cycles) docs/ - protocol.md - MideaUART protocol details - zcl_hvac.md - Zigbee ZCL Thermostat cluster details - Hardware integration guide.md - Hardware connection information - Build system details.md - Build system and dependencies + protocol.md - MideaUART protocol details + zcl_hvac.md - Zigbee ZCL Thermostat cluster details + hardware_connection_diagram.md - ESP32-C6 <-> Ballu AC wiring diagram + home_assistant_integration.md - Home Assistant usage examples + Hardware integration guide.md - ESP32-C6 hardware integration (RU) + Build system details.md - Build system and dependencies +``` + +## Documentation + +- [MideaUART protocol](docs/protocol.md) +- [Zigbee ZCL Thermostat cluster](docs/zcl_hvac.md) +- [Hardware connection diagram](docs/hardware_connection_diagram.md) +- [Home Assistant integration guide](docs/home_assistant_integration.md) +- [ESP32-C6 hardware integration guide](docs/Hardware%20integration%20guide.md) +- [Build system details](docs/Build%20system%20details.md) ## Getting Started diff --git a/docs/hardware_connection_diagram.md b/docs/hardware_connection_diagram.md new file mode 100644 index 0000000..9ffc9e3 --- /dev/null +++ b/docs/hardware_connection_diagram.md @@ -0,0 +1,98 @@ +# Hardware Connection Diagram: ESP32-C6 ↔ Ballu AC + +This document describes the physical wiring between the ESP32-C6 controller and +the Ballu air conditioner's MideaUART port, and the logical signal path through +the firmware. + +> Pin numbers below match the firmware defaults in `src/app_controller.c` +> (`apply_default_uart_config`): **TX = GPIO16**, **RX = GPIO17**, 9600 baud, 8N1. +> These are configurable via `app_controller_config_t.uart_config`. + +## 1. Signal Overview + +``` ++---------------------+ UART 9600 8N1 +---------------------+ +| | (50 ms command spacing) | | +| Home Assistant | | Ballu AC unit | +| (Zigbee coord.) | | (Midea UART bus) | +| | | | ++----------+----------+ +----------+----------+ + | | + Zigbee 2.4 GHz (802.15.4) 3.3V TTL UART + | | ++----------v---------------------------------------------------v----------+ +| ESP32-C6 controller | +| | +| [Zigbee radio] --> zigbee_zcl --> integration_layer --> midea_protocol | +| | | | +| v v | +| status_monitor <--> uart_driver | +| | | +| GPIO16 (TX) --------+ | +| GPIO17 (RX) --------+ | ++-------------------------------------------------------------------------+ +``` + +## 2. Physical Wiring (ESP32-C6 ↔ AC MideaUART header) + +The Ballu/Midea indoor unit exposes a 3-wire (or 4-wire) TTL UART header. The AC +side already provides regulated power on some models; **verify the voltage on the +AC connector before wiring** — the ESP32-C6 GPIO are strictly 3.3V tolerant. + +| ESP32-C6 pin | Direction | AC MideaUART pin | Notes | +| :-- | :--: | :-- | :-- | +| GPIO16 (TX) | ESP → AC | RX | Controller transmits commands to the AC | +| GPIO17 (RX) | AC → ESP | TX | Controller receives status frames from the AC | +| GND | common | GND | **Mandatory** common ground reference | +| 3V3 | power | +5V/+12V | Do **not** connect AC +5V/+12V directly to 3V3; use a suitable regulator if powering the ESP32-C6 from the AC | + +```mermaid +graph LR + subgraph AC [Ballu AC - Midea UART header] + ARX[RX] + ATX[TX] + AGND[GND] + APWR[+5V / +12V] + end + + subgraph ESP [ESP32-C6 controller] + ETX[GPIO16 TX] + ERX[GPIO17 RX] + EGND[GND] + E3V3[3V3] + end + + ETX -->|3.3V TTL| ARX + ATX -->|3.3V TTL| ERX + EGND --- AGND + APWR -.->|via 3.3V regulator only| E3V3 +``` + +## 3. Wiring Rules + +- **Cross TX/RX**: controller TX (GPIO16) → AC RX; AC TX → controller RX (GPIO17). +- **Common ground is mandatory** — floating grounds cause framing errors. +- **3.3V logic only.** If the AC UART header uses 5V logic, insert a logic-level + shifter between the boards. +- **Power isolation.** Never feed the AC's raw supply rail into the ESP32-C6 3V3 + pin; step it down with a regulator (or power the ESP32-C6 over USB during + development). +- **Strapping pins.** GPIO16/GPIO17 are the ESP32-C6 default UART0 pins used for + boot logging/flashing. When wiring the AC to these pins, disconnect the AC + during flashing, or remap the AC UART to spare GPIO via + `uart_config_t.tx_pin` / `rx_pin` to keep the boot console free. + +## 4. Firmware Signal Path + +- **Command path (HA → AC):** + `zigbee_zcl` receives a ZCL Thermostat command → `integration_layer` maps + `system_mode`/temperature to a `midea_control_t` → `midea_protocol` encodes the + frame → `uart_driver` transmits it on GPIO16 with ≥50 ms spacing. +- **Feedback path (AC → HA):** + `uart_driver` reads a frame on GPIO17 → `midea_protocol` decodes it to + `midea_status_t` → `status_monitor` runs fault detection + watchdog and maps to + `zcl_thermostat_attrs_t` → `zigbee_zcl` publishes `local_temperature` and + `system_mode` for Home Assistant. + +See `docs/Hardware integration guide.md` for detailed ESP32-C6 pinout, strapping +pin cautions, and PCB layout guidance. diff --git a/docs/home_assistant_integration.md b/docs/home_assistant_integration.md new file mode 100644 index 0000000..283d1cb --- /dev/null +++ b/docs/home_assistant_integration.md @@ -0,0 +1,144 @@ +# Home Assistant Integration Guide + +This controller presents the Ballu AC to Home Assistant as a standard Zigbee +**ZCL Thermostat** device. Home Assistant talks to it through a Zigbee +coordinator running either ZHA or Zigbee2MQTT — no custom integration is needed +beyond the device pairing. + +## 1. What the Device Exposes + +The firmware implements a ZCL Thermostat cluster server +(`src/zigbee_zcl.c`) with these attributes: + +| ZCL attribute | Type | Meaning | +| :-- | :-- | :-- | +| `local_temperature` | int16, 0.01°C | Current indoor temperature read from the AC | +| `system_mode` | uint8 | Operating mode (see mapping below) | + +`system_mode` values (as exposed on the Zigbee side): + +| Value | Mode | +| :-- | :-- | +| 0 | Off | +| 1 | Auto | +| 3 | Cool | +| 4 | Heat | + +Internally these map to MideaUART modes via the integration layer +(`integration_layer_map_zcl_to_midea_mode`); MideaUART additionally supports +Dry, Fan, Sleep, and Turbo (`src/midea_protocol.h`). + +## 2. Pairing + +1. Put the Zigbee coordinator into permit-join mode (ZHA: *Add device*; + Zigbee2MQTT: *Permit join*). +2. Power on the ESP32-C6 controller; it joins as a Zigbee end device / router. +3. The device appears with a Thermostat entity exposing current temperature and + a mode selector. + +## 3. Home Assistant Climate Entity + +Once paired, ZHA/Zigbee2MQTT automatically create a `climate.*` entity backed by +the Thermostat cluster. Example resulting entity state: + +```yaml +climate.ballu_ac: + current_temperature: 24.5 # from local_temperature (2450 * 0.01°C) + hvac_mode: cool # from system_mode = 3 + temperature: 25.0 # target setpoint +``` + +### Setting mode and temperature (Lovelace / service call) + +```yaml +# Turn on cooling at 25°C +service: climate.set_temperature +target: + entity_id: climate.ballu_ac +data: + hvac_mode: cool + temperature: 25 +``` + +```yaml +# Switch to heating +service: climate.set_hvac_mode +target: + entity_id: climate.ballu_ac +data: + hvac_mode: heat +``` + +```yaml +# Turn the unit off +service: climate.set_hvac_mode +target: + entity_id: climate.ballu_ac +data: + hvac_mode: "off" +``` + +## 4. Example Automations + +Cool the room when it gets warm: + +```yaml +automation: + - alias: "Cool bedroom when hot" + trigger: + - platform: numeric_state + entity_id: climate.ballu_ac + attribute: current_temperature + above: 27 + action: + - service: climate.set_temperature + target: + entity_id: climate.ballu_ac + data: + hvac_mode: cool + temperature: 24 +``` + +Turn the AC off when everyone leaves: + +```yaml +automation: + - alias: "AC off when away" + trigger: + - platform: state + entity_id: group.family + to: "not_home" + action: + - service: climate.set_hvac_mode + target: + entity_id: climate.ballu_ac + data: + hvac_mode: "off" +``` + +## 5. Zigbee2MQTT Notes + +If using Zigbee2MQTT, the device publishes to +`zigbee2mqtt/` with a JSON payload containing +`local_temperature` and `system_mode`. Publish a command like: + +```json +{ "system_mode": "cool", "occupied_heating_setpoint": 2500 } +``` + +Setpoints in raw ZCL are in 0.01°C units (2500 = 25.0°C), matching the firmware's +temperature representation. + +## 6. Status Reporting & Faults + +- The controller polls the AC on a configurable interval (default 5000 ms, + `status_monitor_config_t.poll_interval_ms`) and updates `local_temperature` / + `system_mode` accordingly. +- If the AC reports a non-zero `error_code` or `alarm_mask`, the status monitor + latches a fault (`status_monitor_has_fault`) and the app controller reports + unhealthy (`app_controller_is_healthy`). +- A communication watchdog triggers automatic reset/recovery + (`app_controller_recover_if_needed`) if polling fails repeatedly. + +See `docs/zcl_hvac.md` for the full ZCL Thermostat cluster reference and +`docs/hardware_connection_diagram.md` for wiring. diff --git a/docs/plans/2026-07-05-ballu-ac-esp32c6-controller-implementation.md b/docs/plans/2026-07-05-ballu-ac-esp32c6-controller-implementation.md index fb7bd89..08b8994 100644 --- a/docs/plans/2026-07-05-ballu-ac-esp32c6-controller-implementation.md +++ b/docs/plans/2026-07-05-ballu-ac-esp32c6-controller-implementation.md @@ -80,12 +80,12 @@ Implementation of ESP32-C6 based AC controller that bridges Zigbee (Home Assista - [x] Update Readme.md ### Task 7: Documentation and Validation -- [ ] Update CLAUDE.md with implementation details -- [ ] Create hardware connection diagram in docs/ -- [ ] Add usage examples for Home Assistant integration -- [ ] Validate all documentation against implementation -- [ ] Final review and cleanup -- [ ] Update Readme.md +- [x] Update CLAUDE.md with implementation details +- [x] Create hardware connection diagram in docs/ +- [x] Add usage examples for Home Assistant integration +- [x] Validate all documentation against implementation +- [x] Final review and cleanup +- [x] Update Readme.md ## Technical Details