Skip to content

Commit 233e97f

Browse files
authored
Merge pull request #4 from ngoviet/audit/robustness-and-thread-safety
fix(core): thread-safe MQTT callbacks, off-loop blocking I/O, extended register map
2 parents 8a39c2f + 602e5a5 commit 233e97f

53 files changed

Lines changed: 4244 additions & 1525 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.codegraph/.gitignore‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# CodeGraph data files — local to each machine, not for committing.
2+
# Ignore everything in .codegraph/ except this file itself, so transient
3+
# files (the database, daemon.pid, sockets, logs) never show up in git.
4+
*
5+
!.gitignore

‎.gitignore‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,22 @@ CLAUDE.md
8383
# Preparation files
8484
PREPARE_GITHUB.md
8585

86+
87+
# repowise API keys (local)
88+
.repowise/
89+
.repowise-workspace*
90+
.repowise/.env
91+
92+
# MCP / editor tooling (local only)
93+
.mcp.json
94+
.playwright-mcp/
95+
.lavish/
96+
97+
# RE artifacts and vendor dumps (local only)
98+
# Contains live tokens, EMQX admin credentials, and captured device records — never publish.
99+
tools/
100+
legacy/
101+
*.xapk
102+
*.apk
103+
mqtt_discovery.json
104+
api_exploration_*.json

‎CLAUDE.md‎

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
# lumentreeHA — Home Assistant Lumentree Solar Inverter Integration
1+
# lumentreeHA — Home Assistant Lumentree Solar Inverter Integration
22

33
HACS custom integration for Lumentree hybrid solar inverters. Real-time MQTT monitoring, energy statistics, battery management, PV power tracking. MIT licensed.
44

55
## Project Overview
66

7-
Monitors Lumentree inverters via MQTT. Provides 100+ sensors per inverter: PV input (2 strings), battery (voltage/current/power/SOC/temperature), grid (import/export), load, daily/monthly/yearly/total energy, inverter status/temperature/faults.
7+
Monitors Lumentree inverters via MQTT. Provides 83 sensor entities per inverter (55 real-time + 28 statistics): PV input (2 strings), battery (voltage/current/power/SOC/temperature), grid (import/export), load, daily/monthly/yearly/total energy, inverter status/temperature.
88

99
### Stack
1010
- **Language**: Python 3.11+
@@ -15,20 +15,19 @@ Monitors Lumentree inverters via MQTT. Provides 100+ sensors per inverter: PV in
1515
## Architecture
1616

1717
```
18-
├── __init__.py # Integration entry — async_setup_entry, MQTT subscribe
19-
├── const.py # MQTT topics, device classes, units, defaults
20-
├── config_flow.py # UI config flow — MQTT broker + inverter settings
21-
├── common.py # Shared utilities, value parsing
22-
├── sensor.py # LumentreeSensor (Entity)
23-
├── binary_sensor.py # Status/fault binary sensors
24-
├── diagnostics.py # HA diagnostics support
25-
├── core/ # MQTT client, data models
26-
├── coordinators/ # DataUpdateCoordinator per inverter
27-
├── entities/ # Entity definitions by sensor group
28-
├── services/ # HA service definitions
29-
├── models/ # Pydantic data models
30-
├── translations/ # i18n (strings.json)
31-
└── tests/ # pytest test suite
18+
├── __init__.py # Integration entry — async_setup_entry, MQTT subscribe
19+
├── const.py # MQTT topics, device classes, units, defaults
20+
├── config_flow.py # UI config flow — MQTT broker + inverter settings
21+
├── common.py # build_device_info (DeviceInfo for sensor/binary_sensor)
22+
├── sensor.py # LumentreeSensor (Entity)
23+
├── binary_sensor.py # Status/fault binary sensors
24+
├── diagnostics.py # HA diagnostics support
25+
├── core/ # HTTP API client, MQTT client, Modbus parser, exceptions
26+
├── coordinators/ # DataUpdateCoordinator per inverter
27+
├── entities/ # Entity definitions by sensor group
28+
├── services/ # HA service definitions
29+
├── translations/ # i18n (en.json; source strings in strings.json)
30+
└── tests/ # pytest test suite
3231
```
3332

3433
## Build/Test
@@ -52,30 +51,31 @@ python -m hassfest
5251

5352
## Code Conventions
5453

