Projektvorstellung: Spritpreis von deiner Heimtankstelle mit ESP32 auf Display anzeigen

Es geht, wird aber in den Beispielen zur 2.7.4 nicht so publiziert. Der WiFiSecureClient kann PEM-Zertifikate. Wenn man dann mehrere Beispiele zusammen würfelt, kann man etwas brauchbares bauen.
Ich habe es nicht für Tankerkönig gemacht, weil ich keinen API-Key habe. Ich habe es auf meiner Website gemacht. Das könnt Ihr auch zum Testen benutzen.
Ich erhalte eine Verbindung und den Payload.

/*
    HTTP over TLS (HTTPS) example sketch

    This example demonstrates how to use
    WiFiClientSecure class to access HTTPS API.
    We fetch and display the status of
    esp8266/Arduino project continuous integration
    build.

    Created by Ivan Grokhotkov, 2015.
    This example is in public domain.
*/

#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <ESP8266HTTPClient.h>

const char *ssid = "SSID";
// >= 8 oder <= 63 Zeichen oder NULL
const char *pass = "geheim";

const char *host = "www.wikinger-tommy.de";
const uint16_t port = 443; 

// Im Browser (FF) die Website aufrufen, mit der Mouse auf das Schloß klicken, weitere Informationen,
// Zertifikat anzeigen, ganz nach rechts auf das höchste Zertifikat gehen, runter scrollen bis "Verschiedenes" 
// dort PEM(Zertifikat) wählen und zwischen "CERT( und )CERT"; einfügen, evtl. Gültigkeitsdatum eintragen
// gültig bis Mon, 04 Jun 2035

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";

X509List cert(cert_XSRG_ROOT_X1);

void setup() {
  Serial.begin(115200);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  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());

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

  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));

  // Use WiFiClientSecure class to create TLS connection
  WiFiClientSecure client;
  Serial.print("Connecting to ");
  Serial.println(host);

  // Serial.printf("Using certificate: %s\n", cert_XSRG_ROOT_X1);
  client.setTrustAnchors(&cert);

  if (!client.connect(host, port)) {
    Serial.println("Connection failed");
    return;
  }

  HTTPClient http;
  Serial.print("[HTTPS] begin...\n");
    if (http.begin(client, "https://www.wikinger-tommy.de/arduino/test.txt")) {
		
      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("[HTTP] GET... code: %d\n", httpCode);

        // file found at server
        if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
          String payload = http.getString();
          Serial.println(payload);
        }
      } else {
        Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
      }

      http.end();
    } else {
      Serial.printf("[HTTP Unable to connect\n");
    }
}
 

void loop() {
}

Für den Tankerkönig ist es das gleiche Root-Zertifikat, da der seins auch bei LetsEncrypt hat.

Gruß Tommy

1 Like

Hallo,

habe gerade mal in Deinen Sketch die Tankerkönigdaten reingepackt, API-Key hatte ich mir ja schon geholt (ist unproblematisch).
Verbindung klappt, das JSON wird geholt:

"name":"JET BERLIN AM TIERPARK 126",
"brand":"JET","street":"AM TIERPARK",
"houseNumber":"126",
"postCode":10319,
"place":"BERLIN",
"openingTimes":,
"overrides":,
"wholeDay":true,
"isOpen":true,
"e5":1.729,
"e10":1.669,
"diesel":1.519,
"lat":52.49549,
"lng":13.52344,
"state":"deBE"

Muß ich morgen nur noch dazu kommen den Rest reinzukopieren und an das 128x32 Display anzupassen, dann hat das Heltec-Modul einen Verwendungszweck...

Also erstmal vielen Dank Tommy.

Gruß aus Berlin
Michael

Danke Tommy, gute Arbeit! Bin mal gespannt wann der erste Fuchs hier im Forum deinen Sketch mit meinem lauffähig kombiniert. (Und hoffentlich ebenfalls uns allen hier zugänglich macht.) :+1:t2:

GRRR!
Du bist doch auch nicht den ersten Tag bei.
</>
!!!

Da ist ja keine Hürde mehr drin.
Deine Zeile:

jsonBuffer = httpGETRequest(serverPath.c_str());

Neue Zeile bei mir:

// alt
String payload = http.getString();
// neu 
jsonBuffer = http.getString();

Die ganze Abfrage in den Loop, wie bei Dir.
Das solltest Du selbst in den Griff bekommen.

Gruß Tommy

