PubliBike Stations Info auf SmartMirror

Ich bin zur Zeit immer wieder mit Velos von PubliBike in Bern unterwegs. Bei der mir am nächsten liegende Station kommt es leider häufig mal vor, dass keine Velos, oder nur E-Bikes (ein E-Bike vom Ostring in die Stadt hinunter macht macht nicht viel Sinn) vorhanden sind. Daher habe ich mir überlegt, es wäre doch cool, wenn ich direkt auf meinem SmartMirror sehen könnte, ob es noch Velos an der Station hat (als Alternative zur Mobile-App). Doch sind die PubliBike Stationsinfos überhaupt öffentlich verfügbar?

Auf der Webseite von PubliBike lässt sich eine Karte mit allen Standorten anzeigen. Auf der Karte sind auch die Velo-Verfügbarkeiten pro Station angegeben.

Und da die Informationen ja irgendwie auf die Karte müssen, gehe ich davon aus, dass ich auch irgendwie darauf zugreifen kann. Ich zoome also mal auf die mir nächstgelegene Station (damit ich nur noch die Daten von dieser Station habe) und öffne die Entwicklerkonsole in meinem Browser. Mit Hilfe des Network-Tab schaue ich mir die Kommunikation der Webseite an. Schnell sehe ich folgenden Request:

Das sieht doch schon vielversprechend aus. Schauen wir uns doch mal die Response dazu an:

{
  "id": 332,
  "latitude": 46.943804,
  "longitude": 7.4694264,
  "state": {
    "id": 1,
    "name": "Aktiv"
  },
  "name": "Egelgasse-Ostring",
  "address": "Egelgasse 72",
  "zip": "3006",
  "city": "Bern",
  "vehicles": [
    {
      "id": 1965,
      "name": "501989",
      "type": {
        "id": 2,
        "name": "E-Bike"
      }
    },
    {
      "id": 2367,
      "name": "102526",
      "type": {
        "id": 1,
        "name": "Velo"
      }
    }
  ],
  "network": {
    "id": 5,
    "name": "Bern",
    "background_img": null,
    "logo_img": "https://www.publibike.ch/static-content/Netz5.svg",
    "sponsors": []
  },
  "sponsors": []
}

Voilà, genau was ich will.

Als nächstes müssen diese Daten auf meinen SmartMirror. Für die Anzeige von Temperaturen verwende ich bereits das Plugin MMM-haas. Dieses kann Sensor-Daten aus meinem Home-Assistant auslesen und auf der SmartMirror darstellen. Die Sensor-Daten wiederum sende ich per MQTT an Home-Assistant. Daher will ich für die PubliBike Daten den gleichen Weg gehen. Bei mir läuft unter anderen auch eine Node-Red Instanz, diese verwende ich nun um die API-Daten von PubliBike zu Verarbeiten und in einen MQTT Channel zu pushen. Der Node-Red Flow dafür sieht wie folgt aus:

Am Anfang des Flows verwende ich einen Inject-Node. Dieser injected einen Payload manuell oder in einem festgelegten Intervall in den Flow. Ich injecte damit die ID der gewünschten PubliBike Station. Danach kommt eine Function-Node der mir den HTTP-Request vorbereitet, d.H. die URL zusammenbaut (mit der ID aus dem vorherigen Node). Nun folgt ein HTTP Request Node der dann effektiv die PubliBike API aufruft und ein geparstes JSON-Objekt zurückliefern. Natürlich hätte ich auf einfach nur den HTTP Request Node verwenden können und die API URL gleich da drin zu speichern. Wie oben im JSON sichtbar, zeigt mir die API alle Velos (und E-Bikes) der aktuellen Station an. Nun muss ich diese aber noch zählen. Dazu verwende ich wieder einen Function-Node mit etwas JavaScript:

var bike = 0;
var ebike = 0;

var vehicles = msg.payload.vehicles;
var stationname = msg.payload.name

for (var x in vehicles) {
    
    vehicle = vehicles[x];
    
    if (vehicle.type.name == "E-Bike") {
      ebike++;
    }
  
    if (vehicle.type.name == "Velo") {
      bike++
    }
}

msg.payload = { "velo": bike, "ebike": ebike, "stationname" : stationname, }
msg.topic = "publibike/" + msg.payload.stationname

return msg;

Der Payload dieser Funktion kommt dann anschliessend in einen MQTT Out Node, der eine Message im ensprechenden Channel (Topic) erstellt. Damit habe ich mal die Anzahl Velos und E-Bikes regelmässig auf einem MQTT-Topic. Der Inject-Node habe ich übrigens mit einem 5 Minuten Intervall konfiguriert. Als nächsten Schritt sollen diese Daten nun von einem Home-Assistant Sensor ausgelesen werden.

Home-Assistant hat dafür einen MQTT-Sensor, ich erstelle also die Konfiguration und lade Home-Assistant neu.

sensor:
  - platform: mqtt
    name: "Publibike Egelgasse-Ostring - Velos"
    state_topic: "publibike/Egelgasse-Ostring"
    value_template: "{{ value_json['velo'] | int }}"
  - platform: mqtt
    name: "Publibike Egelgasse-Ostring - E-Bike"
    state_topic: "publibike/Egelgasse-Ostring"
    value_template: "{{ value_json['ebike'] | int }}"

In Home-Assistant sieht das dann wie folgt aus:

Jetzt fehlt noch die Konfiguration des MMM-haas Modul für den SmartMirror:

{
    module: "MMM-HASS",
    position: "bottom_left",
    config: {
        host: "....",
        port: "8123",
        https: false,
        hassiotoken: true,
        devices: [{
            deviceLabel: "publibike",
            deviceReadings: [{
                sensor: "sensor.publibike_egelgasse_ostring_velos",
                icon: "fa fa-bicycle",
                suffix: ""
                },
                {
                sensor: "sensor.publibike_egelgasse_ostring_e_bike",
                icon: "fa fa-plug",
                suffix: ""
                }
            ]
            },
        ]
    }
}

Auf dem SmartMirror ist nun das gewünschte Resultat zu sehen:

Übrigens, wie auf dem Bild zu sehen, habe ich auch die Daten von aare.guru auf den SmartMirror integriert. Das Vorgehen da war praktisch gleich (Node-Red -> MQTT -> HomeAssistant Sensor -> SmartMirror):