ESP32 SSL Error + OLED Adafruit + termometr w Supla z danymi z API

Kacper1263
Posts: 2
Joined: Fri Nov 08, 2024 2:17 pm

Post

witam wszystkich,
jestem kompletnie "zielony" w temacie supla-device, ostatnio zachciało mi się trochę wgłębić w temat aby wykorzystać Suple w swoich projektach ale idzie to coś topornie więc proszę o pomoc :p

Słowem wstępu, mam prosty projekt. ESP32 z ekranem OLED SSD1306 które działa mi jako termometr, temperaturę wewnątrz mierzy DHT22 a temperaturę zewnętrzną postanowiłem sobie zasysać z pobliskiego paczkomatu przez API :D. Naszło mnie aby do tego wszystkiego dodać właśnie Suple aby mieć wgląd w apce do danych z DHT + tych zassanych z API. Do tej porty z Suplą miałem kontakt tylko przez Zamela więc od strony "kodowania" Supli nie mam wiedzy. Na co dzień piszę głównie w C# ale coś tam z C++ jeszcze pamiętam ale braki mogą być + kod trochę pisany na kolanie, za to kilka lat temu sporo bawiłem się Arduino.

I teraz do rzeczy, problemów po drodze miałem sporo ale aktualnie nie mogę przeskoczyć poniższych trzech:
  1. "SSL error: -1, ERROR - Generic error" - nie mogę połączyć się z serwerem supli, gdzieś się na forum doszukałem, że trzeba ustawić certyfikaty za pomocą "setSuplaCACert" oraz "setSupla3rdPartyCACert" ale to nie pomogło

    Code: Select all

    Supla - starting initialization (platform 0)
    Main storage not configured
    Config storage not configured
    Channel(0) value changed to temp(27.70), humi(38.60)
    GUID: 9E69D6EB1490454DBD9B8C18806D8382
    Device name: SUPLA-ESP32
    Device software version: SDK 24.10.05-dev
    Initializing network layer
    [Wi-Fi] Network AP/hostname: SUPLA-ESP32-1C6920302C00
    Using Supla protocol version 23
    Current status: [5] SuplaDevice initialized
    Enter normal mode
    WiFi: establishing connection with SSID: "KMA"
    Indoor Temperature: 27.70°C, Indoor Humidity: 38.60%
    WiFi Station disconnected
    E (10100) wifi:sta is connecting, return error
    Indoor Temperature: 27.70°C, Indoor Humidity: 38.90%
    Connected BSSID: 24:E4:CE:55:19:84
    local IP: 192.168.0.148
    subnetMask: 255.255.255.0
    gatewayIP: 192.168.0.1
    Signal strength (RSSI): -19 dBm
    Establishing encrypted connection with: svr32.supla.org  (port: 2016)
    SSL error: -1, ERROR - Generic error
    Connection fail (0). Server: svr32.supla.org 
    Indoor Temperature: 27.70°C, Indoor Humidity: 38.90%
    Channel(0) value changed to temp(27.70), humi(38.90)
    Establishing encrypted connection with: svr32.supla.org  (port: 2016)
    SSL error: -1, ERROR - Generic error
    Current status: [6] Not connected to Supla server
    Connection fail (0). Server: svr32.supla.org 
    
  2. Odkąd podpiąłem Suple do projektu to pojawiły się problemy z obsługą OLEDa, wywołanie np. display.println(...) i potem display() kończą się tym, że ESP się wywala a następnie leci restart. Musze/Mogę obsługiwać tego OLEDa ale przez jakieś metodki z libki supli zamiast te z libki od Adafruit?

    Code: Select all

    Device software version: SDK 24.10.05-dev
    Initializing network layer
    [Wi-Fi] Network AP/hostname: SUPLA-ESP32-1C6920302C00
    Using Supla protocol version 23
    Current status: [5] SuplaDevice initialized
    Enter normal mode
    WiFi: establishing connection with SSID: "KMA"
    Guru Meditation Error: Core  1 panic'ed (StoreProhibited). Exception was unhandled.
    
    Core  1 register dump:
    PC      : 0x4008a514  PS      : 0x00060b30  A0      : 0x800db688  A1      : 0x3ffb21d0  
    A2      : 0x00000000  A3      : 0x00000000  A4      : 0x00000400  A5      : 0x00000000  
    A6      : 0x00000000  A7      : 0x00000040  A8      : 0x00000001  A9      : 0x71eb851e  
    A10     : 0x028f5c28  A11     : 0x00000000  A12     : 0x00002710  A13     : 0x0000e5c0  
    A14     : 0x3ffc4f94  A15     : 0x3ffc45a0  SAR     : 0x00000002  EXCCAUSE: 0x0000001d  
    EXCVADDR: 0x00000000  LBEG    : 0x4008a514  LEND    : 0x4008a51f  LCOUNT  : 0x0000003f  
    
    
    Backtrace: 0x4008a511:0x3ffb21d0 0x400db685:0x3ffb21e0 0x400d3be3:0x3ffb2200 0x400ed23c:0x3ffb2270 0x40090972:0x3ffb2290
    
  3. I ostatnie to pytanie w jaki sposób mogę zrobić sobie w supli kanał z fake termometrem do którego dane będę przekazywać z API zamiast z DHT? Gdzieś na forum widziałem jakiś przykład wirtualnego termometru, który działał na zasadzie klaski, która dziedziczyła chyba z DHT ale miała nadpisane metodki od zwracania danych, nie mogę niestety teraz tego odnaleźć. Dobrze rozumiem, że to jest najprostsze obejście?
