Kanał pomiarowy

User avatar
klew
Posts: 13909
Joined: Thu Jun 27, 2019 12:16 pm
Location: Wrocław
Has thanked: 135 times
Been thanked: 137 times

Post

Juszczaczek1 wrote: Sat Jan 25, 2025 6:19 pm
klew wrote: Wed Jan 22, 2025 8:36 am
Juszczaczek1 wrote: Wed Jan 22, 2025 8:16 am Dzięki za podpowiedzi , zobaczymy czy chat gpt to wszystko ogarnie😝
Raczej nie przygotuje Ci integracji z Suplą, bo on nie zna za dobrze Supli i generuje często kod pasujący bardziej pod Arduino.
Możesz próbować mu wrzucić przykładowy plik froniusa i napisać, aby na jego podstawie coś wygenerował.
Ale ogólnie mogą z tym być problemy.
Jest gdzieś jakiś przykład kodu tworzącego kanał licznika energii, muszę chatowi pokazać bo nic nie ogarnia.Albo czy myślicie nad dodanie również integrację z falownikiem foxess tak jak jest to z fronius?
Skąd pobierasz tego jsona? Z falownika czy z jakiegoś serwisu w sieci?
Prześlij wszystko co masz zrobione do tej pory.
Najlepsze suple dla Twojego domu :mrgreen:
Juszczaczek1
Posts: 389
Joined: Sun Nov 08, 2020 3:41 pm
Been thanked: 2 times

Post

klew wrote: Sat Jan 25, 2025 8:59 pm
Juszczaczek1 wrote: Sat Jan 25, 2025 6:19 pm
klew wrote: Wed Jan 22, 2025 8:36 am

Raczej nie przygotuje Ci integracji z Suplą, bo on nie zna za dobrze Supli i generuje często kod pasujący bardziej pod Arduino.
Możesz próbować mu wrzucić przykładowy plik froniusa i napisać, aby na jego podstawie coś wygenerował.
Ale ogólnie mogą z tym być problemy.
Jest gdzieś jakiś przykład kodu tworzącego kanał licznika energii, muszę chatowi pokazać bo nic nie ogarnia.Albo czy myślicie nad dodanie również integrację z falownikiem foxess tak jak jest to z fronius?
Skąd pobierasz tego jsona? Z falownika czy z jakiegoś serwisu w sieci?
Prześlij wszystko co masz zrobione do tej pory.
Dane pobierane są z serwera foxess cloud z pomocą klucza API .Ten kod zwraca mi dane w formie JSON takie jak podałem w pierwszym poscie

Code: Select all

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecureBearSSL.h>
#include <MD5Builder.h>
#include <NTPClient.h>
#include <WiFiUdp.h>

// Dane sieci WiFi
const char* ssid = "xxxxxxx";
const char* password = "xxxxxxxx";

// Dane API FoxESS
const String token = "...";
const String endpoint = "/op/v0/device/real/query";
const String apiURL = "https://www.foxesscloud.com";
const String lang = "en";

// Synchronizacja czasu
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 0, 60000);

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);

  Serial.println("Łączenie z WiFi...");
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }

  Serial.println("\nPołączono z WiFi!");
  Serial.print("Adres IP: ");
  Serial.println(WiFi.localIP());

  // Synchronizacja czasu z NTP
  Serial.println("Synchronizowanie czasu z serwerem NTP...");
  timeClient.begin();
  while (!timeClient.update()) {
    timeClient.forceUpdate();
  }

  unsigned long long timestamp = getCurrentUTCTimestamp();
  Serial.print("Czas UTC (ms): ");
  Serial.println(timestamp);

  // Generowanie sygnatury
  String signature = generateSignature(endpoint, token, timestamp);

  // Wysyłanie żądania do API
  connectToAPI(endpoint, timestamp, signature);
}

void loop() {
  // Nic w pętli głównej
}

