Probleme mit JSON Abruf beim Tankerkoenig

Hallo Forum,
ich bin noch recht blutiger Anfänger im coden, deshalb hab ich die Hoffnung hier Unterstützung zu finden.

Hatte mir letztens hier im Forum den Tread Spritpreis auf dem ESP32 den Code probiert, da der damalige Code aus Zeigt her eure geilen Projekte auf meinem ESP8266 nicht laufen wollte (http statt https usw).

Ansich hab ich den Code nun recht gut für mich angepasst, aber jetzt kommt mein Problem:

Ich würde gerne mehrere Tanken abfragen und mir dann auf einem kleinem SSD1306 ausgeben.
Nur ich bekomme es nicht hin, die Abfragen mit mehreren IDs zu erstellen und diese dann abwechselnd anzeigen zu lassen.

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecure.h>
#include <ArduinoJson.h>
#include "FastLED.h"
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <time.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

// Anzahl der LEDs für die FastLED Lib festlegen
#define ANZAHL_LEDS 3 // Weil an 60er LED-Stripe angeschlossen
#define LED_PIN 2
#define Brightness 5
CRGB leds[ANZAHL_LEDS];

const char *ssid = "Plöpp";
// >= 8 oder <= 63 Zeichen oder NULL
const char *pass = "EyCaramba";

// Dein Tankerkoenig ApiKey und die abzufragende TankstellenID
String TankerkoenigApiKey = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
String TankstellenID = "xyz"; // Kraemer RVW
char TName[] = "Kraemer ";

// Ist der Preis keiner dieser Variable soll die LED bunt blinken (float ist zu ungenau, char array wäre besser, dann funktioniert das eigentlich definierte gleich oder kleiner als auch...)
float preisalarm = 1.66;

const char *host = "creativecommons.tankerkoenig.de";
const uint16_t port = 443;

// Use WiFiClientSecure class to create TLS connection
WiFiClientSecure client;

const String url = "https://creativecommons.tankerkoenig.de/json/detail.php?id=" + TankstellenID + "&apikey=" + TankerkoenigApiKey;

// *INDENT-OFF*
const char cert_XSRG_ROOT_X1 [] PROGMEM = R"CERT(
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
-----END CERTIFICATE-----
)CERT";
// *INDENT-ON*
X509List cert(cert_XSRG_ROOT_X1);

uint32_t lastTime;
const uint32_t intervall = 1000UL * 60 * 5; // mindestens 5 Minuten

// Aktiviert LED im loop
bool ledalarm = false;


void configCA() {
  client.setTrustAnchors(&cert);
  Serial.println("Single CA");
}

int abfrage() {
  Serial.print("Connecting to ");
  Serial.println(host);
  if (!client.connect(host, port)) {
    Serial.println("Connection failed");
    return -1;
  }
  lastTime = millis();
  HTTPClient http;
  Serial.print("[HTTPS] begin...\n");

  if (http.begin(client, url)) {

    Serial.print("[HTTPS] GET...\n");
    // start connection and send HTTP header
    int httpCode = http.GET();
    // httpCode will be negative on error
    if (httpCode > 0) {
      // HTTP header has been send and Server response header has been handled
      Serial.printf("[HTTPS] GET... code: %d\n", httpCode);

      // file found at server
      if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
        String jsonBuffer = http.getString();
        Serial.println(jsonBuffer);
        StaticJsonDocument<1024> doc;
        DeserializationError error = deserializeJson(doc, jsonBuffer);

        if (error) {
          Serial.print(F("deserializeJson() failed: "));
          Serial.println(error.f_str());
          return -2;
        }
        bool isOk = doc["ok"];
        if (!isOk) {
          String msg = doc["message"];
          Serial.println(msg);
          return -5;
        }
        JsonObject station = doc["station"];
        String name = station["name"];
        Serial.println(name);
        bool open = station["isOpen"];
        Serial.println(open ? "offen" : "geschlossen");
        float station_e5 = station["e5"];
        float station_e10 = station["e10"];

        if (open == true) {
          Serial.print("E10: \t");
          Serial.println(station_e10, 3);
          Serial.print("E5: \t\t");
          Serial.println(station_e5, 3);
          display.clearDisplay();
          display.setCursor(0, 10);
          display.setTextSize(1);
          display.println(TName);
          display.println();
          display.setTextSize(2);
          display.print("E10 ");
          display.println(station_e10, 3);
          display.setTextSize(1);
          display.println();
          display.setTextSize(2);
          display.print("E5  ");
          display.println(station_e5, 3);
          display.display();
          
          if (station_e5 <= preisalarm) {
            Serial.println("Preisalarm hat zugeschlagen");
            ledalarm = true;
          } else {
            Serial.println("Preisalarm hat nicht zugeschlagen");
            ledalarm = false;
          }
        } else {
          display.clearDisplay();
          display.setCursor(0, 20);
          display.setTextSize(1);
          display.println("Tankstelle ist");
          display.println("geschlossen!");
          display.display();
          Serial.println("Die Zapfe bleibt kalt");
          ledalarm = false;
        }

      }
    } else {
      Serial.printf("[HTTPS] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
      return -3;
    }

    http.end();
    return 0;
  } else {
    Serial.printf("[HTTPS Unable to connect\n");
    return -4;
  }
}

