Files
arnaudne 941abd98d5 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>
2026-06-28 01:05:24 +02:00

201 lines
5.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# myprimal
MQTT bridge for the MySolem / MyIndygo IoT platform (irrigation + pool). Reverse-engineered client that dynamically discovers all devices and exposes them via MQTT with Home Assistant autodiscovery and Homebridge EasyMQTT compatibility.
## Features
- Auto-discovers all modules, sensors, and outputs on startup
- Polls sensor readings on configurable intervals
- Publishes to MQTT with retained state
- Home Assistant MQTT autodiscovery (sensors + switches)
- Compatible with Homebridge [EasyMQTT](https://github.com/Shaquu/homebridge-easymqtt) plugin
- Manual commands via MQTT (`/set` topics)
- Runtime poll interval tuning via MQTT
- REST API for health, state snapshot, and direct control
- Docker deployment
## Setup
### 1. Configure
Copy `.env.example` to `.env` and fill in credentials:
```bash
cp .env.example .env
```
Required:
- `SOLEM_EMAIL` / `SOLEM_PASSWORD` — MySolem account credentials
- `MQTT_URL` — your MQTT broker (e.g. `mqtt://192.168.1.10:1883`)
### 2. Run locally
```bash
npm install
node src/index.js
```
### 3. Run with Docker
```bash
docker compose up -d
```
On first run, `config.json` is created in the Docker volume for persistent poll interval settings.
## MQTT Topics
All topics are prefixed with `MQTT_TOPIC_PREFIX` (default: `myprimal`).
### Sensor readings (retained)
```
myprimal/{module_slug}/sensor/{metric}
```
Payload: `{"value": 24.5, "unit": "°C", "ts": "2026-06-28T10:00:00.000Z"}`
Examples:
```
myprimal/lrpc_f1da27/sensor/temperature {"value": 24.5, "unit": "°C", ...}
myprimal/lrps_0565c0/sensor/ph {"value": 7.35, "unit": "pH", ...}
myprimal/lrps_0565c0/sensor/orp_redox {"value": 690, "unit": "mV", ...}
myprimal/lr6ag_070917/sensor/plumbago {"value": 54, "unit": "%", ...}
```
### Output state (retained)
```
myprimal/{module_slug}/output/{index}/state
```
Payload: `{"value": 0, "ts": "..."}``value` 1 = running, 0 = stopped
### Commands
```
myprimal/{module_slug}/output/{index}/set
```
Payload:
```json
{ "action": "run", "duration": 30 } // run for 30 minutes
{ "action": "stop" } // stop immediately
{ "action": "boost", "duration": 120 } // boost (pool pump only)
{ "action": "pause", "days": 3 } // pause/rain delay N days
```
### Availability (retained)
```
myprimal/{module_slug}/availability "online" | "offline"
```
### Config (retained, runtime-tunable)
Read current config:
```
myprimal/$config
```
Update poll intervals (seconds):
```
myprimal/$config/set {"poll": {"fast": 30, "normal": 120}}
```
Update interval for a specific sensor:
```
myprimal/$config/set {"poll": {"overrides": {"lrps_0565c0/ph": 30}}}
```
Changes take effect immediately and persist across restarts.
### Poll buckets (defaults)
| Bucket | Default | Sensor types |
|---|---|---|
| `fast` | 60s | pH, ORP, pressure, water temperature |
| `normal` | 300s | Soil moisture, air temperature, flow |
| `slow` | 900s | Binary sensors (rain, level switch, valve state) |
## Home Assistant
Entities are auto-created via MQTT discovery on startup. Check **Settings → Devices & Services → MQTT** — all Solem devices appear automatically.
Discovery topics: `homeassistant/{sensor|binary_sensor|switch}/myprimal_{id}/config`
No manual configuration required.
## Homebridge (EasyMQTT)
Install [homebridge-easymqtt](https://github.com/Shaquu/homebridge-easymqtt) and configure accessories pointing to the MQTT topics above.
Example for pool light switch:
```json
{
"accessory": "EasyMQTT",
"name": "Pool Light",
"type": "Switch",
"mqttGetTopic": "myprimal/lrpc_f1da27/output/1/state",
"mqttSetTopic": "myprimal/lrpc_f1da27/output/1/set",
"mqttGetTransformation": "return JSON.parse(message).value === 1 ? 'true' : 'false';",
"mqttSetTransformation": "return value === 'true' ? JSON.stringify({action:'run',duration:30}) : JSON.stringify({action:'stop'});"
}
```
## REST API
| Method | Path | Description |
|---|---|---|
| `GET` | `/health` | Service health + counts |
| `GET` | `/state` | All cached sensor readings |
| `GET` | `/state/:moduleId` | Readings for one module |
| `GET` | `/registry` | Full device registry |
| `POST` | `/control/:moduleId/:outputIndex` | Send manual command |
| `POST` | `/rediscover` | Re-discover all devices |
### Control example
```bash
# Run pool light (LRPC output 1) for 30 minutes
curl -X POST http://localhost:3001/control/6481bcea8782b78554c02bed/1 \
-H 'Content-Type: application/json' \
-d '{"action":"run","duration":30}'
# Stop
curl -X POST http://localhost:3001/control/6481bcea8782b78554c02bed/1 \
-H 'Content-Type: application/json' \
-d '{"action":"stop"}'
```
## Module Slug Reference (Domicile)
| Module | Slug | Type |
|---|---|---|
| LRPC-F1DA27 (pool controller) | `lrpc_f1da27` | Filtration pump (output 0), light (output 1) |
| LR6AG-070917 (irrigation) | `lr6ag_070917` | 6 irrigation stations (outputs 05) |
| LRMS-0721DC (sensor station) | `lrms_0721dc` | Soil moisture × 2, air temp |
| LRPS-0565C0 (pool analyser) | `lr_mas_0565c0` | Water temp, pH, ORP |
| LRPR-0D6800 (filter pressure) | `lr_pr_0d6800` | Filter pressure |
| LRLEVEL-0D2ED9 (fill valve) | `lr_niv_0d2ed9` | Fill valve control |
| LR2IPECO-0C9282 | `lr_ip_eco_0c9282` | Flow meter |
| POOL-LVL-0E953B (level switch) | `pool_level_sensor_0e953b` | Pool level binary |
## Architecture
```
MySolem API ──► solem.js (auth + HTTP)
registry.js (device discovery on startup)
poller.js (per-bucket poll timers)
state.js (in-memory cache, EventEmitter)
┌─────────┴──────────┐
mqtt/publish.js api/routes.js
mqtt/discovery.js (REST API)
mqtt/commands.js ──► control.js ──► MySolem API
mqtt/config-bridge.js
```