So, ich habe jetzt das Beispiel mal etwas zerlegt, so dass man wahlweise die Single-CA (für eine definierte Domain/Root-CA), als auch die CA-Liste (alle bekannten CA) benutzen kann. Man darf aber immer nur eine der zusätzlichen ino rein kopieren!

Hauptprogramm:


#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecure.h>

const char *ssid = "ssid";
// >= 8 oder <= 63 Zeichen oder NULL
const char *pass = "geheim";

const char *host = "www.wikinger-tommy.de";
const uint16_t port = 443; 

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

void setup() {
  Serial.begin(115200);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  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());

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

  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));

  Serial.print("Connecting to ");
  Serial.println(host);
  
  // Initialisierung Root-CA
  configCA();
  
  if (!client.connect(host, port)) {
    Serial.println("Connection failed");
    return;
  }

  HTTPClient http;
  Serial.print("[HTTPS] begin...\n");
    if (http.begin(client, "https://www.wikinger-tommy.de/arduino/test.txt")) {
    
      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("[HTTP] GET... code: %d\n", httpCode);

        // file found at server
        if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
          String payload = http.getString();
          Serial.println(payload);
        }
      } else {
        Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
      }

      http.end();
    } else {
      Serial.printf("[HTTP Unable to connect\n");
    }
}
 
void loop() {
}

Dann kann man entweder eine einzelne CA einbinden
_clientOneCA.ino


// Im Browser die Website aufrufen, mit der Mouse auf das Schloß klicken, weitere Informationen
// Zertifikat anzeigen, ganz nach rechts auf das höchste Zertifikat gehen, runterscrollen bis "Verschiedenes" 
// dort PEM(Zertifikat) wählen und zwischen "CERT( und )CERT"; einfügen, evtl. Gültigkeitsdatum eintragen
// gültig bis Mon, 04 Jun 2035


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";

X509List cert(cert_XSRG_ROOT_X1);

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

oder die CA-Liste im littleFS
_clientAllCA.ino

#include <CertStoreBearSSL.h>
#include <FS.h>
#include <LittleFS.h>

// certs.ar muss im LittleFS liegen
BearSSL::CertStore certStore;

void configCA() {
  LittleFS.begin();
	int numCerts = certStore.initCertStore(LittleFS, PSTR("/certs.idx"), PSTR("/certs.ar"));
	client.setCertStore(&certStore);
	Serial.print("Certstore. CAs: ");
	Serial.println(numCerts);
}	

Viel Spaß damit.

Gruß Tommy

Tommy, ich habe leider nach wie vor keinen ESP8662 zum testen.

Ich habe selbst etwas "komplettes" bereitgestellt, nur eben für den ESP32. Mein Gedanke dahinter war einfach nur ebenfalls etwas "komplettes" für den ESP8662 hier im Thread zu haben. :slight_smile:

Diejenigen welche auf diesen Thread stoßen interessieren sich ja für eine Benzinpreisabfrage und sind bestimmt froh direkt etwas fertiges für eben ESP32 oder ESP8662 zu haben. Ich hoffe das ist verständlich.

(Achso und deine SSID und Passwort solltest du noch aus deinem Post entfernen.)

Hallo,

ja, ist beim reinkopieren nicht aufgefallen, ich habe es editiert.

Gruß aus Berlin
Michael

1 Like

@amithlon
Kannst du deine Lösung posten, ich kriegs nicht hin.

Auch von mir bis hierhin, danke an Tommy.

Danke.

Gruß Tommy

Dann mal quick & dirty die Lösung für den ESP8266 (ohne Display, nur serielle Ausgabe). Das Display sollte jeder selbst hin bekommen.


#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecure.h>
#include <ArduinoJson.h>

const char *ssid = "ssid";
// >= 8 oder <= 63 Zeichen oder NULL
const char *pass = "geheim";

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";

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";

X509List cert(cert_XSRG_ROOT_X1);

uint32_t lastTime;
const uint32_t intervall = 1000UL * 60 * 5; // mindestens 5 Minuten
 
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;
          }
          JsonObject station = doc["station"];
          String name = station["name"];
          Serial.println(name);
          bool open = station["isOpen"];  
          Serial.println(open?"offen":"geschlossen");
          float num = station["e5"];
          Serial.print("E5: \t\t"); 
          Serial.println(num,2);
          num = station["e10"];
          Serial.print("E10: \t\t"); 
          Serial.println(num,2);
          num = station["diesel"];
          Serial.print("Diesel: \t"); 
          Serial.println(num,2);
          
        }
      } 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);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  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());

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

  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);
}

