HTTP-Anfragen

Wie du deine Sensoren über HTTP mit Stadtpuls reden lässt.

Stadtpuls erlaubt dir, Sensor-Daten über HTTP hinzuzufügen. Dies eröffnet viele Möglickeiten, wie du mit der Plattform interagieren kannst. Zum Beispiel könnte ein Raspberry Pi, ein Arduino Board, dein Browser, ein Webserver oder dein Smartphone (um nur einige zu nennen) Daten sammeln und sie auf Stadtpuls veröffentlichen. Voraussetzung ist, dass dein Endgerät das "Hypertext Transfer Protocol" (HTTP) spricht.

Im erstes Beispiel erklären wir dir, wie du mit einem einfachen Python-Script Werte auf Stadtpuls hinzufügen kannst.

Daten senden mit Python

Voraussetzungen

Folgende Voraussetzungen sollten erfüllt sein:

Du hast einen Stadtpuls Account
Du hast einen Token erstellt und dir sicher gespeichert
Du hast bereits einen Sensor vom Typ HTTP angelegt
Du hast Python (3)* installiert
Du hast einen Code Editor wie VSCode, Pycharm, Sublime Text, VIM, Nano oder ähnlich installiert
Du hast ein Terminal Emulator installiert**

* Python 2 geht auch, das Script ist jedoch nur mit Python 3 getestet und möglicherwiese nicht kompatibel mit Python 2.

** Jede Plattform hat ihr eigenes Terminal. Wir gehen hier von Linux oder MacOS aus und verwenden die BASH Shell. Für Windows gibt es z.B. die Powershell oder WSL, um zu dem gleichen Ergebnis zu kommen.

Python Script Schritt für Schritt

Erstelle eine neue Datei mit dem Name stadtpuls.py. Als erstes solltest du folgende Zeilen einfügen und speichern:

import requests
import json

Diese Zeilen sagen Python, welche Bibliotheken du benötigst. Führe die Datei aus, um zu sehen was passiert. Starte eine neue Shell Session in deinem Terminal und navigiere zu deinem Python Script. Dann führe folgenden Befehl aus:

python3 stadtpuls.py

Wenn du keinen Fehler bekommst, bist du bereit, weiter zu machen. Es könnte aber passieren, dass eine Fehlermeldung erscheint:

Traceback (most recent call last):
  File "stadtpuls.py", line 2, in <module>
    import requests
ModuleNotFoundError: No module named 'requests'

Das bedeutet, dass die Bibliothek requests nicht installiert ist. Diese kannst du mit dem Package Manager pip und folgendem Befehl intallieren:

pip install requests

Die json-Bibliothek ist eine System-Bibliothek und sollte standardmäßig vorhanden sein. Probier es noch einmal. Nun sollte dein Script keinen Fehler mehr melden.

Als nächstes erstellen wir einige Variablen, die wir im Laufe des Scripts benötigen. Unterhalb von den import-Befehlen fügen wir die folgenden Zeilen ein:

sensor_url = "https://api.stadtpuls.com/api/v3/sensors/<DEINE SENSOR ID>/records"
token = "<DEINEN TOKEN HIER EINFÜGEN>"
headers = {"authorization": "Bearer {}".format(token)}
json = {"measurements": [42]}

Du solltest hier deine eigene Sensor-URL und deinen Token einfügen.

(Bonus. Gehe auf die Seite jwt.io und füge deinen Token in das Feld "Encoded" ein. Damit kannst du sehen, welche Informationen in dieser Zeichenkette gespeichert sind.)

Die Variable headers ist für die HTTP POST Anfrage und transportiert deinen Token, damit dein Sensor die Daten erhält. Ohne diese würde die API deine Anfrage zurückweisen, weil du nicht authorisiert bist.

Die Variable json beinhaltet deine Daten. Wir geben hier einen Wert von 42 in das Array measurements ein. Die API erwartet diese Struktur und würde ein JSON, das anders benannt ist, zurückweisen.

Deine Sensor-URL kannst du in deinem Account auf der Seite deines Sensors finden. Du kannst die URL auch im Browser öffnen, um eine HTTP GET Anfrage zu stellen. Wenn dein Sensor noch keine Daten hat, solltest du so etwas sehen:

{"data":[]}