String generateSignature(const String& endpoint, const String& token, unsigned long long timestamp) {
  // Generowanie danych do sygnatury
  String data = endpoint + "\\r\\n" + token + "\\r\\n" + String(timestamp);

  Serial.println("\n--- Generowanie sygnatury ---");
  Serial.println("Dane wejściowe do MD5 (zwróć uwagę na białe znaki):");
  Serial.println("----------------------------------------------------");
  Serial.println("[endpoint]: '" + endpoint + "'");
  Serial.println("[token]: '" + token + "'");
  Serial.println("[timestamp]: '" + String(timestamp) + "'");
  Serial.println("[full data]: '" + data + "'");
  Serial.println("----------------------------------------------------");

  // Generowanie sygnatury MD5
  MD5Builder md5;
  md5.begin();
  md5.add(data);
  md5.calculate();
  String signature = md5.toString();

  Serial.println("Wygenerowana sygnatura MD5: " + signature);
  return signature;
}

unsigned long long getCurrentUTCTimestamp() {
  return static_cast<unsigned long long>(timeClient.getEpochTime()) * 1000;
}

void connectToAPI(const String& endpoint, unsigned long long timestamp, const String& signature) {
  std::unique_ptr<BearSSL::WiFiClientSecure> client(new BearSSL::WiFiClientSecure);
  client->setInsecure();

  HTTPClient http;
  String url = apiURL + endpoint;

  Serial.println("\n--- Wysyłanie żądania do API ---");
  Serial.println("URL: " + url);

  if (http.begin(*client, url)) {
    http.addHeader("Content-Type", "application/json");
    http.addHeader("signature", signature);
    http.addHeader("token", token);
    http.addHeader("lang", lang);
    http.addHeader("timestamp", String(timestamp));

    // Puste ciało zapytania
    String postData = "{}";

    Serial.println("Nagłówki:");
    Serial.println("[Content-Type]: application/json");
    Serial.println("[signature]: " + signature);
    Serial.println("[token]: " + token);
    Serial.println("[lang]: " + lang);
    Serial.println("[timestamp]: " + String(timestamp));
    Serial.println("Ciało żądania: " + postData);

    int httpResponseCode = http.POST(postData);

    if (httpResponseCode > 0) {
      Serial.print("Kod HTTP: ");
      Serial.println(httpResponseCode);
      Serial.println("Odpowiedź serwera:");
      Serial.println(http.getString());
    } else {
      Serial.print("Błąd HTTP: ");
      Serial.println(httpResponseCode);
    }

    http.end();
  } else {
    Serial.println("Błąd inicjalizacji połączenia HTTPS.");
  }
}
 
Juszczaczek1
Posts: 389
Joined: Sun Nov 08, 2020 3:41 pm
Been thanked: 2 times

Post

klew wrote: Tue Jan 21, 2025 9:03 pm Myślę że bez problemu można to pokazać jako licznik energii na sd4linux z użyciem parsera json.
Tylko wszystkich danych tam nie wrzucisz. Jeśli coś byś chciał dołożyć z tych co licznik energii u nas nie ma, to można na jakimś kanale kpop dać
Jakie dane mogę wrzucić na kanał licznik energii?
User avatar
klew
Posts: 13909
Joined: Thu Jun 27, 2019 12:16 pm
Location: Wrocław
Has thanked: 135 times
Been thanked: 137 times

Post

Juszczaczek1 wrote: Wed Jan 29, 2025 9:22 am
klew wrote: Tue Jan 21, 2025 9:03 pm Myślę że bez problemu można to pokazać jako licznik energii na sd4linux z użyciem parsera json.
Tylko wszystkich danych tam nie wrzucisz. Jeśli coś byś chciał dołożyć z tych co licznik energii u nas nie ma, to można na jakimś kanale kpop dać
Jakie dane mogę wrzucić na kanał licznik energii?
Od tej linijki:
https://github.com/SUPLA/supla-device/b ... eter.h#L73
do linii ~175 są settery. Masz opisane w komentarzu jaki format danych przyjmuje.
Najlepsze suple dla Twojego domu :mrgreen:
Juszczaczek1
Posts: 389
Joined: Sun Nov 08, 2020 3:41 pm
Been thanked: 2 times

