https://d226lax1qjow5r.cloudfront.net/blog/blogposts/build-an-air-quality-reporting-service-with-messages-api/blog_air-quality-reporting_1200x600.png

Erstellen eines Berichtsdienstes zur Luftqualität mit Messages API

Zuletzt aktualisiert am December 2, 2020

Lesedauer: 12 Minuten

Haben Sie schon einmal darüber nachgedacht, Ihre bestehende Anwendung so zu erweitern, dass sie mit mehreren Kommunikationskanälen interagieren kann? Was wäre, wenn wir diese Idee nutzen könnten, um auf Themen wie Luftverschmutzung und Klimawandel aufmerksam zu machen?

Das Projekt World Air Quality Index ist ein gemeinnütziges Projekt, das 2007 ins Leben gerufen wurde. Ihre Aufgabe ist es, das Bewusstsein für Luftverschmutzung zu fördern und den Zugang zu weltweiten Luftqualitätsinformationen zu gewährleisten. Sie bieten REST-APIs an, um Zugang zu Daten von Wetter- und Luftqualitätsüberwachungsstationen auf der ganzen Welt zu erhalten. Sie können auch andere Datenquellen nutzen, um einen Dienst zu erstellen, der sich auf soziale Themen konzentriert!

In diesem Beispiel bauen wir einen Dienst auf, der von Node.js - einer JavaScript Runtime und der Vonage Messages APIbetrieben wird, der Informationen über die aktuelle Luftqualität an einem bestimmten Ort über WhatsApp und Facebook Messenger sendet.

Der Quellcode für das Beispiel, das wir erstellen werden, ist auch auf GitHub.

Vonage API-Konto

Um dieses Tutorial durchzuführen, benötigen Sie ein Vonage API-Konto. Wenn Sie noch keines haben, können Sie sich noch heute anmelden und mit einem kostenlosen Guthaben beginnen. Sobald Sie ein Konto haben, finden Sie Ihren API-Schlüssel und Ihr API-Geheimnis oben auf dem Vonage-API-Dashboard.

Einrichten der Entwicklungsumgebung

Wir müssen einen ngrok Tunnel für unsere Anwendung öffnen, um sie mit minimaler Konfiguration über das Internet zugänglich zu machen. Nach der Installation von ngroköffnen Sie ein Terminal und führen Sie ngrok http 3070 aus, um Ihren lokalen Port 3070 für das Internet freizugeben. Stellen Sie sicher, dass Sie dies mit der PORT Variable in .env. Kopieren Sie die HTTPS-URL, wie sie von ngrok in die Konsole und notieren Sie sie.

Screenshot of ngrok running in a terminal emulator

Nun ist es an der Zeit, die für die Anwendung erforderlichen Abhängigkeiten zu installieren. Führen Sie aus npm init -y zum Erstellen einer package.json Datei zu erstellen. Wir werden Express.js - ein beliebtes Webanwendungs-Framework für Node.js und Axios - eine HTTP-Client-Bibliothek für dieses Projekt - sowie Dotenv - ein Modul zur Verwaltung von Umgebungsvariablen - verwenden. Später werden wir auch Dedent und Commander.js einsetzen, um einige weitere Funktionen zu implementieren. Installieren Sie diese Module, indem Sie sie ausführen:

npm install --save express axios dotenv dedent commander

Da wir von Zeit zu Zeit Änderungen an unserem Quellcode vornehmen werden, können wir einige Tastenanschläge einsparen, indem wir Nodemon installieren, das kontinuierlich auf Änderungen achtet und die Anwendung automatisch neu startet. Installieren Sie es als eine Entwicklungsabhängigkeit, indem Sie

npm install -D nodemon

In diesem Tutorial ist unser Einstiegspunkt eine Datei namens lib/index.js. Ergänzen oder aktualisieren Sie die main und die script Schlüssel in package.json um die Anwendung mit nodemon auszuführen:

// package.json

{
  ...
  "main": "lib/index.js",
  ...
  "scripts": {
    "start": "node .",
    "dev": "nodemon .",
  },
  ...
}

