Corona-Ampel

CoVid Ampel

Aktuell kann man für das Bundesland Bayern anhand einer einfachen Ampel die notwendigen Maßnahmen gegen die Corona-Pandemie ablesen. Da diese Daten auch als API zur Verfügung stehen, ist die Umsetzung mit einem internetfähigen Mikrocontroller, wie dem ESP32, recht einfach.

Verwendete Bauteile

Datenverarbeitung

Über die freie API von corona-ampel-bayern.de können die wichtigsten Daten ausgelesen und weiterverarbeitet werden.
URL: https://corona-ampel-bayern.de/data/data.json

Das Resultat ist ein JSON-String, der folgendermaßen aufgebaut ist:

{
    "hospitalizationLast7Days": 366,
    "hospitalizationLast7DaysIncidence": 2.8,
    "currentIntensiveCarePatients": 282,
    "lastSync": "2021-10-21T07:30:01.850Z",
    "lastUpdate": "2021-10-21T07:00:02.708Z"
}

Aufbau

Der folgende Schaltplan zeigt einen sehr simplen Aufbau, denn es sind außer dem ESP32 nur drei verschiedenfarbige LEDs (inkl. Vorwiderstand) notwendig.

Aufbau der Schaltung

Anstatt der einzelnen LEDs kann auch ein sog. LED traffic light module verwendet werden, auf dem in einer kleinen Platine schon die richtigen LEDs inkl. Vorwiderstände verbaut sind.

LED traffic light module
Abb.: LED traffic light module
LED traffic light module mit Vorwiderstand
Abb.: LED traffic light module mit verbautem Vorwiderstand

Vorsicht: Einige dieser LED-Ampel-Module haben keine oder 0Ω Widerstände!
Hier sollten separate Vorwiderstände benutzt werden.

Sketch

Der folgende Sketch verbindet sich alle 60 Minuten mit dem eingestellten, lokalen WLAN und ruft die aktuellen Werte der API ab.
Zum Parsen der von der API gelieferten Daten wird hier die Library ArduinoJson verwendet, die es einfach macht, die benötigten Werte auszulesen.

#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>

// Replace with your WiFI credentials
const char *WIFI_SSID     = "**********";
const char *WIFI_PASSWORD = "**********";
const char *DATA_URL      = "https://corona-ampel-bayern.de/data/data.json";

#define LED_PIN_RED     13
#define LED_PIN_YELLOW  12
#define LED_PIN_GREEN   14

#define CHECK_INTERVAL                60  // in minutes
#define MAX_INTENSIVE_CARE_PATIENTS  600
#define MAX_HOSPITALIZATION         1200

#define DEBUG true
#ifdef DEBUG
    #define DEBUG_INIT() Serial.begin(9600)
    #define DEBUG_PRINT(val) Serial.print(val)
    #define DEBUG_PRINTLN(val) Serial.println(val)
#else
    #define DEBUG_INIT()
    #define DEBUG_PRINT(val)
    #define DEBUG_PRINTLN(val)
#endif

#define lmillis() ((long)millis())

HTTPClient httpClient;
StaticJsonDocument<1000> jsonDoc;
long nextUpdate = 0;

void setup()
{
    DEBUG_INIT();
    pinMode(LED_PIN_RED, OUTPUT);
    pinMode(LED_PIN_YELLOW, OUTPUT);
    pinMode(LED_PIN_GREEN, OUTPUT);

    for (byte i = 0; i < 30; i++) {
        resetLeds();
        digitalWrite(12 + i % 3, HIGH);
        delay(50);
    }
    resetLeds();

    nextUpdate = lmillis() + 1000;
}

void loop()
{
    if (lmillis() - nextUpdate >= 0) {
        nextUpdate = lmillis() + CHECK_INTERVAL * 60 * 1000;
        updateCovLights();
    }
}

