Home Assistant — first-class citizen.
BudMaster ships with native MQTT auto-discovery. Enable MQTT in Settings, point it at your local broker (Mosquitto add-on, or the broker that already runs alongside HA), and every sensor and actuator appears in Home Assistant without any configuration on the HA side. No custom integration to install, no YAML to write, no HACS dependency.
Temp, humidity, VPD, CO₂, PAR, DLI, soil pH/EC/NPK, fan RPM, light dim %, every relay state — all show up with proper units, device classes and friendly names.
HA can set targets too: change stage, override fan, toggle CO₂, trigger a recipe. The controller publishes state-changes back so HA stays in sync.
No HA Cloud account needed. No Nabu Casa pass-through. The whole loop runs on your LAN at MQTT-typical latency (a few milliseconds).
If HA restarts, the controller keeps running. If the controller restarts, HA discovers it again automatically. Either side can come and go.
Bare-minimum HA config
If your HA already has the MQTT integration set up, this is literally all the YAML you need — the rest is handled by discovery.
configuration.yaml# Nothing. Discovery does it.
# (If you don't yet have the MQTT integration:
# Settings → Devices & Services → Add Integration → MQTT
# Broker: your broker's IP, port 1883, no auth needed locally.)
If you prefer the explicit-template-sensor route — for example because you want a single endpoint without running an MQTT broker — you can pull the JSON straight from the controller's REST API:
configuration.yaml · REST sensorrest: - resource: http://budmaster.local/api/environment scan_interval: 30 sensor: - name: "Grow VPD" value_template: "{{ value_json.vpd }}" unit_of_measurement: "kPa" device_class: pressure - name: "Grow CO2" value_template: "{{ value_json.co2 }}" unit_of_measurement: "ppm" device_class: carbon_dioxide - name: "Grow score" value_template: "{{ value_json.score }}"
ESPHome — drop-in YAML.
If you’re running ESPHome and you’d rather BudMaster appear as just another ESPHome device (same dashboard, same OTA, same logs), grab the prebuilt YAML from the controller’s /api/esphome endpoint and add it to your ESPHome dashboard. The controller responds in the same vocabulary your other ESPHome nodes already use.
substitutions: device_name: budmaster-nexus device_ip: 192.168.1.100 # Pulls every entity from the live device. # Refresh nightly via ESPHome scheduled action. packages: budmaster: !include budmaster_remote.yaml
The fetched YAML covers all sensors, all switches, all selects, and a status sensor that reports firmware version + last-seen so HA knows when the unit’s been offline.
Node-RED — the flow you already have.
Anything you can do in Node-RED with HTTP request and MQTT-in / MQTT-out nodes, you can do with BudMaster. Common patterns we see in customer setups:
Subscribe to budmaster/risk/bud_rot. On true → push to Pushover / Discord / Telegram with the current temp + RH + recommended action.
At lights-off, change BudMaster stage to night; at lights-on, switch back. Useful when running a non-standard photoperiod ESPHome can’t express.
Read VPD from two BudMasters; if room A drifts >0.2 kPa from room B, log a warning to InfluxDB.
Count solenoid-on minutes per day, model bottle life from CFM-rate, push a Discord notification when 7 days’ supply remaining.
Minimal flow — alert on canopy temp out-of-band
node-red · HTTP poll// Inject (every 60s) → HTTP request → Function → Switch → Push notification // URL: http://budmaster.local/api/environment // Function: if (msg.payload.temp > 30 || msg.payload.temp < 18) { msg.payload = `Canopy ${msg.payload.temp}°C — out of band`; return msg; } return null;
MQTT — topic structure you can predict.
If you'd rather skip the auto-discovery and hand-roll your own subscriptions (MQTT-style integrations, custom dashboards, scripts), the topic tree is flat and predictable:
topic structure# State (read-only — controller publishes, you subscribe) budmaster/<device-id>/sensor/temp # float, °C budmaster/<device-id>/sensor/rh # float, % budmaster/<device-id>/sensor/vpd # float, kPa budmaster/<device-id>/sensor/co2 # int, ppm budmaster/<device-id>/sensor/par # float, μmol/m²/s budmaster/<device-id>/sensor/dli # float, mol/m²/day (rolling) budmaster/<device-id>/state/stage # seedling | veg | flower | flush budmaster/<device-id>/state/mode # auto | manual # Commands (write — you publish, controller acts) budmaster/<device-id>/cmd/stage # set stage budmaster/<device-id>/cmd/mode # set mode budmaster/<device-id>/cmd/fan/extract # 0-100 PWM % budmaster/<device-id>/cmd/co2/target # target ppm
QoS 1 by default. LWT (last will + testament) on budmaster/<device-id>/availability so subscribers know when the controller has dropped offline.
Grafana + InfluxDB — your own dashboards.
The built-in BudMaster dashboard is good. If you want your own dashboards — multi-room overlays, per-strain comparisons, year-on-year yield charts — point an InfluxDB-Telegraf exec at the REST endpoint, then point Grafana at InfluxDB. Same pattern as a thousand smart-home setups.
telegraf.conf · HTTP input[[inputs.http]] urls = ["http://budmaster.local/api/environment"] data_format = "json" interval = "30s" tag_keys = ["stage", "mode"] json_string_fields = ["firmware_version"] [[outputs.influxdb_v2]] urls = ["http://localhost:8086"] token = "$INFLUX_TOKEN" bucket = "grow"
From there, every chart in Grafana is a one-line Flux query against the grow bucket. The metrics tag automatically by stage and mode, so you can filter for "flower-stage VPD over the last 90 days" without any special handling.
REST API — if you're rolling your own.
Every endpoint returns JSON. Authentication is a single bearer token (set in Settings, copy once). No OAuth dance, no rate limit drama, no SDK to install. Documentation lives at /api.html and also at /api/docs on the controller itself, so it stays in sync with the firmware version you’re actually running.
# Read every live sensor curl http://budmaster.local/api/environment # Set a target curl -X POST http://budmaster.local/api/co2/target \ -H "Authorization: Bearer $TOKEN" \ -d '{"ppm": 1200}' # Switch stage curl -X POST http://budmaster.local/api/mode \ -H "Authorization: Bearer $TOKEN" \ -d '{"stage": "flower"}'
The thing nobody else does — no cloud bridge.
Most "smart" grow controllers route every reading through the manufacturer’s servers and back. Fine until the company loses a database, gets bought, changes the API, or just shuts the cloud down. Your dashboard goes dark; your automation breaks.
BudMaster has no cloud. We don’t run one because we don’t want to. The controller talks directly to your home network and only your home network. Every protocol on this page works inside your LAN with zero traffic crossing the internet.
If we vanish tomorrow, nothing changes. The MQTT topics keep publishing. The REST API keeps responding. The Home Assistant integration keeps working because it never depended on us in the first place. That’s the whole point.