Kopieren Sie den Inhalt von .env.example im Hauptverzeichnis in eine neue Datei namens .env. Sobald Sie im Vonage API Dashboard angemeldet sind, suchen Sie Ihren API-Schlüssel und Ihr API-Geheimnis und aktualisieren Sie die Werte in .env. Es gibt auch einige zusätzliche Variablen, die in den nächsten Abschnitten zugewiesen werden.

Empfangen einer eingehenden Nachricht über Messages API

Immer wenn Vonage eine eingehende Nachricht auf Ihrer virtuellen Telefonnummer oder über einen der anderen Kanäle empfängt, stellen die Vonage-Server eine HTTP-Anfrage an einen definierten Webhook-Endpunkt mit einer JSON-Nutzlast. Für dieses Tutorial legen wir fest, dass die /webhook/inbound Route in unserer Anwendung auf alle derartigen Anfragen wartet.

Um sicherzustellen, dass wir diese Anfrage erhalten, müssen wir die Sandbox-Umgebung konfigurieren, die Sie auf dem Vonage API Dashboard unter "Messages and Dispatch" finden. Setzen Sie den Webhook für eingehende Nachrichten (HTTP POST) auf <ngrok-https-url>/webhook/inbound und klicken Sie auf "Webhaken speichern".

Screenshot showing setting webhook

Verknüpfen Sie auf derselben Seite einen Test Account, von dem aus Sie Nachrichten senden möchten. Klicken Sie auf die Links "Zur Sandbox hinzufügen" in den WhatsApp- und Messenger-Kanälen. Scannen Sie dann den QR-Code auf Ihrem Telefon oder klicken Sie auf den angegebenen Link. In der Regel müssen Sie eine Passphrase an eine für die Sandbox eingerichtete Nummer oder Seite senden. Sobald Sie Ihr Testkonto verknüpft und den Webhook-Endpunkt festgelegt haben, können Sie fortfahren. Speichern Sie die auf dem Dashboard angegebene Sandbox-Telefonnummer in Ihrem Adressbuch, damit Sie leicht darauf zugreifen können.

Wir werden eine Express.js-Anwendung erstellen, die auf Port 3070 Die Mindestanforderungen sind die Annahme von HTTP POST-Anfragen auf dieser Route und das Senden eines Statuscodes von 200. In unserer Express.js-Anwendung kann auf diese Nutzlast über das req.body Objekt. Um einen Blick auf die Daten der Nutzlastanforderung zu werfen, führen Sie die Anwendung aus, indem Sie npm run dev.

// lib/index.js

require("dotenv").config();

const express = require("express");

const app = express();
const PORT = process.env.PORT || 3070;

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

app.post("/webhook/inbound", (req, res) => {
  console.log(req.body);
  res.status(200).end();
});

app.listen(PORT, () => console.log(`Listening on Port ${PORT}...`));

Versuchen Sie, eine Nachricht von WhatsApp an die Sandbox-Nummer zu senden, und beobachten Sie die Ausgabe in dem Terminalfenster, in dem Ihre Anwendung ausgeführt wird. Senden Sie eine weitere Nachricht von der Messenger-App an die Sandbox-Seite und beobachten Sie die Ausgabe erneut.

Screenshot showing request body for Webhook requests for different channels

Die im obigen Beispiel gezeigten Ausgaben zeigen, dass die verschiedenen Kanäle durch Validierung unterscheidbar sind req.body.from.type. Je nach Kanal kann die eingehende Nachricht entweder von einer Telefonnummer oder einer Seiten-/Kontokennung stammen. Auf die gesendete Nachricht kann über das req.body.message Objekt im Körper der Anfrage.

Setzen Sie den Wert von VONAGE_NUMBER auf die Rufnummer, die in req.body.to.number und VONAGE_PAGE_ID auf die Seiten-ID wie in req.body.to.id auf die entsprechenden Variablen in .env da wir die Sandbox verwenden. In der Praxis würde dies durch eine WhatsApp Business Account-Nummer und eine Facebook-Seiten-ID ersetzt werden, die mit einer Vonage-Anwendung verknüpft sind.