55-
- **Pattern**: HA DataUpdateCoordinator pattern — coordinator polls data, entities read from coordinator
56-
- **MQTT topics**: Subscribed in `__init__.py`, parsed in `common.py`, stored in coordinator
54+
- **Pattern**: HA DataUpdateCoordinator pattern — coordinator polls data, entities read from coordinator
55+
- **MQTT topics**: Subscribed in `core/mqtt_client.py`, parsed in `core/realtime_parser.py`, stored in coordinator
5756
- **Entities**: One entity per sensor value, grouped by domain (sensor/binary_sensor)
5857
- **Config flow**: UI-based setup, no manual YAML required. Validates MQTT connectivity.
59-
- **Naming**: Follow HA conventions — snake_case files, PascalCase classes
60-
- **Types**: All new code must have type hints. Pydantic models in `models/` for data structures.
61-
- **Anti-patterns**: Avoid blocking calls in async context. Use `async_add_executor_job` for MQTT operations.
58+
- **Naming**: Follow HA conventions — snake_case files, PascalCase classes
59+
- **Types**: All new code must have type hints.
60+
- **Anti-patterns**: Avoid blocking calls in async context. Use `async_add_executor_job` for any file or network I/O — coordinators, the API client and the MQTT client all do.
61+
- **Anti-patterns**: Never call a vendor write endpoint (`bind device`, `register`, `upSnAddress`, `setRemarkName`, `delDevice`, `device/sendMsg`). `iot_class: cloud_polling` means read-only Tier 1 only.
6262
- **Translation**: All user-facing strings in `strings.json`, no hardcoded English in entities.
6363

6464
## MQTT Topic Structure
6565

66+
Two topics per inverter, both built in `const.py` and formatted in `core/mqtt_client.py`:
67+
6668
```
67-
lumentree/{serial_number}/pv/input1/power
68-
lumentree/{serial_number}/pv/input1/voltage
69-
lumentree/{serial_number}/battery/power
70-
lumentree/{serial_number}/battery/soc
71-
lumentree/{serial_number}/grid/power
72-
lumentree/{serial_number}/load/power
73-
lumentree/{serial_number}/energy/total
74-
...
69+
reportApp/{device_sn} # subscribe — the device publishes its Modbus-RTU frame here
70+
listenApp/{device_sn} # publish — the integration sends read commands here
7571
```
7672

73+
The payload is a hex-encoded Modbus-RTU frame, not JSON, and there is no per-metric topic tree.
74+
See [docs/api/REGISTER_MAP.md](docs/api/REGISTER_MAP.md) for the register layout.
75+
7776
## HACS
7877

7978
- `hacs.json` at root, `manifest.json` for HA metadata
8079
- Version tracked via GitHub Releases (semantic versioning)
81-
- HA >= 2024.3.0 required
80+
- Effective HA floor is **2024.4**, not the `2023.1.0` declared in `hacs.json`: `config_flow.py` does a runtime `from homeassistant.config_entries import ConfigFlowResult`, and that symbol only exists from 2024.4. On 2023.1–2024.3 the integration installs and then fails at setup.
81+
- Python 3.11+ (`asyncio.timeout` in the coordinators).

‎CONTRIBUTING.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Cảm ơn bạn đã quan tâm đóng góp! Dự án này được duy trì bở
2121
5. Submit a pull request
2222

2323
### Code style
24-
- Python 3.9+, Home Assistant 2023.1+
24+
- Python 3.11+, Home Assistant 2024.4+
2525
- Follow existing patterns in the codebase
2626
- Use `__slots__` for new classes
2727
- Log with module-level `_LOGGER`

‎README.md‎

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,10 @@ High-performance **Home Assistant custom integration** for **Lumentree hybrid so
4242
- **Battery Management**: Power, voltage, current, SOC (%), status (Charging/Discharging)
4343
- **Grid Power**: Import/export power + status
4444
- **Load Power**: Total consumption monitoring
45-
- **AC Output**: Voltage, frequency, power, apparent power
46-
- **AC Input**: Voltage, frequency, power
47-
- **Device**: Temperature, online status, UPS mode, serial number
45+
- **AC Output**: Voltage, frequency, power, apparent power, current
46+
- **AC Input**: Voltage, frequency, power, current
47+
- **Battery Settings**: Capacity, charge/discharge current limits, charge voltages, protection thresholds
48+
- **Device**: Temperature, online status, UPS mode, serial number, inverter/generator power
4849
- **Battery Cells**: Individual cell voltage monitoring
4950

5051
### Daily Statistics (HTTP API — 5min refresh)
@@ -53,11 +54,12 @@ High-performance **Home Assistant custom integration** for **Lumentree hybrid so
5354
- **288-point 5-minute series** for detailed charts
5455

5556
### Monthly Statistics
56-
- 9 metrics: PV, Charge, Discharge, Grid, Load, Essential, Total Load, Saved (kWh), Savings (VND)
57+
- 7 metrics: PV, Charge, Discharge, Grid, Load, Essential, Total Load
58+
- Saved (kWh) and Savings (VND) as state attributes
5759
- **Daily arrays** for month-view charts (1-31 days)
5860

