Serial format is PPPPPP+SSSSSS+0001 — slice(-6) was picking up the trailing 0001 suffix. slice(6,12) gives the correct device identifier. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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 plugin
- Manual commands via MQTT (
/settopics) - 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:
cp .env.example .env
Required:
SOLEM_EMAIL/SOLEM_PASSWORD— MySolem account credentialsMQTT_URL— your MQTT broker (e.g.mqtt://192.168.1.10:1883)
2. Run locally
npm install
node src/index.js
3. Run with Docker
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:
{ "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 and configure accessories pointing to the MQTT topics above.
Example for pool light switch:
{
"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
# 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