Senden einer Nachricht über Messages API

Bei Verwendung der Vonage Messages API wird eine Nachricht an einen Kanal gesendet, indem eine HTTP POST-Anforderung mit einem Nachrichtenobjekt an den API-Endpunkt gesendet wird. Bei Verwendung der Sandbox lautet der Endpunkt: https://messages-sandbox.nexmo.com/v0.1/messages.

Die Messages API-Referenzzeigt, dass die Anfrage einen Authorization Header mit dem Wert Basic base64(apiKey):base64(apiToken) oder Bearer jwtToken und ein Nachrichtenobjekt im Body der Anfrage enthalten. Um dies zu verwenden, aktualisieren Sie Ihre /lib/utils.js Datei mit dem unten stehenden Beispiel:

// lib/utils.js

require("dotenv").config();

const Axios = require("axios");

const sendMessage = async (message, body) => {
  await Axios.post(
    "https://messages-sandbox.nexmo.com/v0.1/messages",
    {
      from: {
        type: body.from.type,
        number: process.env.VONAGE_NUMBER
      },
      to: {
        type: body.from.type,
        number: body.from.number
      },
      message: {
        content: {
          type: "text",
          text: message
        }
      }
    },
    {
      auth: {
        username: process.env.VONAGE_API_KEY,
        password: process.env.VONAGE_API_SECRET
      }
    }
  );
};

module.exports = {
  sendMessage,
};

Die Hilfsfunktion sendMessage nimmt den Hauptteil der Nachricht entgegen und sendet ihn an die angegebene WhatsApp-Nummer. Das Nachrichtenobjekt kann dynamisch konstruiert werden, um mehrere Kanäle zu unterstützen; Sie können dies in einer anderen Hilfsfunktion implementieren.

Aktualisieren Sie Ihre /lib/index.js Datei, rufen Sie innerhalb der Webhook-Funktion die sendMessage mit der Nachricht auf, die Sie senden möchten, wie unten gezeigt:

// lib/index.js
...
const { sendMessage } = require("./utils");

app.post("/webhook/inbound", (req, res) => {
  sendMessage("Thanks for sending a message!", req.body);
  res.status(200).end();
});
...

Wir haben ein Skelett für einen Konversationsdienst erstellt, der die Messages API zum Senden und Empfangen von Nachrichten über WhatsApp und Messenger verwendet. Versuchen Sie, eine Nachricht an die Vonage Sandbox Number auf WhatsApp zu senden!

Abrufen von Daten aus den APIs des Weltluftqualitätsindex

Das World Air Quality Index Project bietet JSON-APIs für Luftqualitätsdaten in nahezu Echtzeit. Um Zugang zu den Daten zu erhalten, melden Sie sich für ein API-Token an. Wir erhalten einen Verifizierungslink an die E-Mail-Adresse, die wir auf dieser Seite angeben, der uns zu einer Seite mit dem API-Token weiterleitet. Setzen Sie den Wert von AQICN_TOKEN in .env auf das Token, das auf dieser Seite angezeigt wird.

Suchen Sie mit der WAQI Search API nach einer passenden Luftqualitätsmessstation für eine bestimmte Stadt. Die HTTP-GET-Anfrage an https://api.waqi.info/search/ hat zwei erforderliche Abfrageparameter - keyword der als Suchbegriff verwendet wird, um den Namen einer Station oder Stadt zu finden, und token der sich auf das WAQI-API-Token bezieht.

Wenn wir die Anfrage von Postman oder Insomnia aus stellen - beides beliebte GUI-Anwendungen zum Debuggen von HTTP-API-Anfragen -, können wir sehen, dass die Antwort für das Schlüsselwort london enthält. begrenzte Station-Metadaten für jedes Suchergebnis enthält.

// GET https://api.waqi.info/search/?token={{AQICN_TOKEN}}&keyword=london
{
  "status": "ok",
  "data": [
    {
      "uid": 5724,
      "aqi": "36",
      "time": {
        "tz": "+01:00",
        "stime": "2020-11-04 05:00:00",
        "vtime": 1604462400
      },
      "station": {
        "name": "London",
        "geo": [
          51.5073509,
          -0.1277583
        ],
        "url": "london"
      }
    },
    ...
  ]
}