Libka Supli najnowsza z menedżera w wersji 24.10.4. Builduje wszystko w Arduino IDE bo z jakiegoś powodu PlatformIO mi nie trawi projektu z Suplą :P. Poniżej kod z usuniętymi fragmentami od OLEDa więc będą puste metodki, to ten kod który mi się aktualnie kompiluje ale nie działa z powodu błędu SSL.

Będę wdzięczny za wszystkie porady!

Code: Select all

#include <HTTPClient.h>
#include <Arduino_JSON.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
//#include <DHT.h>
#include <config.h>
#include <ArduinoOTA.h>
#include <SuplaDevice.h>
#include <supla/sensor/DHT.h>
#include <supla/network/esp_wifi.h>
#include <supla/device/supla_ca_cert.h>

const char* ssid = WIFI_SSID;
const char* password = WIFI_PASS;

Supla::ESPWifi wifi(ssid, password);

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

const String apiUrl = "https://greencity.pl/shipx-point-data/248/KRA186M/air_index_level";

#define DHTPIN 4      // Define the pin connected to the DHT sensor
#define DHTTYPE DHT22 // Define sensor type (DHT22)
DHT dht(DHTPIN, DHTTYPE);

float lastTemperature = -1, lastHumidity = -1, lastPM25Percent = -1, lastPM10Percent = -1, lastPressure = -1;
String lastQuality = "";
float indoorTemperature = -1, indoorHumidity = -1;

unsigned long previousAPIMillis = 0, previousDHTMillis = 0, previousDisplayMillis = 0;
const long apiInterval = 300000;      // 5 minutes in milliseconds
const long dhtInterval = 5000;        // 5 seconds in milliseconds
const long displayInterval = 5000;    // 5 seconds display switch interval
bool displayOutdoor = false;           // Toggle display between indoor and outdoor

void setup() {
  Serial.begin(115200);
  pinMode(DHTPIN, INPUT_PULLUP);
  dht.begin();
  
  char GUID[SUPLA_GUID_SIZE] = SUPLA_GUID;
  char AUTHKEY[SUPLA_AUTHKEY_SIZE] = SUPLA_KEY;
  
  // CHANNEL0 - DHT22 Sensor
  new Supla::Sensor::DHT(DHTPIN, DHTTYPE);

  SuplaDevice.setSuplaCACert(suplaCACert);
  SuplaDevice.setSupla3rdPartyCACert(supla3rdCACert);
  SuplaDevice.setAutomaticResetOnConnectionProblem(60); 
  SuplaDevice.begin(GUID,              // Global Unique Identifier 
                    "svr32.supla.org ",  // SUPLA server address
                    "[email protected]",   // Email address used to login to Supla Cloud
                    AUTHKEY); 


}
bool otaReady = false;
void loop() {
  SuplaDevice.iterate();
  
  // moved here from setup, supla should handle WiFi so we just wait, right?
  if(WiFi.status() == WL_CONNECTED && !otaReady){
    // OTA
    ArduinoOTA.setPassword("wifi-temp-ota");
    ArduinoOTA
      .onStart([]() {
      })
      .onEnd([]() {
      })
      .onProgress([](unsigned int progress, unsigned int total) {
      })
      .onError([](ota_error_t error) {
      });
    ArduinoOTA.begin();
    otaReady = true;

  }

  if(otaReady){
    ArduinoOTA.handle();
  }
  unsigned long currentMillis = millis();

  // Fetch API data every 5 minutes
  if (currentMillis - previousAPIMillis >= apiInterval || previousAPIMillis == 0) {
    fetchWeatherData();
    previousAPIMillis = currentMillis;
  }

  // Read DHT22 sensor data every 5 seconds
  if (currentMillis - previousDHTMillis >= dhtInterval || previousDHTMillis == 0) {
    // wait 2s on first run to let the sensor initialize
    if (previousDHTMillis == 0) {
    }

    indoorTemperature = dht.readTemperature();
    indoorHumidity = dht.readHumidity();
    Serial.print("Indoor Temperature: ");
    Serial.print(indoorTemperature);
    Serial.print("°C, Indoor Humidity: ");
    Serial.print(indoorHumidity);
    Serial.println("%");
    previousDHTMillis = currentMillis;
  }

  // Switch display between indoor and outdoor data every 5 seconds
  if (currentMillis - previousDisplayMillis >= displayInterval || previousDisplayMillis == 0) {
    displayOutdoor = !displayOutdoor;

    if (displayOutdoor) {
      displayWeatherData("Outdoor", lastTemperature, lastHumidity, lastPM25Percent, lastPM10Percent, lastPressure, lastQuality);
    } else {
      displayWeatherData("Indoor", indoorTemperature, indoorHumidity, -1, -1, -1, "");
    }
    previousDisplayMillis = currentMillis;
  }
}

