mbta2mqtt
is a bridge between the MBTA's
real-time data API and MQTT.
It's meant to be very lightweight, and as a core principle keeps no state. It just gets updates and sends them on.
While you can make requests to the MBTA API without an API key, this uses the streaming API. And that requires an API key. You can get one from the MBTA developer portal.
The default config expects this to be stored in an
environment variable MBTA_API_KEY
. You can also just
put it in the config file.
You'll also need the hostname and port of your MQTT broker (like Mosquitto. If you're using localhost on the default port with no authnetication, this will just work with the defaults.
And, you'll need a list of MBTA stops by number. As of right now, I've only tested this with the bus. Theoretically it should work with the subway too, and for that matter commuter rail, but I haven't tested it and there are probably related bugs.
Stop IDs are easy to find: search on
mbta.com and then look at the
number in the URL. Like, Massachusetts Ave @ Newbury St
is https://www.mbta.com/stops/93 — stop 93
.
This is true for T stations, too. For example, Central
Square in Cambridge is https://www.mbta.com/stops/place-cntsq,
and the corresponding stop ID is place-cntsq
.
Be aware that bus stop numbers just cover one side of the street — one direction. The opposite side will be an entirely different stop.
After you get your API key, add that as a secret:
printf api_key_string | podman secret create MBTA_API_KEY -
(Replacing api_key_string
with the actual hex string, of
course.) Then, use podman run
something like this:
podman run --secret=MBTA_API_KEY,type=env \
--net=host --volume .:/var/log/mbta2mqtt:Z \
quay.io/mattdm/mbta2mqtt /opt/mbta2mqtt/mbta2mqtt.py \
place-davis place-portr
... where place-davis
and place-portr
are the stops
you want predictions for. This will write logs to .
—
the current directory. For "real" use, you'll want to
change that to something else.
This should "just work" if your MQTT broker is running
on localhost:1883
. Otherwise (and in general because
you will probably want to make some other changes),
copy example.conf
to a location on
your host of your chosing, and put that into the
container with
----volume /location/mbta2mqtt.conf:/etc/mbta2mqtt/mbta2mqtt.conf
.
And you'll want to change the log output volume
mount, too!
For actual use, add --detatch
(or just -d
) to
run in the background, and (see below) probably also
--restart=on-failure
, unless you're using systemd
or some other service manager.
Take a look at defaults.conf
.
Everything that's there can be overridden or
extended by a further configuration file, like
/etc/mbta2mqtt/mbta2mqtt.conf
.
It's important to be aware that we are not tracking the state of the whole MBTA system.
We're only getting updates for resources associated with the stops listed in the configuration — and then the resources associated with those So, for example, we don't know about every bus on a route, just ones that there are currently predictions for that are associated with one of these stops.
However, this cascades — we get updates for all of the related resources. That means you'll see messages (and Home Assistant entities) for other stops on any route that has a prediction associated with your configured list of stops.
So, you'll see lots of stops and other entries that seem random. They're not really random, though — they're there because they're referenced by something (maybe going through several degrees of separation). You might need them if, for exxample, you want to find the name of the stop where your (hoped-to-be) future bus is right now.
Since data is passed through with minimal processing, you can find the description and details for each resource type in the MBTA v3 API docs. (I'd link directly, but that's not possible ^[issue: swagger-api/swagger-ui#1369], so... scroll down to Models and find each one.)
- AlertResource
- LineResource
- RredictionResource
- RouteResource
- StopResource
- TripResource
- VehicleResource
Again, an opinionated choice: the basic approach to dealing with HTTP or MQTT errors is to log them and quit, rather than trying to recover.
I expect that this will run in a container or under some other service management, which should then just restart (possibly with some kind of increasing delay).
At the next startup, the MBTA API will send a 'reset' message, and so everything should be cleaned up and ready to go.
mbta2mqtt
sends
MQTT Discovery
messages for Home Assistant. If you have MQTT set up, this
will create (and of course update) sensor entities which represent
the real-time data resources sent by the T.
These sensor entities will (as configured by default) be named
using the prefix mbta
, followed by one of the resource types
as described above, followed by the particular name of that
thing. For example: sensor.mbta_route_90
.
The )useful_ information for these entities is stored as attributes. I've also tried to set the state for each entity type
We also set up a device corresponding to the stops you're following, for convienience and visability. Not all entities will be attached to this device, because it's kind of overwhelming if we do that. And remember, that will icnlude entities for other stops that you're not getting predictions for.
When mbta2mqtt
exits cleanly, it will remove all entities
and devices. (It'll also do this when it starts, so it doesn't
leave old stuff around.)
So, again, nothing tracks state. As it is, the Home Assistant device associated with a stop is kind of useful — it shows the predictions with bus lines and times:
However, there is a lot more buried in the attributes
of the prediction sensors, and even more in attributes of
entities which aren't associated with the device. For example,
the prediction might have an assocated active alert. But
the attributes just show the alert number. You need to
find the entity for that — its will be sensor.mbta_alert_NNNN
,
where NNNN
is the number — to see the details.
A useful dashboard would display all of this.
My current two competing ideas are:
-
Create template sensors and templated dashboard views in Home Assistant with all the proper connections.
-
Make a separate little service which does keep state, at least in-memory, and which creates more useful Home Assistant sensors and devices.
Or maybe it's best to just make a whole (separate) Home Assistant integration.
Current big rough list:
- Write some home assistant template entities.
- And a dashboard card.
- Refactor code to make less hacky, y'know?
- Make some control stuff from Home Assistant.
- change / set stops
- restart
There are plenty of other things to address, of course!
Yes, please! However, I definitely don't have the spare time to make this a big project. If you'd like to actually own this, or are inspired by my hacky code to make something better, let's talk!