Es ist an der Zeit, eine Hilfsfunktion für unsere Anwendung zu implementieren, um das oberste Ergebnis der Suchergebnisse zu erhalten und es zum Abrufen der erwarteten Daten zu verwenden.

// lib/utils.js
...
const getStation = async (keyword) => {
  const stationData = await Axios.get(
    "https://api.waqi.info/search/",
    {
    params: {
      token: process.env.AQICN_TOKEN,
      keyword
    }
  });
  if (stationData.data.data.length === 0) {
    return { error: "No Stations Found. Try Again." };
  }
  return stationData.data.data[0].station;
};
...

Um die Feed-Daten von der Station zu erhalten, stellen Sie eine weitere HTTP-GET-Anfrage, diesmal an die WAQI City/Station Feed API. Der Endpunkt für diese API lautet https://api.waqi.info/feed/<station-url>/ wobei station-url entspricht dem Wert des url Schlüssels in dem station Objekts, das von getStation. Das API-Token ist auch als Abfrageparameter erforderlich.

Die Anfrage für die Station, die für londonwird ein JSON-Objekt zurückgegeben, das Folgendes enthält Rohmessungen und detaillierte Metadaten der Stationenthält, wie unten gezeigt:

// GET https://api.waqi.info/feed/london/?token={{AQICN_TOKEN}}
{
  "status": "ok",
  "data": {
    "aqi": 36,
    "idx": 5724,
    "attributions": [
      {
        "url": "http://uk-air.defra.gov.uk/",
        "name": "UK-AIR, air quality information resource - Defra, UK",
        "logo": "UK-Department-for-environment-food-and-rural-affairs.png"
      },
      {
        "url": "https://londonair.org.uk/",
        "name": "London Air Quality Network - Environmental Research Group, King's College London",
        "logo": "UK-London-Kings-College.png"
      },
      {
        "url": "https://waqi.info/",
        "name": "World Air Quality Index Project"
      }
    ],
    "city": {
      "geo": [51.5073509, -0.1277583],
      "name": "London",
      "url": "https://aqicn.org/city/london"
    },
    "dominentpol": "pm25",
    "iaqi": {
      "co": { "v": 7.4 },
      "h": { "v": 92 },
      "no2": { "v": 23.3 },
      "o3": { "v": 2.9 },
      "p": { "v": 1029.4 },
      "pm10": { "v": 16 },
      "pm25": { "v": 36 },
      "so2": { "v": 3.4 },
      "t": { "v": 3.8 },
      "w": { "v": 3.7 }
    },
    "time": {
      "s": "2020-11-04 05:00:00",
      "tz": "+00:00",
      "v": 1604466000,
      "iso": "2020-11-04T05:00:00Z"
    },
    "forecast": {},
    "debug": { "sync": "2020-11-04T14:41:04+09:00" }
  }
}

Implementieren Sie eine weitere Hilfsfunktion für diese Anfrage. Diese Funktion nimmt das station Objekt als Parameter, das von getStationabgefragt wird, und fragt die API nach den Daten der Station ab. Aktualisieren Sie lib/utils.js durch Hinzufügen der folgenden getStationData Funktion:

// lib/utils.js
...
const getStationData = async (station) => {
  const aqiData = await Axios.get(
    `https://api.waqi.info/feed/${station.url}/`,
    {
      params: {
        token: process.env.AQICN_TOKEN
      }
    }
  );
  if (aqiData.data.data.status === "error") {
    return { error: "Could not get data. Try Again." };
  }
  return aqiData.data.data;
};
...

Wir können nun unsere Dienstprogramme verwenden, um die WAQI-API beim Empfang einer Nachricht auf einem von der Vonage Messages API unterstützten Kanal abzufragen und nach der Verarbeitung dieser Daten eine aussagekräftige Antwort zurückzusenden.

