Das Wetter mit Serverless und Farben anzeigen

Avatar of Burke Holland
Burke Holland am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Ich gehe gerne joggen. Manchmal ist es draußen kalt. Manchmal ist es draußen kalt, aber es sieht nicht so aus. Die Sonne scheint, die Vögel zwitschern. Dann tritt man in Shorts und T-Shirt nach draußen und merkt, dass man etwa 2 Minuten hat, bevor die Erfrierungen einsetzen.

Ich habe beschlossen, dieses Problem der ersten Welt mit einer Glühbirne zu lösen, die je nach Außentemperatur eine bestimmte Farbe anzeigt. Es funktioniert besser als erwartet, und das will etwas heißen, denn normalerweise funktioniert nichts so, wie ich es will.

Das war ein tolles Projekt, und da es sich im Wesentlichen um einen gehosteten Dienst handelt, der auf einem Timer läuft, ist es ein perfekter Anwendungsfall für Serverless.

Jetzt denkst du vielleicht: „Ähm, wäre es nicht einfacher, einfach das Wetter zu überprüfen?“ Nun ja, wäre es, aber dann hätte ich keinen Vorwand, eine teure Glühbirne zu kaufen oder einen Artikel mit dem Wort „Serverless“ zu schreiben.

Schauen wir uns also an, wie du deine eigene Wetter-Glühbirne bauen kannst. Der endgültige Code ist nicht kompliziert, aber er enthält einige interessante Teile, die es wert sind, beachtet zu werden. Übrigens, habe ich erwähnt, dass es Serverless ist?

Die Wetter-Glühbirne bauen

Das Erste, was du brauchen wirst, ist die Glühbirne. Du kannst keine Wetter-Glühbirne ohne Glühbirne haben. Sag das Wort „Glühbirne“ etwa 10 Mal laut und du wirst merken, was für ein seltsames Wort es ist. Glühbirne, Glühbirne, Glühbirne, Glühbirne – siehst du? Seltsam.

Ich benutze die LIFX Mini Color. Sie ist nicht *zu* teuer, aber was noch wichtiger ist, sie hat eine offene API.

Die API hat zwei Authentifizierungsmethoden. Die erste enthält das Wort „OAuth“ und es tut mir jetzt schon leid, dass du das lesen musstest. Keine Sorge, es gibt einen einfacheren Weg, der nicht OAu… das, was nicht genannt werden darf, beinhaltet.

Der zweite Weg ist die Registrierung einer Anwendung bei LIFX. Du erhältst einen Schlüssel zurück und alles, was du tun musst, ist, diesen Schlüssel bei jeder HTTP-Anfrage mitzusenden. Das ist es, was ich für diese Demo verwende.

Wenn wir zum Beispiel die Glühbirne blau färben wollten, können wir einfach color: blue an den /state Endpunkt übergeben.

Die API unterstützt einige verschiedene Farbformate, darunter benannte Farben (wie rot, blau), Hex-Werte, RGB, Kelvin, Farbton, Helligkeit und Sättigung. Das ist wichtig, denn es spielt eine Rolle bei dem, was sich als der schwierigste Teil dieses Projekts herausstellte: die Umwandlung von Temperatur in Farbe.

Temperatur mit Farbe darstellen

Wenn du jemals eine Wettervorhersage gesehen hast, wirst du mit der Art und Weise vertraut sein, wie die Meteorologie Wetterbedingungen auf einer Karte mit Farbe darstellt.

Normalerweise geschieht dies zur Visualisierung von Niederschlägen. Du hast wahrscheinlich diesen bedrohlichen grünen Streifen von Stürmen gesehen, der sich auf einer Wetterkarte auf dich zubewegt, während du versuchst herauszufinden, ob du dich in die Badewanne setzen solltest, weil du im Weg eines Tornados bist. Oder vielleicht sind das nur wir alle unglücklichen Seelen hier in Amerikas Tornado Alley.

Farbe wird auch zur Darstellung der Temperatur verwendet. Das ist genau das, was ich mit der Glühbirne machen wollte. Das Schwierige ist, dass es keine standardisierte Methode zu geben scheint, dies zu tun. Einige Karten zeigen es als Vollfarben in Bändern. In diesem Fall könnte Blau das Band von 0℉ – 32℉ darstellen.