void setup() {
  Serial.begin(115200);

  // Initialize the Neopixels and Brightness
  FastLED.addLeds<NEOPIXEL, LED_PIN>(leds, ANZAHL_LEDS);
  FastLED.setBrightness(Brightness); // Helligkeit 25

  leds[0] = CRGB::Black;
  FastLED.show();

  // Initalize Display
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }
  delay(500);
  display.clearDisplay();

  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, 10);
  // Display static text
  display.println("Hallo!");
  display.println();
  display.println("Warte auf WLAN...");
  display.display();
  delay(300);

  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  // Diese WiFi Methode stellt sicher dass die Konfiguration nur erneut in den Flash Speicher geschrieben wird, wenn sich diese auch geändert hat.
  // Wichtig dabei ist dass Wifi.persistent(false) vor allen anderen WiFi Methoden ausgeführt werden muss.
  WiFi.persistent(false);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  display.clearDisplay();
  display.setCursor(0, 10);
  display.setTextSize(1);
  display.println("Verbunden!");
  delay(300);
  display.clearDisplay();
  display.setCursor(0, 10);

  // Set time via NTP, as required for x.509 validation
  configTime(3 * 3600, 0, "fritz.box", "de.pool.ntp.org");

  Serial.print("Waiting for NTP time sync: ");
  time_t now = time(nullptr);
  while (now < 8 * 3600 * 2) {
    delay(500);
    Serial.print(".");
    now = time(nullptr);
  }
  Serial.println("");
  struct tm timeinfo;
  gmtime_r(&now, &timeinfo);
  Serial.print("Current time: ");
  Serial.print(asctime(&timeinfo));

  // Initialisierung Root-CA
  configCA();
  int rc = abfrage();
  Serial.print("rc: ");
  Serial.println(rc);
  if (rc > 0) {
    display.clearDisplay();
    display.setCursor(0, 10);
    display.setTextSize(1);
    display.print("Fehler: ");
    display.println(rc);
    ledalarm = false;
  } 
}

void loop() {

  if (millis() - lastTime >= intervall) {
    int rc = abfrage();
    Serial.print("rc: ");
    Serial.println(rc);
    if (rc > 0) {
      display.clearDisplay();
      display.setCursor(0, 10);
      display.setTextSize(1);
      display.print("Fehler: ");
      display.println(rc);
      ledalarm = false;
    }
  }
  colorled();
}

void colorled() {
  if (ledalarm == true) {
    uint8_t NUM_LEDS = 3; // Wieviele LEDs sollen blinken
    uint8_t thisSpeed = 3; //10
    uint8_t deltaHue = 5;
    uint8_t thisHue = beat8(thisSpeed, 255);
    fill_rainbow(leds, NUM_LEDS, thisHue, deltaHue);
    FastLED.show();
  } else {
    leds[0] = CRGB::Black;
    FastLED.show();
  }
}

Ich wäre Euch dankbar, wenn Ihr mir helfen würdet.
Danke

Euer Daniel

Edith fügt hinzu:
Hardware:
WemosD1 Clone von AZ-Delivery
0,96" OLED white I2C Display
und WS2812b LEDs

als ich mit viel Strings arbeiten wollen, fügte ich SD Card hinzu. so kann man jedes mal nur eine Tankstelle abfragen und mit neuen Zeilen Von Karte futtern.

Blockzitat
[kolaha]
als ich mit viel Strings arbeiten wollen, fügte ich SD Card hinzu. so kann man jedes mal nur eine Tankstelle abfragen und mit neuen Zeilen Von Karte futtern.

Das Projekt soll klein bleiben, damit es in ein Kleines gedrucktes Gehäuse passt.
Ein zusätzlicher SD Kartenleser passt nicht mehr rein.

na gut, dann wenn du eine aus der liste schmeißen willst, musst dann neu hochladen.
definiere einige im Sketch, mal schauen wie man dass machen kann

Und was genau willst du auf dem Mikro-Display anzeigen ?
In deinem ersten Link wurde doch auch die komplette Anpassung an den esp8266 beschrieben, was musstest du denn da noch selbst programmieren ?