void loop() {
  if (millis() - lastTime >= intervall) {
    int rc = abfrage();
    Serial.print("rc: ");
    Serial.println(rc);
  }
}

Als Ausgabe erhalte ich für die Tanke:

JET NUERNBERG FUERTHER STR. 275
offen
E5: 		1.70
E10: 		1.64
Diesel: 	1.50

Gruß Tommy

5 Likes

Hallo Tommy, kann es sein, das Du endlich auch mal wieder richtig angefixxt warst?
:slight_smile:
Danke dafür...
Und nochmal der Versuch:
@uwefed ist es möglich den Thread Zeigt her eure geilen Projekte! dafür aufzumachen?

Hallo Tommy,

super....hatte mir schon die Nacht reserviert. Jetzt gehts doch früher zu Bett.
Mein Versuch hat beim übertragen ins json gehakt und ist ständig abgestürzt.
Die einfache Version ohne json hat funktioniert.
Da kann ich jetzt drauf aufbauen.

Vielen Dank.

Gruß
Dieter

Das ist noch nicht optimiert. Eigentlich sollte man als Erstes das Feld "ok" auswerten, bevor man sich den Rest anschaut.
Aber etwas sollte ja auch für die Teilnehmer übrig bleiben, damit nicht nur C&P entsteht.

Ja, das Thema hat mich interessiert (besonders das HTTPS) und es hat Spaß gemacht, endlich mal wieder so richtig rum zu probieren und zu merken, es geht viel mehr, man muss es nur finden :wink: .

Nebenbei war das JSON auch nicht schädlich für die Erkenntnise :wink:

Gruß Tommy

Hallo,

ich habe das jetzt mal für mein Heltec-Modul Kit 8 lauffähig gemacht:
Heltec Kit 8
lag ja hier rum. Da das Modul auch einen Akkuanschluß und Ladeschaltung hat, habe ich den ESP8266 schlafen geschickt (1k Widerstand zwischen RST und GPIO16 anlöten).
Ist noch nicht sonderlich aufgeräumt, macht aber erstmal was es soll.

/*
    HTTP over TLS (HTTPS) example sketch

    This example demonstrates how to use
    WiFiClientSecure class to access HTTPS API.
    We fetch and display the status of
    esp8266/Arduino project continuous integration
    build.

    Created by Ivan Grokhotkov, 2015.
    This example is in public domain.
*/

#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

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

String tag[] = {"So","Mo","Di","Mi","Do","Fr","Sa"};

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

const char *ssid = "xxxx";
const char *pass = "yyyy";

// Dein Tankerkoenig ApiKey und die abzufragende TankstellenID
String TankerkoenigApiKey = "xxxxx";
String TankstellenID = "yyyyy";

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

// Im Browser (FF) die Website aufrufen, mit der Mouse auf das Schloß klicken, weitere Informationen,
// Zertifikat anzeigen, ganz nach rechts auf das höchste Zertifikat gehen, runter scrollen bis "Verschiedenes" 
// dort PEM(Zertifikat) wählen und zwischen "CERT( und )CERT"; einfügen, evtl. Gültigkeitsdatum eintragen
// gültig bis Mon, 04 Jun 2035

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";

X509List cert(cert_XSRG_ROOT_X1);

// Sleeptime
unsigned long waitTime  =  60000000; // 1 Minute wenn WLAN fehlschlägt
unsigned long sleepTime = 300000000; // 5 Minuten bis nächstes Datenholen