Andere verwenden eine Gradientenskala, die präziser ist. Das war es, was ich für die Wetter-Glühbirne wollte.

Mein erster Versuch, dies zu lösen, war, einfach nach „Temperaturfarbskala“ und anderen Variationen dieses Suchbegriffs zu googeln. Ich bekam viele Informationen über Kelvin zurück.

Kelvin ist eine Darstellung der Farbtemperatur. Buchstäblich. Bei jeder Lichtquelle (Glühbirne, Sonne, usw.) wirkt sich die tatsächliche Temperatur dieser Quelle auf die Farbe des von ihr emittierten Lichts aus. Ein Feuer brennt gelblich-rot. Je heißer dieses Feuer wird, desto mehr bewegt es sich in Richtung Weiß. Daher die Redewendung „weißglühend“. Wenn also jemand „rotglühend“ sagt, kannst du ihn vor allen korrigieren, denn wer liebt keinen besserwisserischen Idioten?

Die LIFX-Glühbirne unterstützt Kelvin, also denkst du vielleicht, dass das funktionieren würde. Schließlich ist das die Kelvin-Skala….

Das Problem ist, dass es einfach nicht genug Farbvariation gibt, denn das sind keine tatsächlichen Farben, sondern eher der Farbstich, den ein Licht aufgrund seiner „Temperatur“ abgibt. Hier ist das Kelvin-Farbrad, das mit der LIFX-App geliefert wird.

Diese Farben sind auf der Glühbirne kaum voneinander zu unterscheiden. Nicht ganz das, was ich wollte.

Das lässt mir nur noch den Versuch, die Farbe in Hex, RGB oder ein anderes Format umzuwandeln. Das ist schwierig, denn wo fängst du an? Ich habe eine peinliche Menge Zeit damit verbracht, RGB-Skalawerte zwischen Blau für kalt (0, 0, 255) und Rot für heiß (255, 0, 0) einzustellen. Ungefähr zu dieser Zeit dämmerte es mir, dass HSL vielleicht ein besserer Weg wäre. Warum? Weil der **Farbton** viel einfacher zu verstehen ist.

Farbton

Farbton ist eine Darstellung von Farbe auf einer Skala zwischen 0 und 360. Deshalb sehen wir Farbe oft als Rad dargestellt (360°). Das ist eine starke Vereinfachung, aber wenn du nicht möchtest, dass ich über Wellenlängen spreche, bleiben wir bei dieser Definition.

Das Farbton-Farbrad sieht so aus….

Wenn wir es abflachen, ist es einfacher zu verstehen.

Wir sind bereit, Temperatur in Farbe umzuwandeln. Das Erste, was wir tun müssen, ist, einen festgelegten Temperaturbereich zu ermitteln. Ich habe mich für 0℉ bis 100℉ entschieden. Wir können nicht mit unendlichen Temperatur-Farbkombinationen arbeiten. Zahlen gehen endlos, Farben nicht. Es kann nur so heiß werden, bevor unsere Glühbirne ständig hellrot leuchtet, und das sind 100℉. Dasselbe gilt für Kälte.

Wenn Hellblau 0℉ darstellt, kann ich bei etwa der 200er Marke auf der Farbtonskala beginnen. Rot wird 100℉ darstellen. Du siehst, dass Rot an beiden Extremen liegt, also kann ich entweder nach links ODER nach rechts gehen, je nachdem, welche Farben ich zur Darstellung der Temperatur verwenden möchte. Es ist nicht dasselbe wie die Farben, die in echten Wetterprogrammen verwendet werden, aber wen kümmert's? Offensichtlich nicht mich.

Ich habe mich für rechts entschieden, weil es links kein Pink gibt und Pink meine Lieblingsfarbe ist. Außerdem hatte ich das Gefühl, dass Pink Wärme besser darstellt als Grün. Grün bedeutet Regen und Tornados.

Jetzt können wir einen Farbton basierend auf der Temperatur zurückrechnen. Bereit? Los geht's.