void updateCovLights()
{
    static bool hasError = false;
    connectWifi();

    DEBUG_PRINT("Requesting data...");
    httpClient.begin(DATA_URL);

    int httpCode = httpClient.GET();
    if (httpCode == 200) {
        DEBUG_PRINTLN("[ok]");
        String payload = httpClient.getString();

        DeserializationError jsonError = deserializeJson(jsonDoc, payload);
        if (jsonError) {
            DEBUG_PRINT("deserializeJson() failed: ");
            DEBUG_PRINTLN(jsonError.c_str());
            hasError = true;
        } else {
            int hospitalizationLast7Days = jsonDoc["hospitalizationLast7Days"];
            int currentIntensiveCarePatients = jsonDoc["currentIntensiveCarePatients"];
            DEBUG_PRINTLN("hospitalizationLast7Days     = " + String(hospitalizationLast7Days));
            DEBUG_PRINTLN("currentIntensiveCarePatients = " + String(currentIntensiveCarePatients));

            resetLeds();
            if (currentIntensiveCarePatients > MAX_INTENSIVE_CARE_PATIENTS) {
                digitalWrite(LED_PIN_RED, HIGH);
            } else if (hospitalizationLast7Days > MAX_HOSPITALIZATION) {
                digitalWrite(LED_PIN_YELLOW, HIGH);
            } else {
                digitalWrite(LED_PIN_GREEN, HIGH);
            }
        }
    } else {
        DEBUG_PRINTLN("ERROR: " + String(httpCode));
        hasError = true;
    }

    httpClient.end();
    disconnectWifi();

    if (hasError) {
        resetLeds();
        for (byte i = 0; i < 20; i++) {
            digitalWrite(LED_PIN_YELLOW, !digitalRead(LED_PIN_YELLOW));
            delay(500);
        }
        resetLeds();
    }
}

void connectWifi()
{
    DEBUG_PRINT("Connecting to WiFi.");
    WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        DEBUG_PRINT(".");
    }
    DEBUG_PRINTLN("[ok]");
}

void disconnectWifi()
{
    DEBUG_PRINT("Disconnecting WiFi...");
    WiFi.disconnect();
    while (WiFi.status() == WL_CONNECTED) {
        delay(500);
        DEBUG_PRINT(".");
    }
    DEBUG_PRINTLN("[ok]");
}

void resetLeds()
{
    digitalWrite(LED_PIN_RED, LOW);
    digitalWrite(LED_PIN_YELLOW, LOW);
    digitalWrite(LED_PIN_GREEN, LOW);
}

Nach dem Kompilieren und Ausführen des Sketches sollten auf der seriellen Konsole die folgenden Debug-Ausgaben erscheinen und nach einigen Sekunden schaltet die Ampel auf die aktuelle Phase.

Ausgabe auf der seriellen Konsole der Arduino-IDE
Abb.: Ausgabe auf der seriellen Konsole der Arduino-IDE
Fertige CoVid-Ampel auf dem Breadboard
Abb.: Fertige CoVid-Ampel auf dem Breadboard (zeigt grün...😷)

Für den Betrieb kann der Debug-Modul abgeschaltet werden, indem folgende Zeile geändert wird:
#define DEBUG false

Bedingungen

Damit die Ampel auf eine bestimmte Phase schaltet sind folgende Bedingungen festgelegt worden.
(Angaben ohne Gewähr; Quelle: corona-ampel-bayern.de)

GRÜN Die Werte für die gelbe und die rote Phase sind nicht erreicht.
GELB Es wurden in einer Woche mehr als 1.200 neue COVID-19 Patienten in bayerischen Krankenhäusern aufgenommen.
ROT Es werden aktuell mehr als 600 COVID-19 Patienten auf Intensivstationen in Bayern versorgt.

Je nachdem welche Farbe die Ampel anzeigt sind bestimmte Vorgaben zu erfüllen und Maßnahmen zu ergreifen.
(siehe: corona-ampel-bayern.de)

zurück