MQTT Integration

Connect SpojBoard to Home Assistant or any MQTT-capable server for custom transit data sources.

Overview

Instead of querying transit APIs directly, SpojBoard sends an MQTT request and receives departure data from your server. This enables:

  • Integration with Home Assistant automations
  • Custom data sources (any transit API, databases, web scraping)
  • Server-side data aggregation and filtering
  • Reduced API calls (server caches data for multiple displays)

Any MQTT-capable server will work β€” Home Assistant, Python scripts, Node-RED flows, or custom daemons.

How It Works

SpojBoard              MQTT Broker              Your Server
    β”‚                       β”‚                        β”‚
    │── "request" ────────>│──── Trigger ─────────>β”‚
    β”‚                       β”‚                        β”‚
    β”‚                       β”‚                  Fetch/Format
    β”‚                       β”‚                  Transit Data
    β”‚                       β”‚                        β”‚
    β”‚<── JSON response ────│<──── Publish ─────────│
    β”‚                       β”‚                        β”‚
  Parse &                                            
  Display
  1. SpojBoard publishes "request" to the request topic (every N seconds, configurable)
  2. Your server detects the request via MQTT subscription
  3. Server fetches and formats transit data from your sources
  4. Server publishes JSON response to the response topic
  5. SpojBoard receives, parses, and displays departures
Note: SpojBoard sends just the string "request" β€” not a JSON object. Your server already knows which stops to query.

SpojBoard Configuration

1. Select MQTT Mode

In the web interface, choose MQTT (Custom) from the City Selector.

2. MQTT Broker Settings

  • Broker Address: IP or hostname (e.g., 192.168.1.100 or homeassistant.local)
  • Broker Port: Default 1883
  • Username/Password: Optional, for authenticated brokers

3. MQTT Topics

  • Request Topic: Where SpojBoard publishes requests (e.g., home/spojboard/request)
  • Response Topic: Where SpojBoard listens for responses (e.g., home/spojboard/departures)

4. Select ETA Mode

ETA Mode

Server sends pre-calculated minutes. SpojBoard displays as-is.

Limitation: Requires frequent refresh (10-60s) to stay accurate.

"eta": 5

5. JSON Field Mappings

Configure how SpojBoard reads your JSON response. All field names are customizable:

Field Default Name Required Example
Line NumberlineYes"12", "A"
DestinationdestYes"SΓ­dl. Barrandov"
ETA (minutes)etaETA mode only5
Timestamp (unix)depTimestamp mode only1768154164
PlatformpltNo"D"
AC FlagacNotrue

Expected JSON Response

Your server should publish a JSON object with a departures array:

{
  "departures": [
    {
      "line": "12",
      "dest": "SΓ­dl. Barrandov",
      "dep": 1768154164,
      "plt": "D",
      "ac": false
    },
    {
      "line": "A",
      "dest": "Depo HostivaΕ™",
      "dep": 1768154284,
      "ac": true
    }
  ]
}

Dual Filtering Strategy

Minimum departure time filtering happens in two places:

  1. Server-side: Filter departures before sending (keeps MQTT payloads small)
  2. Device-side: Applied every 10 seconds during ETA recalculation
Important: Set the same minimum departure time on both server and device. For example, if SpojBoard is set to 3 minutes, your server template should also filter eta >= 3.

Home Assistant Example

1. MQTT Binary Sensor

Add to configuration.yaml:

mqtt:
  binary_sensor:
    - name: "SpojBoard Request"
      unique_id: spojboard_request
      state_topic: "home/spojboard/request"
      payload_on: "request"
      payload_off: "OFF"
      off_delay: 2

2. Template Sensor for Departures

Format your transit data into SpojBoard's JSON format:

template:
  - trigger:
      - platform: time_pattern
        seconds: "/15"
    sensor:
      - name: "SpojBoard Departures JSON"
        unique_id: spojboard_departures_json
        state: "{{ now().isoformat() }}"
        attributes:
          departures: >
            {% set ns = namespace(departures=[]) %}
            {# Add your transit sensors here #}
            {% for entity in your_transit_sensors %}
              {% set eta = ... %}
              {% if eta >= 3 %}
                {% set ns.departures = ns.departures + [{
                  'line': entity.state,
                  'dest': entity.attributes.destination,
                  'dep': as_timestamp(...) | int,
                  'ac': false
                }] %}
              {% endif %}
            {% endfor %}
            {{ ns.departures }}

3. Automation to Publish Response

automation:
  - alias: SpojBoard - Send Departures
    triggers:
      - trigger: state
        entity_id: binary_sensor.spojboard_request
        to: "on"
    actions:
      - action: mqtt.publish
        data:
          topic: home/spojboard/departures
          payload: >
            {{ {
              'departures': state_attr('sensor.spojboard_departures_json', 'departures')
            } | to_json }}

Troubleshooting

SpojBoard Not Receiving Messages

  • Check MQTT broker is running
  • Verify topic names match exactly (case-sensitive)
  • Check binary sensor toggles to "on" when SpojBoard requests
  • Check automation is enabled and triggering

Empty Departures Array

  • Verify template sensor has data in Developer Tools β†’ Template
  • Check transit sensors are not unknown or unavailable
  • Verify minimum ETA filter isn't too restrictive

Departures Not Counting Down

  • Verify you're in Timestamp mode and sending dep field with unix timestamps
  • Check SpojBoard logs show "ETA Recalc" every 10 seconds
  • Ensure NTP is synced on SpojBoard
Debugging: Use MQTT Explorer to monitor message flow, or mosquitto_sub -h localhost -t "#" -v in terminal.