Post

czego brakuje w tym kodzie ? W supla pojawia się kanał licznik energii wyświetla się całkowita produkcja i nic więcej .

Code: Select all

#include <SuplaDevice.h>
#include "foxess.h"
#include <supla/network/esp_wifi.h>

// Dane WiFi
const char* ssid = "xxxxxx";
const char* password = "xxxxxxx";

// Połączenie Wi-Fi
Supla::ESPWifi wifi(ssid, password);

// Zmienna przechowująca czas ostatniego zapytania
unsigned long lastRequestTime = 0;
const unsigned long requestInterval = 60000;  // Interwał 1 minuta (60 000 ms)

// Deklaracja obiektu foxess
Supla::PV::FoxESS* foxess;

void setup() {
  Serial.begin(115200);
  delay(1000); // Czekanie na uruchomienie

  // Inicjalizacja Wi-Fi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Łączenie z Wi-Fi...");
  }
  Serial.println("Połączono z Wi-Fi!");

  // GUID urządzenia (z komunikatu)
  char GUID[SUPLA_GUID_SIZE] = {0xB3,0x73,0xBC,0xFB,0xF8,0x08,0x0B,0xBB,0x20,0x09,0xE5,0x88,0x1C,0x78,0xC0,0xF7};
  char AUTHKEY[SUPLA_AUTHKEY_SIZE] = {0xD1,0xD5,0x47,0x8F,0x93,0xA5,0xFF,0x01,0x03,0x4B,0xBB,0xCC,0xE5,0xA8,0x76,0xF3};

  // Dodanie urządzenia FoxESS (tu musisz podać odpowiednie dane)
  foxess = new Supla::PV::FoxESS("xxxxxxxxxxxxxxxxxxxxxxxxxxx", "/op/v0/device/real/query", "https://www.foxesscloud.com");

  // Inicjalizacja urządzenia Supla
  SuplaDevice.begin(GUID, "svrxx.supla.org", "xxxxxxxx", AUTHKEY);
}

void loop() {
  unsigned long currentMillis = millis();

  // Jeśli minęła jedna minuta od ostatniego zapytania
  if (currentMillis - lastRequestTime >= requestInterval) {
    // Zapisz czas, kiedy wysyłamy zapytanie
    lastRequestTime = currentMillis;

    // Wysyłanie zapytania do FoxESS API niezależnie od odpowiedzi
    foxess->iterateAlways();  // Zaktualizuj dane z API FoxESS

    // Możesz także wywołać SuplaDevice.iterate() jeśli chcesz aktualizować urządzenie Supla
    SuplaDevice.iterate();
  }

  // Opcjonalnie, jeśli chcesz dodać inne operacje, np. aktualizację stanu urządzenia
}
plik .h

Code: Select all

#ifndef SRC_SUPLA_PV_FOXESS_H_
#define SRC_SUPLA_PV_FOXESS_H_

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecureBearSSL.h>
#include <MD5Builder.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <ArduinoJson.h>
#include <supla/sensor/one_phase_electricity_meter.h>  // Dodano nagłówek

namespace Supla {
namespace PV {

class FoxESS : public Supla::Sensor::OnePhaseElectricityMeter {  // Dziedziczenie po OnePhaseElectricityMeter
 public:
  FoxESS(const String& token, const String& endpoint, const String& apiURL);
  void iterateAlways();
  void readValuesFromDevice();

 protected:
  String token;
  String endpoint;
  String apiURL;
  unsigned long long getCurrentUTCTimestamp();
  String generateSignature(unsigned long long timestamp);
  void connectToAPI(unsigned long long timestamp, const String& signature);