Nehmen wir an, es ist draußen kühle 50℉.

Wenn 100℉ das Heißeste ist, das wir betrachten (360), und 0℉ das Kälteste (200), dann haben wir eine Farbskala von 160 Punkten. Um herauszufinden, wo wir uns in diesem 160-Punkte-Bereich befinden müssen, können wir die aktuelle Temperatur durch die Obergrenze von 100℉ teilen, was uns den genauen Prozentsatz ergibt, den wir uns in unserem Bereich bewegen müssen, oder 50%. Wenn wir uns zu 50 % in einen 160-Punkte-Bereich bewegen, bleiben wir bei 80. Da wir bei 200 beginnen, ergibt sich ein Farbton von 280.

Das klingt kompliziert, aber nur weil Textaufgaben in Mathematik **SCHEIßE** sind. Hier ist, wie der Code aussieht, wenn alles fertig ist…

let hue = 200 + (160 * ( temperature / 100 ));

OK! Wir haben eine dynamische Farbskala basierend auf dem Farbton, und was soll ich sagen, wir können den Farbton genauso einfach an LIFX übergeben wie eine benannte Farbe.

Jetzt müssen wir nur noch die aktuelle Temperatur herausfinden, einen Farbton zurückrechnen und das alle paar Minuten tun. Serverless, wir kommen!

Serverless Timer-Funktionen

Serverless ist in aller Munde. Es ist wie HTML5 früher: Es ist egal, was es ist, wichtig ist nur, dass du das Wort kennst und keine Angst hast, es in einem Blogbeitrag zu verwenden.

Für dieses Beispiel verwenden wir Azure Functions, da es Unterstützung für Timer-Trigger gibt und wir diese Timer-Trigger lokal testen können, bevor wir mit VS Code bereitstellen. Eines der Dinge an Serverless, die mich unendlich ärgern, ist, wenn ich es nicht lokal debuggen kann.

Mit den Azure Functions Core Tools und der Azure Functions Extension für VS Code kann ich ein neues Serverless-Projekt erstellen und einen Timer-Trigger auswählen.

Timer-Trigger in Azure Functions werden als Cron Expressions spezifiziert. Keine Sorge, ich wusste auch nicht, was das ist.

Cron Expressions ermöglichen es dir, sehr spezifisch mit der Intervalldefinition zu werden. Cron teilt Dinge in Sekunde, Minute, Stunde, Tag, Monat, Jahr auf. Wenn du also etwas jede Sekunde jeder Minute jeder Stunde jedes Tages jedes Jahres ausführen wolltest, sähe dein Ausdruck so aus…

* * * * * *

Wenn du es jeden Tag um 10:15 Uhr ausführen wollen würdest, sähe es so aus…

* 15 10 * * *

Wenn du es alle 5 Minuten ausführen wollen würdest (was Azure standardmäßig tut), gibst du das an, indem du sagst „wenn die Minuten durch 5 teilbar sind“.

0 */5 * * * *

Für die Zwecke dieser Funktion haben wir es auf 2 Minuten eingestellt.

Ich verwende ein Intervall von 2 Minuten, weil das die Häufigkeit ist, mit der wir die Wetter-API kostenlos aufrufen können 💰.

Die Vorhersage von DarkSky abrufen

DarkSky hat eine wunderbare Wetter-API, die du bis zu 1.000 Mal pro Tag kostenlos aufrufen kannst. Wenn es 1.440 Minuten pro Tag gibt (und das ist der Fall), bedeutet das, dass wir DarkSky alle 1,44 Minuten pro Tag aufrufen können und im kostenlosen Bereich bleiben. Ich habe einfach auf 2 Minuten aufgerundet, da sich die Temperatur nicht so schnell ändert.

So sieht unsere Funktion aus, wenn wir die DarkSky-API aufrufen. Alle meine Tokens, Schlüssel und Längen- und Breitengrad-Einstellungen befinden sich in Umgebungsvariablen, damit sie nicht fest codiert sind. Diese werden in der Datei local.settings.json gesetzt. Ich habe axios für meine HTTP-Anfragen verwendet, weil es ein magisches, magisches Paket ist.