Damit sind die Vorbereitungen abgeschlossen. Nun folgt die eigentliche Anfrage mit der requests-Bibliothek. Füge die folgenden Zeilen an dein Script an.

try:
    response = requests.post(sensor_url, json=json, headers=headers)
    if response.status_code != 201:
        print("Fehler beim Senden der Daten: {}".format(response.status_code))
    else:
        print("Daten wurden erfolgreich gesendet")
except requests.exceptions.RequestException as error:
    print(error)

Wir starten diesen Block mit einem try und except Block. Dadurch können wir etwaige Fehler, die der Code innnerhalb des try Blocks werfen könnte, mit dem except Block auffangen. In diesem Fall fangen wir mit requests.exceptions.RequestException nur Fehler der requests Bibliothek auf. Syntaxfehler würden ebenfalls einen Fehler erzeugen, werden aber nicht mit unserem print Befehl gehandhabt. Die Zeile

response = requests.post(sensor_url, json=json, headers=headers)

ist der Kern unseres Scriptes. Das object requests macht eine HTTP POST Anfrage (requests.post) an die URL sensor_url mit den Header-Informationen headers und den Daten json. Das Ergebnis der Anfrage speichern wir in der Variable response und führen mit der Zeile

if response.status_code != 201:

einen Test aus, ob die Antwort der API etwas anderes als den HTTP Statuscode 201 hat. Wenn dies der Fall ist, wird eine Fehlermeldung in der folgenden Zeile mit dem print Befehl ausgegeben. Wenn der erwartetete Statuscode 201 von der API zurückgegeben wurde, geben wir eine Erfolgsmeldung aus.

Das Gesamte Python-Script

Hier siehst du nochmal das gesamte Python-Script.

import requests
import json

sensor_url = "https://api.stadtpuls.com/api/v3/sensors/<DEINE SENSOR ID>/records"
token = "<DEINEN TOKEN HIER EINFÜGEN>"
headers = {"authorization": "Bearer {}".format(token)}
json = {"measurements": [42]}

try:
    response = requests.post(sensor_url, json=json, headers=headers)
    if response.status_code != 201:
        print("Fehler beim Senden der Daten: {}".format(response.status_code))
    else:
        print("Daten wurden erfolgreich gesendet")
except requests.exceptions.RequestException as error:
    print(error)

Herzlichen Glückwunsch! Du hast dein erstes Stadtpuls Python-Script erstellt.

Daten senden mit Javascript

Javascript kann auf verschiedenste Weisen ausgeführt werden, mit Node.js, mit Replit.com, auf codesandbox.io, via GitHub Codespaces, auf JSBin und an vielen anderen Plätzen. Um die Einstiegshürde so gering wie möglich zu halten, empfehlen wir hier JSBin oder für Firefox-Nutzer:innen den Multi Line Editor der Web Console.

Voraussetzungen

Folgende Voraussetzungen sollten erfüllt sein:

Du hast einen Stadtpuls Account
Du hast einen Token erstellt und dir sicher gespeichert
Du hast bereits einen Sensor vom Type HTTP angelegt
Du hast entweder JSBin oder den FireFox Multi Line Editor *

* Brave, Safari, Chrome, Edge Benutzer:innen können mit SHIFT + ENTER direkt in der Console schreiben.

Javascript Schritt für Schritt

Um sicherzustellen, dass Firefox uns nicht mit Fehlern ärgert, die uns sagen, dass unsere const Variablen bereits definiert sind, kapseln wir unser gesamtes Script in einem Closure. Alle weiteren Befehlszeilen werden in die geschwungenen Klammern geschrieben.

{
  // Dein Code kommt hier rein
}

Als nächstes erstellen wir einige Variablen, die wir im Laufe unseres Scripts benötigen. Innerhalb unserer geschwungenen Klammern fügen wir folgende Zeilen ein:

const url = "https://api.stadtpuls.com/api/v3/sensors/<DEINE SENSOR ID>/records";
const token = "<DEIN TOKEN HIER EINFÜGEN>";
const headers = new Headers({
  authorization: `Bearer ${token}`,
  "content-type": "application/json",
});
const data = {
  measurements: [42],
};

Du solltest hier deine eigene Sensor-URL und deinen eigenen Token einfügen.

(Bonus. Gehe auf die Seite jwt.io und füge deinen Token in das Feld "Encoded" ein. Damit kannst du sehen, welche Informationen in dieser Zeichenkette gespeichert sind.)