 private:
  WiFiUDP ntpUDP;
  NTPClient timeClient;
  float totalGeneratedEnergy;
  float currentPower;
  bool dataFetchInProgress;
  void parseResponse(const String& response);
};

};  // namespace PV
};  // namespace Supla

#endif  // SRC_SUPLA_PV_FOXESS_H_
plik .cpp

Code: Select all

#include "foxess.h"
#include <supla/log_wrapper.h>
#include <supla/time.h>

namespace Supla {
namespace PV {

FoxESS::FoxESS(const String& token, const String& endpoint, const String& apiURL)
    : token(token),
      endpoint(endpoint),
      apiURL(apiURL),
      timeClient(ntpUDP, "pool.ntp.org", 0, 60000),
      totalGeneratedEnergy(0),
      currentPower(0),
      dataFetchInProgress(false) {
  timeClient.begin();
}

unsigned long long FoxESS::getCurrentUTCTimestamp() {
  // Czekamy na synchronizację z serwerem NTP
  while (!timeClient.update()) {
    timeClient.forceUpdate();
  }
  // Zwracamy czas w formacie milisekundowym
  return static_cast<unsigned long long>(timeClient.getEpochTime()) * 1000;
}

String FoxESS::generateSignature(unsigned long long timestamp) {
  // Tworzymy dane do wygenerowania podpisu
  String data = endpoint + "\\r\\n" + token + "\\r\\n" + String(timestamp);
  MD5Builder md5;
  md5.begin();
  md5.add(data);
  md5.calculate();
  return md5.toString();
}

void FoxESS::connectToAPI(unsigned long long timestamp, const String& signature) {
  std::unique_ptr<BearSSL::WiFiClientSecure> client(new BearSSL::WiFiClientSecure);
  client->setInsecure();  // Bezpieczne połączenie (brak weryfikacji certyfikatu)

  HTTPClient http;
  String url = apiURL + endpoint;

  if (http.begin(*client, url)) {
    // Ustawienie nagłówków
    http.addHeader("Content-Type", "application/json");
    http.addHeader("signature", signature);
    http.addHeader("token", token);
    http.addHeader("lang", "en");
    http.addHeader("timestamp", String(timestamp));

    String postData = "{}";  // Wysłanie pustego ciała (POST)

    // Wykonanie zapytania HTTP
    int httpResponseCode = http.POST(postData);

    if (httpResponseCode > 0) {
      String response = http.getString();
      SUPLA_LOG_DEBUG("HTTP Response: %s", response.c_str());
      parseResponse(response);
    } else {
      SUPLA_LOG_DEBUG("HTTP Error: %d", httpResponseCode);
    }

    http.end();
  }
}

void FoxESS::parseResponse(const String& response) {
  // Parsowanie odpowiedzi JSON
  DynamicJsonDocument doc(8192);
  DeserializationError error = deserializeJson(doc, response);

  if (error) {
    SUPLA_LOG_DEBUG("JSON Parse Error: %s", error.c_str());
    return;
  }

  if (doc["errno"].as<int>() != 0) {
    SUPLA_LOG_DEBUG("API Error: %s", doc["msg"].as<const char*>());
    return;
  }

  JsonArray datas = doc["result"][0]["datas"].as<JsonArray>();
  for (JsonObject data : datas) {
    String variable = data["variable"].as<String>();

    if (variable == "generation") {
      totalGeneratedEnergy = data["value"].as<float>();
      setFwdActEnergy(0, totalGeneratedEnergy * 100000);
    } else if (variable == "generationPower") {
      currentPower = data["value"].as<float>();
      setPowerActive(0, currentPower * 100000);
    }
  }

  updateChannelValues();
}

void FoxESS::iterateAlways() {
  if (!dataFetchInProgress) {
    // Pobieramy znacznik czasu
    unsigned long long timestamp = getCurrentUTCTimestamp();
    String signature = generateSignature(timestamp);
    connectToAPI(timestamp, signature);
    dataFetchInProgress = true;
  }
}

void FoxESS::readValuesFromDevice() {
  // Obsługuje odczyty w iterateAlways
}

};  // namespace PV
};  // namespace Supla
logi

