feat: initial myprimal MQTT bridge service

Dynamic MySolem/MyIndygo IoT bridge with MQTT, Home Assistant
autodiscovery, and Homebridge EasyMQTT compatibility.

- Device discovery via MySolem API on startup (all modules/inputs/outputs)
- Configurable poll engine (fast/normal/slow buckets, per-input overrides)
- MQTT retained state publishing + HA autodiscovery payloads
- Unified manual command routing (linesControl vs sendManualModuleCommand)
- Runtime config via MQTT $config/set, persisted to config.json
- Expression override system (API-provided > hardcoded > passthrough)
- Minimal REST API: /health, /state, /control, /rediscover
- Docker deployment (Dockerfile + docker-compose.yml)
- 38 unit tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-28 01:05:24 +02:00
commit 941abd98d5
48 changed files with 12118 additions and 0 deletions
+101
View File
@@ -0,0 +1,101 @@
# LR6AG — Agricultural Valve Controller (LR6AG-070917)
**Module ID**: `626984f038ec558c598bb6d5`
**Serial**: `6606010709170001`
**Type**: `lr-ag`
**Role**: Controls 6 irrigation stations, has 1 rain sensor input
---
## Input
| Input ID | Name | Type | Unit | Notes |
|---|---|---|---|---|
| `626984f038ec558c598bb6d7` | *(unnamed)* | 2 (TOR/on-off) | raw | Rain sensor — value 1=rain, 0=clear |
### Rain sensor — recent state
```
2026-06-04T15:37 value=1 (rain detected)
2026-06-03T10:57 value=0 (clear)
2026-06-02T12:19 value=1 (rain detected)
2026-05-28T19:06 value=0 (clear)
2026-05-28T19:05 value=0
```
---
## Outputs
| Output ID | Name | Index | Flow rate |
|---|---|---|---|
| `626984f038ec558c598bb6d8` | Station 1 | 0 | 30 m³/h |
| `626984f038ec558c598bb6d9` | Station 2 | 1 | 14 m³/h |
| `626984f038ec558c598bb6da` | Station 3 | 2 | 20 m³/h |
| `626984f038ec558c598bb6db` | Station 4 | 3 | 1 m³/h |
| `626984f038ec558c598bb6dc` | Station 5 | 4 | 38 L/h |
| `626984f038ec558c598bb6dd` | Station 6 | 5 | 38 L/h |
Flow rate unit: `1` = L/h, `2` = m³/h
---
## Programs
6 programs (one per station), all **reset on 2026-06-04 with no active windows**.
Programs are named Station 16 (type 3 = standard irrigation).
```
GET /programs/modules?moduleIds=626984f038ec558c598bb6d5
```
---
## Remote state
```
GET /remote/module/state?moduleId=626984f038ec558c598bb6d5
```
- Battery: 81%
- Last radio contact: 2026-06-04T19:57:05Z
- Relay: `60ca4276ad69dac1558f7c61` (LRMB10)
**Live output status** (from `state.ag.outputs`):
| Station | State | Rain delay |
|---|---|---|
| 0 | off | 255 days |
| 1 | off | 255 days |
| 2 | off | 0 |
| 3 | off | 0 |
| 4 | off | 0 |
| 5 | off | 0 |
Stations 0 and 1 have a rain delay of 255 — effectively suspended indefinitely.
`state` field: `0` = off, `1` = on/running.
---
## Manual control
```
POST /module/sendManualModuleCommand
{
"moduleSerialNumber": "6606010709170001",
"commandType": "station",
"outputIndex": 0,
"command": null,
"commandParams": { "hours": 0, "minutes": 15, "on": 0, "off": 0 }
}
```
Rain delay (suspend station):
```json
{
"moduleSerialNumber": "6606010709170001",
"commandType": "status",
"command": "off",
"commandParams": 7,
"outputIndex": 0
}
```
`commandParams` = number of days to delay (255 = maximum/indefinite).