Antworten Sie mit sachdienlichen Informationen

Die Daten, die wir von den WAQI-APIs erhalten, müssen verarbeitet und "lesbar" gemacht werden. Wir können zwei verschiedene Vorlagen für die Berichterstattung über die Daten verwenden - eine für einen kurzen Bericht, der den Luftqualitätsindex und die gesundheitlichen Auswirkungen gemäß der US-EPA-Skala 2016 enthält, und eine weitere für einen detaillierten Bericht, der die Schadstoffwerte und Wetterinformationen zusammen mit den jeweiligen Maßeinheiten enthält.

AQI Air Pollution Level Health Implications Cautionary Statement (for PM 2.5)
0-50 Good Air quality is considered satisfactory, and air pollution poses little or no risk. None.
51-100 Moderate Air quality is acceptable; however, for some pollutants there may be a moderate health concern for a very small number of people who are unusually sensitive to air pollution. Active children and adults, and people with respiratory disease, such as asthma, should limit prolonged outdoor exertion.
101-150 Unhealthy for Sensitive Groups Members of sensitive groups may experience health effects. The general public is not likely to be affected. Active children and adults, and people with respiratory disease, such as asthma, should limit prolonged outdoor exertion.
151-200 Unhealthy Everyone may begin to experience health effects; members of sensitive groups may experience more serious health effects. Active children and adults, and people with respiratory disease, such as asthma, should avoid prolonged outdoor exertion; everyone else, especially children, should limit prolonged outdoor exertion.
201-300 Very Unhealthy Health warnings of emergency conditions. The entire population is more likely to be affected. Active children and adults, and people with respiratory disease, such as asthma, should avoid all outdoor exertion; everyone else, especially children, should limit outdoor exertion.
300+ Hazardous Health alert: everyone may experience more serious health effects. Everyone should avoid all outdoor exertion.

Quelle: AQI-Grundlagen, AirNow

Wir müssen auch die Namen der Schadstoffe und der verschiedenen Wettermessgrößen aus den kryptischen Abkürzungen herausfinden. Wir können die WAQI-API-Referenz konsultieren und Hilfsfunktionen für diese Aufgabe implementieren. Wir können auch zusätzliche Hilfsfunktionen definieren, in denen wir String-Interpolationsmethoden verwenden können und optional Nachrichten für WhatsApp formatieren. Die Implementierung dieser Hilfsfunktionen ist im Quellcode auf GitHub zu finden.

Dedent ist ein nützliches Modul für den Umgang mit mehrzeiligen ES6-JavaScript-Schablonenliteralen. Sie werden feststellen, dass es im Quellcode häufig verwendet wird, um Leerzeichen für eine bessere Lesbarkeit zu erhalten.

Eingehende Nachrichten mit Commander.js analysieren

Es ist nützlich, Nachrichten, die explizit für den Dienst bestimmt sind, zu analysieren und für verschiedene Befehle unterschiedliche Aktionen durchzuführen. Der Commander.js Bibliothek, die ursprünglich für Befehlszeilenanwendungen entwickelt wurde, kann verwendet werden, um die eingehende Nachricht nach Befehlen und Argumenten zu analysieren.

// lib/index.js
...
const { Command } = require("commander");

const trigger = new Command("vonage-aqi");

// override default cli behaviour
trigger.exitOverride();
trigger.addHelpCommand(false);

trigger
  .command("aqi <searchterm...>")
  .alias("a")
  .action(async (searchterm) => {
    searchterm = searchterm.join(" ");
    // fetch and send the brief report
  });

trigger
  .command("info <searchterm...>")
  .alias("i")
  .action(async (searchterm) => {
    searchterm = searchterm.join(" ");
    // fetch and send the detailed report
  });

trigger
  .command("act")
  .action(async () => {
   // send links to resources and information
});

trigger
  .command("help")
  .alias("h")
  .action(async () => {
    // send help and usage information
  });

...