Code: Select all

Łączenie z Wi-Fi...
Łączenie z Wi-Fi...
Łączenie z Wi-Fi...
Połączono z Wi-Fi!
Supla - starting initialization (platform 0)
Main storage not configured
Config storage not configured
GUID: B373BCFBF8080BBB2009E5881C78C0F7
Device name: SUPLA-ESP8266
Device software version: SDK 24.11.04-dev
Initializing network layer
[Wi-Fi] Network AP/hostname: SUPLA-ESP8266-5CCF7F61B18A
Using Supla protocol version 23
Current status: [5] SuplaDevice initialized
Enter normal mode
HTTP Response: {"errno":0,"msg":"success","result":[{"datas":[{"unit":"kW","name":"Today’s power generation","variable":"todayYield","value":8.1},{"unit":"kW","name":"PVPower","variable":"pvPower","value":0.0},{"unit":"V","name":"PV1Volt","variable":"pv1Volt","value":234.2},{"unit":"A","name":"PV1Current","variable":"pv1Current","value":0.0},{"unit":"kW","name":"PV1Power","variable":"pv1Power","value":0.0},{"unit":"V","name":"PV2Volt","variable":"pv2Volt","value":0.0},{"unit":"A","name":"PV2Current","variable":"pv2Current","value":0.0},{"unit":"kW","name":"PV2Power","variable":"pv2Power","value":0.0},{"unit":"V","name":"PV3Volt","variable":"pv3Volt","value":0.0},{"unit":"A","name":"PV3Current","variable":"pv3Current","value":0.0},{"unit":"kW","name":"PV3Power","variable":"pv3Power","value":0.0},{"unit":"V","name":"PV4Volt","variable":"pv4Volt","value":0.0},{"unit":"A","name":"PV4Current","variable":"pv4Current","value":0.0},{"unit":"kW","name":"PV4Power","variable":"pv4Power","value":0.0},{"unit":"A","name":"RCurrent","variable":"RCurrent","value":0.8},{"unit":"V","name":"RVolt","variable":"RVolt","value":233.1},{"unit":"Hz","name":"RFreq","variable":"RFreq","value":49.97},{"unit":"kW","name":"RPower","variable":"RPower","value":0.0},{"unit":"A","name":"SCurrent","variable":"SCurrent","value":0.8},{"unit":"V","name":"SVolt","variable":"SVolt","value":228.5},{"unit":"Hz","name":"SFreq","variable":"SFreq","value":49.97},{"unit":"kW","name":"SPower","variable":"SPower","value":0.0},{"unit":"A","name":"TCurrent","variable":"TCurrent","value":0.8},{"unit":"V","name":"TVolt","variable":"TVolt","value":232.0},{"unit":"Hz","name":"TFreq","variable":"TFreq","value":49.97},{"unit":"kW","name":"TPower","variable":"TPower","value":0.0},{"unit":"℃","name":"AmbientTemperature","variable":"ambientTemperation","value":21.0},{"unit":"℃","name":"BoostTemperature","variable":"boostTemperation","value":10.0},{"unit":"℃","name":"InvTemperation","variable":"invTemperation","value":10.0},{"unit":"kW","name":"Load Power","variable":"loadsPower","value":0.0},{"unit":"kW","name":"Output Power","variable":"generationPower","value":0.0},{"unit":"kW","name":"Feed-in Power","variable":"feedinPower","value":0.0},{"unit":"kW","name":"GridConsumption Power","variable":"gridConsumptionPower","value":0.0},{"unit":"kWh","name":"Cumulative power generation","variable":"generation","value":10660.5},{"name":"Running State","variable":"runningState","value":"170"},{"name":"The current error code is reported","variable":"currentFault","value":""},{"name":"The number of errors","variable":"currentFaultCount","value":"0"}],"time":"2025-01-29 16:43:01 CET+0100","deviceSN":"60AT103021RC037"}]}
WiFi: establishing connection with SSID: "Comnet_421AAC"
Connecting without certificate validation (INSECURE)
Establishing encrypted connection with: svr50.supla.org (port: 2016)
Connected via IP 192.168.18.57
Connected to Supla Server
Initializing SRPC (proto: 23)
Current status: [10] Register in progress
Send: [53 55 50 4C 41 17 01 00 00 00 4B 00 00 00 6B 02 00 00 6A 75 73 7A 63 7A 61 6B 70 61 77 65 6C 40 6F 70 2E 70 6C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 D1 D5 47 8F 93 A5 FF 01 03 4B BB CC E5 A8 76 F3 B3 73 BC FB F8 08 0B BB 20 09 E5 88 1C 78 C0 F7 53 55 50 4C 41 2D 45 53 50 38 32 36 36 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ]
CH[0], type: 5000, FuncList: 0x0, function: 310, flags: 0xD2000, online, validityTimeSec: 0, icon: 0, value: [00 41 44 10 00 00 00 00]
Send: [00 88 13 00 00 00 00 00 00 36 01 00 00 00 20 0D 00 00 00 00 00 00 00 00 00 00 00 41 44 10 00 00 00 00 00 ]
Send: [53 55 50 4C 41 ]
User avatar
klew
Posts: 13909
Joined: Thu Jun 27, 2019 12:16 pm
Location: Wrocław
Has thanked: 135 times
Been thanked: 137 times