Steht doch eindeutig in der API-Beschreibung von Tankerkönig:

https://creativecommons.tankerkoenig.de/json/prices.php?ids=4429a7d9-fb2d-4c29-8cfe-2ca90323f9f8,446bdcf5-9f75-47fc-9cfa-2c3d6fda1c3b,60c0eefa-d2a8-4f5c-82cc-b5244ecae955,44444444-4444-4444-4444-444444444444&apikey=00000000-0000-0000-0000-000000000002

Abfrage prices.php?liste der Tankstellen_id (Komma-getrennt)&apikey=Dein_API_KEY

Gruß Tommy

Falsch, muss man nicht. Man kann die Liste auch als Datei ins LittleFS laden und beim Booten und einen Linkaufruf rein laden.
Tipp: Dateimanager von Fips.

Gruß Tommy

mit diesem Sketch?

Das man den Sketch dafür anpassen muss, könntest sogar Du merken.

Gruß Tommy

Die Abfrage detail.php geht nur für jeweils eine Tankstelle.

Wenn Du mehrere brauchst, solltest Du entweder alle nacheinander abfragen oder die Abfrage über die Umkreissuche oder prices.php erledigen. Da ist dann allerdings die zurückgegebene Menge an Informationen reduziert. Da es vermutlich auf die Preise ankommt sollte das insbesondere bei diesem kleinen Display aber ausreichen.

Siehe auch die API-Beschreibung.

Das hat mich schon mal auf den Weg zur richtigen Richtung gebracht (prices.php),
nur leider habe ich keine Ahnung, wie ich nun die einzelnen JSON Elemente anständig auf mein Display bekomme (oder gar in den SerMon).

Der ursprüngliche Code hatte einen Fehler, da er wenn die Tanke geschlossen war, es im Display nicht angezeigt wurde.

Das Display könnte ich auch austauschen, aber da macht dann wieder mein Anfängerstaus mir wieder einen Strich durch die Rechnung, da ich zwar ein 2.8" E-Ink Display hier hab, aber bis auf mit dem Beispiel Sketch mit einem Uno, ich das Ding nicht zum Brummen bringen kann (Ansteuerung per SPI).

SerMon ist einfacher als Display :slight_smile: - und hast Du ja auch schonmal für den kompletten Datensatz gemacht:

Serial.println(jsonBuffer);

Die Analyse der Json-Daten hast Du ja in Deinem Code auch schon drin. Wenn Du den neuen JSON-Buffer aus dem seriellen Monitor rauskopierst und in den Assistenten von ArduinoJson wirfst, bekommst Du auch ein CodeBespiel - ähnlich wie das, was Du jetzt schon hast.
Es kommt halt ein (JSON-)Array zurück mit jeweils den Daten für die entsprechende Tankstelle.

1 Like

Darauf wurde dort aber auch hingewiesen, dass es keine Preise gibt, wenn die Tanke geschlossen ist. Das musst Du halt auswerten (Feld status muss "open" sein).

Gruß Tommy

Wieso Fehler ?
Der Code sollte ja nicht für alle Ansprüche genügen. Oder siehst du das Forum so, dass es alles für dich programmiert. Da solltest du selbst auch etwas Arbeit reinstecken.
Also es ist def. kein Fehler.
Und das mit dem Displaywechsel kann man auch als Anfänger lernen. Geht alles Step by Step. Dann lernt man es auch.

ich geb's auf ...
Danke an die die wirklich "Hilfe" geleistet haben.

Thema kann geschlossen werden !

Du hast genügend Hinweise bekommen. Ich hatte Dir den Lösungsansatz bereits in #6 gegeben, den Du ignoriert hast.
Wenn Du nicht lernwillig/-fähig bist, ist das Dein Problem.
Deinen Code schreibt keiner für Dich.

Und Tschüß.

Gruß Tommy

Den Hinweis musste ich erstmal verstehen ... das hab ich mittlerweile.
Dennoch fehlt mir das Verständnis für die "Dekodierung" des JSON Strings ... aber jeder Meister ist vom Himmel gefallen.

das verlagt auch keiner ... nichtmal ich.

Gruß Daniel

Dann mache einen Abruf nach #6 und schreibe die Daten nach Serial raus. dann kann man sie hier diskutieren und weiterführen. Nimm eine Tanke, die zu hat und eine die offen ist.
Trotzreaktionen wie von Kleinkindern, bringen nichts.

Gruß Tommy

Und wie soll man dir dann helfen ?
Mit dem vorhandenen Code im Link sind auch viele andere klar gekommen.

Die vielen Anderen sind entweder klar gekommen, da sie entweder selber wussten, wie es weiter geht, oder haben sich mit dem begnügt, was der Code ausgegeben hat.