void fetchWeatherData() {
  // check is wifi connected
  if (WiFi.status() != WL_CONNECTED) {
    return;
  }

  // show fetching message on first run
  if(previousAPIMillis == 0){
  }

  HTTPClient http;
  http.begin(apiUrl);
  http.addHeader("X-Requested-With", "XMLHttpRequest");

  int httpResponseCode = http.POST("");
  if (httpResponseCode == 200) {
    String payload = http.getString();
    JSONVar response = JSON.parse(payload);

    if (JSON.typeof(response) == "undefined") {
      Serial.println("Parsing failed!");
      displayError("API parse error");
    } else {
      lastTemperature = parseSensorValue(response, "TEMPERATURE");
      lastHumidity = parseSensorValue(response, "HUMIDITY");
      lastPM25Percent = parseSensorPercentage(response, "PM25");
      lastPM10Percent = parseSensorPercentage(response, "PM10");
      lastPressure = parseSensorValue(response, "PRESSURE");
      if (response.hasOwnProperty("air_index_level") && JSON.typeof(response["air_index_level"]) != "null") {
        lastQuality = (const char*)response["air_index_level"];
      } else {
        Serial.println("Air Index Level is not available.");
      }
    }
  } else {
    displayError("API request error");
  }

  http.end();
}

float parseSensorValue(JSONVar response, String sensorName) {
  JSONVar sensors = response["air_sensors"];
  for (int i = 0; i < sensors.length(); i++) {
    String sensorData = sensors[i];
    int pos = sensorData.indexOf(":");
    String name = sensorData.substring(0, pos);
    if (name == sensorName) {
      String value = sensorData.substring(pos + 1, sensorData.indexOf(":", pos + 1));
      return value.toFloat();
    }
  }
  return -1;  // return -1 if sensor not found
}

float parseSensorPercentage(JSONVar response, String sensorName) {
  JSONVar sensors = response["air_sensors"];
  for (int i = 0; i < sensors.length(); i++) {
    String sensorData = sensors[i];
    int firstColon = sensorData.indexOf(":");
    int secondColon = sensorData.indexOf(":", firstColon + 1);
    String name = sensorData.substring(0, firstColon);
    if (name == sensorName && secondColon != -1) {
      String percentage = sensorData.substring(secondColon + 1);
      return percentage.toFloat();
    }
  }
  return -1;  // return -1 if sensor not found
}

void displayWeatherData(String source, float temperature, float humidity, float pm25Percent, float pm10Percent, float pressure, String quality) {
 
}

void displayError(String message) {
}
Last edited by Kacper1263 on Sat Nov 09, 2024 4:26 pm, edited 1 time in total.
User avatar
lukfud
Posts: 2480
Joined: Thu Nov 23, 2017 11:33 pm
Location: Warszawa
Has thanked: 13 times
Been thanked: 11 times

Post

Obsługą połączenia z siecią zajmuje się biblioteka supla-device, nie musisz nic dopisywać.

Zacznij od przykładów:
https://github.com/SUPLA/supla-device/b ... rement.ino
https://github.com/SUPLA/supla-device/b ... erface.ino

Dla DHT użyj klasy z biblioteki
https://github.com/SUPLA/supla-device/b ... nsor/DHT.h

Dla temperatury z API użyj
https://github.com/SUPLA/supla-device/b ... rmometer.h
https://www.facebook.com/groups/supladiy
https://www.facebook.com/groups/suplazamel
https://www.facebook.com/groups/suplaauraton
https://smartnerzeczy.pl
Kacper1263
Posts: 2
Joined: Fri Nov 08, 2024 2:17 pm

Post

dzięki za odpowiedź. Widzę, że faktycznie problem z SSL nie występuje przy konfiguracji Supli przez przeglądarkę więc zakładam, że to tylko jakiś problem przy ręcznym podawaniu danych w kodzie.

W sumie to nawet ten przykład z GP Measurement sprawdzi się dla mojego przekazywania danych z API bo fajnie to działa - dzięki.

Do pełni szczęścia został mi tylko temat obsługi OLEDa tak aby nie gryzł się z Suplą, przy okazji crashując ESP

EDIT:
Dodam jeszcze zdekodowany stack trace, może to jakoś pomoże w rozkminach:
supla-stack-trace.png
adafruit-cls.png

EDIT 2:
Problem mi się rozwiązał po ogarnięciu buildowania projektu w VS z Platform IO zamiast w Arduino IDE. Dzięki za pomoc
You do not have the required permissions to view the files attached to this post.

Return to “supla-dev”