Die Variable headers ist für die HTTP POST Anfrage und transportiert deinen Token damit dein Sensor die Daten erhält und den content-type der Anfrage, also was wir denn genau senden. In diesem Fall ist das application/json also JSON. Ohne diese Einträge würde die API deine Anfrage zurückweisen, weil du nicht authorisiert bist oder den falschen Datentyp sendest.

Die Variable data beinhaltet deine Daten. Wir geben hier einen Wert von 42 in das Array measurements ein. Die API erwartet diese Struktur und würde ein JSON, das anders benannt ist, zurückweisen.

Deine Sensor-URL kannst du in deinem Account auf der Seite deines Sensors finden. Du kannst die URL auch im Browser öffnen, um eine HTTP GET Anfrage zu stellen. Wenn dein Sensor noch keine Daten hat, solltest du so etwas sehen:

{"data":[]}

Damit sind die Vorbereitungen abgeschlossen.

Nun folgt die eigentliche Anfrage mit der browsereigenen Methode fetch. Füge die folgenden Zeilen an dein Script unterhalb deiner data Variable an.

fetch(url, {
  method: "POST",
  headers: headers,
  body: JSON.stringify(data),
})

Wir übergeben an die Methode fetch die url zu deinem Sensor und ein Objekt mit unserem headers und data. data wird mit der Methode JSON.stringify von einem Javascript Objekt in eine Zeichenkette umgewandelt und als body an fetch übergegeben. fetch gibt uns ein Promise zurück. Dieses Promise verarbeiten wir mit dem folgenden Befehl, den wir direkt an die schließenden Klammern von unserem fetch anhängen.

.then((response) => {
  if (!response.ok) {
    throw new Error("response not ok");
  }
  if (response.status !== 201) {
    throw new Error("status not 201");
  }
  return reponse.json();
})

Der Befehl .then erwartet eine Funktion, welche das Ergebnis des erfolgreich aufgelösten Promise von fetch übernimmt. Das Ergebnis wird als Argument an die Funktion gegeben. In unserem Fall nennen wir das Ergebnis response. Wir führen mit den Abfragen if (!response.ok)(if response not okay) und if (response.status !== 201) (if status code is not 201) zwei Tests durch, um sicher zu stellen, dass unsere Anfrage erfolgreich war. Wenn eine der beiden Bedingungen nicht erfüllt ist, wird ein Fehler ausgelöst. Wir könnten hier schon mit unserem Script fertig sein. Der Vollständigkeit halber verarbeiten wir jedoch die Informationen aus der Antwort. Mit den Befehlen return reponse.json(); geben wir ein weiteres Promise von der Methode .json() an die nächste .then Methode.

Dafür fügen wir an unser erste .then Methode ein weitere an.

.then((json) => {
  console.info(json);
})

Das Ergebnis der Methode .json() aus der vorherigen .then Methode wird wiederum als Argument an die Funktion gegeben. In unserem Fall wird das Ergebnis nur in der Konsole ausgegeben.

Zu guter letzt fügen wir eine andere Methode, genannt .catch, an.

.catch((error) => {
  console.error(error);
  });

Damit werden alle Error, die wir innnerhalb unserer .then Methoden werfen und auch Fehler, die die fetch Methode werfen könnte, "gefangen" und verarbeitet.

Das gesamte Javascript

Das gesamte Javascript siehst du nochmal hier.

{
  const url = "https://api.stadtpuls.com/api/v3/sensors/<DEINE SENSOR ID>/records";
  const token = "<DEIN TOKEN HIER EINFÜGEN>";
  const headers = new Headers({
    authorization: `Bearer ${token}`,
    "content-type": "application/json",
  });
  const data = {
    measurements: [42],
  };

  fetch(url, {
    method: "POST",
    headers: headers,
    body: JSON.stringify(data),
  })
    .then((response) => {
      if (!response.ok) {
        throw new Error("response not ok");
      }
      if (response.status !== 201) {
        throw new Error("status not 201");
      }
      return response.json();
    })
    .then((json) => {
      console.info(json);
    })
    .catch((error) => {
      console.error(error);
    });
}

Herzlichen Glückwunsch! Du hast dein erstes Stadtpuls Javascript erstellt.