# 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 0–5) | | 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 ```