void setup()
{
  Serial.begin(115200);
  Serial.println();
  Serial.println("ESP Start");

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

  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(0, 10);
  // Display static text
  display.println("Hallo! :)");
  display.display();
  delay(2000);
  display.clearDisplay();

  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  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());

  // Set time via NTP, as required for x.509 validation
  configTime(0, 0, "pool.ntp.org", "time.nist.gov");
  setenv("TZ", "CET-1CEST,M3.5.0,M10.5.0/3", 1);

  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;
  Serial.print("Current time: ");
  Serial.print(ctime(&now));

  timeinfo = localtime(&now);  
  display.setTextSize(1);
  display.setCursor(0, 2);
  display.printf(" %s %02d.%02d.  %02d:%02d Uhr", tag[timeinfo->tm_wday],timeinfo->tm_mday, timeinfo->tm_mon, timeinfo->tm_hour, timeinfo->tm_min);
  display.display();

  // Use WiFiClientSecure class to create TLS connection
  WiFiClientSecure client;
  Serial.print("Connecting to ");
  Serial.println(host);

  // Serial.printf("Using certificate: %s\n", cert_XSRG_ROOT_X1);
  client.setTrustAnchors(&cert);

  if (!client.connect(host, port))
  {
    Serial.println("Connection failed");
    ESP.deepSleep(waitTime, RF_CAL);        // schlafen für 1 Minute
    delay(100);
  }

  HTTPClient http;
  Serial.print("[HTTPS] begin...\n");
  String serverPath = "https://creativecommons.tankerkoenig.de/json/detail.php?id=" + TankstellenID + "&apikey=" + TankerkoenigApiKey;

  if (http.begin(client, serverPath.c_str()))
    {
		
      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("[HTTP] 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;
          }

          JsonObject station = doc["station"];

          float station_e10 = station["e10"];
          Serial.print("Super E10: ");
          Serial.println(station_e10, 3);

          bool station_isOpen = station["isOpen"];
          if (station_isOpen == true)
          {
            display.setCursor(6, 18);
            display.setTextSize(2);
            display.print("E10: ");
            String preis_e10 = String(station_e10,3);
            display.print(preis_e10.substring(0,4));
            display.setTextSize(1);
            display.setCursor(116, 18);
            display.print("9");

            display.display();
          }
          else
          {
            display.clearDisplay();
            display.display();
          }
        }
      }
      else
      {
        Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
      }

      http.end();
    }
    else
    {
      Serial.printf("[HTTP Unable to connect\n");
    }
  Serial.println("Sleep 5 Minuten");
  ESP.deepSleep(sleepTime, RF_CAL);        // schlafen gehen
  delay(100);
    
}
 

void loop() {
}

Danke nochmal an Tommy für die HTTPS-Geschichte und natürlich an dandud100 für die Idee und den Sketch zum Tankerkönig.

Ich werde mal die Stromaufnahme mit schlafendem ESP8266 und aktivem OLED messen, mal schauen, Akkus liegen hier ja auch noch rum...

PS: da hat eine Rundung in der Preisausgabe mir einen Streich gespielt, ist jetzt nicht schön aber richtig.

Gruß aus Berlin
Michael

Hallo Tommy,

ich versuche mich gerade an der Auswertung des JSON-Strings.
Da dies für mich absolutes Neuland ist, bitte ich Dich um einen kurzen Tipp wie ich die ersten Daten des Strings ("ok", "license") angezeigt bekomme. Da stecke ich aktuell fest. Alles was zu "station" gehört, kann ich entsprechend deinem Sketch abfragen.
Dies hier ist der Anfang meines JSON-Strings:

{"ok":true,"license":"CC BY 4.0 - https:\/\/creativecommons.tankerkoenig.de","data":"MTS-K","status":"ok","station":{"id":"65131384-915a-4ad7-9327-0e74d3dfe9a8","name":"OIL! Tankstelle

Wäre schön, wenn du noch einen Tipp für mich hast.

Ich habe meine Funktion auch dahin erweitert:

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 num = station["e5"];
          Serial.print("E5: \t\t"); 
          Serial.println(num,2);
          num = station["e10"];
          Serial.print("E10: \t\t"); 
          Serial.println(num,2);
          num = station["diesel"];
          Serial.print("Diesel: \t"); 
          Serial.println(num,2);
          
        }
      } 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;
  }
}

Gruß Tommy

1 Like

Hallo Tommy,

danke Dir,

Gerade habe ich es rausgefunden:
Z.B.

String wert1 = doc["license"];
Serial.println(wert1);

Habe diese Doku dazu gefunden. Die hat mich weiter gebracht.

Und genau diese Abfrage auf "ok" wollte ich mit einbauen.
Aber wie geschrieben, JSON ist Neuland für mich und muss da viel lesen.

Nochmals Danke.

Gruß Dieter

Der gute alte Float Klassiker. :wink:
Danke übrigens fürs teilen deines Sketch, halte uns auf dem laufenden. :slight_smile:

Kleiner Tipp, auf der Webseite der ArduinoJson Bibliothek gibt es einen Assistant der ist da sehr sehr nützlich. Einfach mal den kompletten JSON String reinpacken und er zeigt dir wie du welchen Teil davon bekommst.

1 Like

Danke, guter Tipp.
Da kann man sich besser reinarbeiten.