5961
### Yearly Statistics
60-
- 9 metrics with **monthly arrays** for year-view charts (1-12 months)
62+
- 7 metrics with **monthly arrays** for year-view charts (1-12 months)
6163
- Historical data across multiple years via disk cache
6264

6365
### Lifetime/Total Statistics
@@ -75,8 +77,8 @@ High-performance **Home Assistant custom integration** for **Lumentree hybrid so
7577

7678
## Requirements
7779

78-
- **Home Assistant**: 2023.1+
79-
- **Python**: 3.9+
80+
- **Home Assistant**: 2024.4+ (`config_flow.py` imports `ConfigFlowResult`, added in 2024.4; `hacs.json` still declares `2023.1.0`)
81+
- **Python**: 3.11+ (the coordinators use `asyncio.timeout`, added in 3.11; the parser and sensor modules also annotate signatures with `X | None` without `from __future__ import annotations`, which Python 3.9 evaluates at import time and rejects)
8082
- **Dependencies**: aiohttp>=3.8.0, paho-mqtt>=1.6.0, crcmod>=1.7
8183
- **Network**: Internet (API + MQTT to `lesvr.suntcn.com`)
8284

@@ -107,24 +109,30 @@ High-performance **Home Assistant custom integration** for **Lumentree hybrid so
107109

108110
## Available Entities
109111

110-
### Real-time Sensors (26 entities)
112+
### Real-time Sensors (48 entities enabled, 55 defined)
111113
| Category | Sensors |
112114
|----------|---------|
113-
| Power | PV1, PV2, PV Total, Battery, Grid, Load, AC Output, AC Input, Total Load |
114-
| Voltage | Battery, PV1, PV2, Grid, AC Output, AC Input |
115-
| Current | Battery |
115+
| Power | PV Power, PV1, PV2, Battery, Grid, Load, Total Load, AC Output, AC Input, Apparent Power, Generator, CT Trickle Feed |
116+
| Voltage | Battery, PV1, PV2, Grid, AC Output, AC Input, Equalizing/Boost/Float Charge Voltage, Battery Low Voltage Protection, Battery Recovery Voltage |
117+
| Current | Battery, AC Input, AC Output, Battery Maximum Charge Current, Maximum Discharge Current |
118+
| Energy | PV Input Today |
116119
| Frequency | AC Output, AC Input |
117-
| Status | Battery SOC (%), Battery Status, Grid Status, Battery Type, UPS Mode, Master/Slave |
118-
| Info | Device Temperature, MQTT Device SN, Battery Cell Info |
120+
| Status | Battery SOC (%), Battery Status, Grid Status, Battery Type, UPS Mode, Master/Slave, AI Mode, Self-Consumption Ratio |
121+
| Setting (diagnostic) | Battery Capacity, Low Capacity Cutoff Point, Protecting Recovery Point, Equalizing Charge Interval, Equalizing Charge Time, Grid Type, AC Output Frequency Setting, Charge From AC, AC Coupling |
122+
| Info (diagnostic) | Device Temperature, Work Mode, Battery Mode, Firmware Version, Controller Version, Battery Cell Info, MQTT Device SN |
123+
124+
Seven real-time sensors ship disabled by default (PV1/PV2 power and voltage, AC Input Voltage, MQTT Device SN, Last Raw MQTT Hex); enable them in the entity registry if you need them. The voltage, current and setting entities stay `unknown` on units that answer with the shorter common frame, rather than reporting a fabricated value. See [docs/api/REGISTER_MAP.md](docs/api/REGISTER_MAP.md).
119125

120126
### Statistics Sensors (28 entities)
121127
| Period | Metrics | Refresh |
122128
|--------|---------|---------|
123129
| Daily (7) | PV, Charge, Discharge, Grid, Load, Essential, Total Load | 5 min |
124-
| Monthly (7) | Same + Saved (kWh) + Savings (VND) | 5 min |
125-
| Yearly (7) | Same + monthly arrays for charting | 5 min |
130+
| Monthly (7) | Same as Daily | 5 min |
131+
| Yearly (7) | Same, plus monthly arrays as attributes for charting | 5 min |
126132
| Total (7) | Lifetime cumulative sums | 5 min |
127133

134+
Saved energy (kWh) and cost savings (VND) are exposed as state attributes on the statistics sensors, not as separate entities.
135+
128136
### Binary Sensors (2 entities)
129137
- Online Status, UPS Mode
130138

0 commit comments

Comments
 (0)