const axios = require('axios');

module.exports = function (context, myTimer) {
  // build up the DarkSky endpoint
  let endpoint = `${process.env.DS_API}/${process.env.DS_SECRET}/${process.env.LAT}, 
                  ${process.env.LNG}`;
  
  // use axios to call DarkSky for weather
  axios
    .get(endpoint)
    .then(response => {
      let temp = Math.round(response.data.currently.temperature);
    
      // TODO: Set the color of the LIFX bulb
    })
    .catch(err => {
      context.log(err.message);
    });
};

Nachdem ich jetzt die Temperatur habe, muss ich die LIFX-API aufrufen. Und was soll ich sagen, jemand hat bereits ein npm-Paket dafür erstellt, das lifx-http-api heißt. Deshalb liebst du JavaScript.

Den Farbton der Glühbirne einstellen

Nachdem das Wetterergebnis zurückkommt, muss ich die LIFX API-Instanz verwenden und die Methode setState aufrufen. Diese Methode gibt ein Promise zurück, was bedeutet, dass wir Promises verschachteln müssen. Das Verschachteln von Promises kann außer Kontrolle geraten und uns direkt in Callback-Hölle zurückwerfen, was wir ja mit Promises vermeiden wollen.

Stattdessen werden wir das erste Promise behandeln und dann Promise.all zurückgeben, das wir auf einer anderen Top-Level-then-Ebene behandeln können. Das verhindert einfach, dass wir then-Anweisungen verschachteln.

Denkt daran, Kinder, Promises sind nur sozial akzeptable Callbacks.

const axios = require('axios');
const LIFX = require('lifx-http-api');

let client = new LIFX({
  bearerToken: process.env.LIFX_TOKEN
});

module.exports = function (context, myTimer) {
  // build up the DarkSky endpoint
  let endpoint = <code>${process.env.DS_API}/${process.env.DS_SECRET}/${
    process.env.LAT
    },${process.env.LNG}<code>;
    
  // use axios to call DarkSky for weather
  axios
    .get(endpoint)
    .then(response => {
      let temp = Math.round(response.data.currently.temperature);
      
      // make sure the temp isn't above 100 because that's as high as we can go
      temp = temp < 100 ? temp : 100;
      
      // determine the hue
      let hue = 200 + (160 * (temp / 100));

      // return Promise.all so we can resolve at the top level
      return Promise.all([
        data,
        client.setState('all', { color: <code>hue:${hue}<code> })
      ]);
    })
    .then(result => {
      // result[0] contains the darksky result
      // result[1] contains the LIFX result
      context.log(result[1]);
    })
    .catch(err => {
      context.log(err.message);
    });
};

Jetzt können wir das Ding lokal ausführen und zusehen, wie unser Timer seine Sache macht.

Das ist es! Lasst es uns bereitstellen.

Die Wetter-Glühbirne bereitstellen

Ich kann über die VS Code-Erweiterung ein neues Functions-Projekt erstellen.

Ich kann mit der rechten Maustaste darauf klicken, um es „Im Portal öffnen“, wo ich eine Bereitstellungsquelle definieren kann, damit mein Code von Github bezogen und bereitgestellt wird. Das ist ideal, denn so wird meine Anwendung automatisch neu bereitgestellt, wann immer ich eine Änderung nach Github pushe.

Lang lebe die Wetter-Glühbirne

Lehne dich jetzt zurück und bestaune den sanften Schein der Wetter-Glühbirne! Warum die tatsächliche Temperatur anschauen, wenn du stattdessen diesen wunderschönen Hot-Pink-Ton betrachten kannst?

Kannst du erraten, wie die Temperatur ist, basierend auf dem, was du aus diesem Artikel weißt? Die Person, die einen Kommentar hinterlässt und am nächsten dran ist, erhält von mir eine kostenlose LIFX-Glühbirne (weil ich euch alle ❤️), oder die Kosten der Glühbirne, wenn du außerhalb der USA bist (~40 $).

Du kannst den gesamten Code für dieses Projekt von Github herunterladen.