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 <noreply@anthropic.com>
This commit is contained in:
2026-07-11 19:31:38 +03:00
parent b3e09d991d
commit ff22483f8b
5 changed files with 355 additions and 48 deletions

129
Claude.md
View File

@@ -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-<module>` - 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/<name>.c` + `<name>.h` pair with a matching `test/<name>_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.
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

View File

@@ -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

View File

@@ -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.

View File

@@ -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/<friendly_name>` 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.

View File

@@ -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