app.post("/webhook/inbound", async (req, res) => {
  try {
    // pass the incoming message text to Commander.js
    trigger.parse(
      req.body.message.content.text
        .trim().toLowerCase().split(" "),
      {
        from: "user"
      }
    );
  } catch (err) {
    // send message based on the type of error
  } finally {
    res.status(200).end();
  }
});
...

Die Commander.js-Bibliothek unterstützt erforderliche und optionale Argumente, variable Argumente und Befehlsaliase und macht die Aufgabe viel einfacher als die manuelle Überprüfung der Befehle und Argumente.

Sicherstellung der Zustellung mit dem Status-Webhook

Wir können eine neue Route einrichten, um auf die Ereignisse zu achten, die nach dem Senden einer Nachricht unter /webhook/status. Stellen Sie sicher, dass Sie dies an den ngrok Tunnel anhängen und ihn als Status-Webhook im Vonage API Dashboard speichern und auf "Webhooks speichern" klicken.

// lib/index.js
...
app.post("/webhook/status", (req, res) => {
  console.log(req.body);
  res.status(200).end();
});
...

Wenn unser Dienst das nächste Mal eine Nachricht erhält und darauf antwortet, beobachten wir verschiedene Zustände der gesendeten Nachricht. Das Feld req.body.status Feld enthält den Status, in den das Nachrichtenobjekt übergegangen ist, als die Webhook-Anforderung gesendet wurde. Wenn die Nachricht von den Vonage-Servern empfangen wird, befindet sich das Objekt im submitted Zustand. Wenn die Zustellung tatsächlich erfolgreich war, sollten wir einen Statuswert erhalten, der wahrscheinlich lautet delivered gefolgt von read.

Wenn ein Fehler aufgetreten ist, könnte der Status lauten rejected oder undeliverable sein und wir könnten diesen Fall theoretisch separat behandeln. Beachten Sie, dass Vonage einen großen Teil der Arbeit übernimmt, indem es in regelmäßigen Abständen erneut versucht, die Nachricht zuzustellen, falls dies fehlgeschlagen ist.

WhatsApp und Messenger Playground

Stellen Sie sicher, dass die Anwendung läuft und der richtige ngrok Tunnel in der Sandbox für Nachrichten gespeichert ist. Nehmen Sie Ihr Telefon ab und senden Sie Nachrichten an die Sandbox-Konten. Ist es nicht ein gutes Gefühl, wenn das Ding tatsächlich funktioniert?

WhatsApp

Screenshot showing a conversation with the service on WhatsApp

Bote

Screenshot showing a conversation with the service on Messenger

Einpacken

Dieses Projekt zeigt, wie flexibel die Vonage-APIs bei der Integration mit nahezu jeder Anwendung sind. Wir haben die Multi-Channel-Kommunikation mit WhatsApp und Messenger behandelt und die WAQI-APIs für dieses Beispiel verwendet. Ich bin gespannt, was Sie nach der Lektüre dieses Artikels entwickeln werden!

Weitere Lektüre

Sie finden den in diesem Tutorial gezeigten Code und den vollständigen Quellcode der funktionierenden Anwendung auf dem GitHub-Repository.

Sehen Sie sich die entsprechende Dokumentation für die Messages API auf Vonage API-Entwickler und Vonage API-Referenz. Erfahren Sie mehr darüber, wie die Kommunikation mit WhatsApp und Messenger auf Vonage API Developer funktioniert.

Falls Sie noch keinen Account bei Vonage haben, melden Sie sich noch heute für eines an für ein kostenloses Guthaben und nutzen Sie Vonage APIs in Ihrem nächsten Projekt! Erreichen Sie uns auf Twitter oder treten Sie dem Slack-Kanal der Gemeinschaft. Lassen Sie uns wissen, was Sie mit den Vonage APIs entwickeln wollen!

Teilen Sie:

https://a.storyblok.com/f/270183/250x250/a84175ca37/sudipto-ghosh.png
Sudipto Ghosh

Sudipto is an undergraduate student at the University of Delhi with a background in Computer Science and Mathematics. He is always excited and curious to know how things work and how they are built. He has experience in building applications with JavaScript, TypeScript, Python and Java with research interests in distributed computing and recommender systems.