Post

Juszczaczek1 wrote: Wed Jan 29, 2025 5:41 pm czego brakuje w tym kodzie ? W supla pojawia się kanał licznik energii wyświetla się całkowita produkcja i nic więcej .
Na moje oko to brakuje tu programisty, który by to zaimplementował :P

Nie da się programować z "AI", jeśli się samemu by nie umiało tego samego zrobić. To są narzędzia, które potrafią przyspieszyć pracę, którą potrafilibyśmy zrobić samemu. Przynajmniej na obecnym etapie.
etd6w8foqr9b1.png
Jak będę miał chwilę czasu, to ten temat ogarnę. Może ktoś szybciej to zrobi?
You do not have the required permissions to view the files attached to this post.
Najlepsze suple dla Twojego domu :mrgreen:
Juszczaczek1
Posts: 389
Joined: Sun Nov 08, 2020 3:41 pm
Been thanked: 2 times

Post

Ok, spokojnie nie ma pośpiechu . Programisty jak najbardziej tu brakuje 😝
Juszczaczek1
Posts: 389
Joined: Sun Nov 08, 2020 3:41 pm
Been thanked: 2 times

Post

Udało mi się zmusić chat aby stworzył mi kod ale jedna rzecz mi się nie zgadza. Chodzi o moc czynną, teraz gdy już nie nie ma produkcji API zwraca moc czynną 0.00kw tyle też jest wysłane do supla ale w aplikacji mam 1,00W gdzie jest popełniony błąd? Mam aplikacje beta najnowsza w której są wykresy m.in. mocy czynnej.
User avatar
klew
Posts: 13909
Joined: Thu Jun 27, 2019 12:16 pm
Location: Wrocław
Has thanked: 135 times
Been thanked: 137 times

Post

Jeśli pokazuje 1 W, to znaczy że tyle wysyła urządzenie.
Najlepsze suple dla Twojego domu :mrgreen:
Juszczaczek1
Posts: 389
Joined: Sun Nov 08, 2020 3:41 pm
Been thanked: 2 times

Post

Potrzebuje pomocy, chodzi o kanał licznika energii . Chce widzieć napięcie i moc na każdej fazie dlatego muszą być 3 kanały i tak mam zrobione ale nie wiem co muszę zrobić aby widzieć dane o całkowitej produkcji i mocy , chodzi oczywiście o produkcję pv. Dane pobierane są z API .

Return to “Pomoc”