Esp8266

Post Reply
Juszczaczek1
Posts: 12
Joined: Wed Jan 08, 2025 7:24 pm

Witam udało się komuś napisać kod na esp8266 do komunikacji z falownikiem za pomocą API?
tony.matthews1
Posts: 20
Joined: Sun Mar 19, 2023 4:37 pm

No, I have not heard of anyone doing this.
H1-6.0-E hybrid inverter
6 x HV2600 v2 batteries
16 x JA Solar 405w panels
7 x Tigo TS4-A-O optimisers
tony.matthews1
Posts: 20
Joined: Sun Mar 19, 2023 4:37 pm

Not using Open API, but this may be of interest: https://github.com/assembly12/Foxess-T- ... ware-setup
H1-6.0-E hybrid inverter
6 x HV2600 v2 batteries
16 x JA Solar 405w panels
7 x Tigo TS4-A-O optimisers
Juszczaczek1
Posts: 12
Joined: Wed Jan 08, 2025 7:24 pm

Code: Select all

#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <MD5Builder.h>
#include <ArduinoJson.h>
#include <NTPClient.h>
#include <WiFiUdp.h>

// Dane Wi-Fi
const char* ssid = "xxxxxxx";
const char* password = "xxxxxxxx";

// Dane API FoxESS
const char* apiHost = "www.foxesscloud.com";
const int apiPort = 443;
const char* apiEndpoint = "/op/v0/device/history/query";  // Endpoint history
const char* apiKey = "xxxxxxxxxx";
const char* deviceSerialNumber = "xxxxxxxxx";

// Ustawienia NTP
WiFiUDP udp;
NTPClient timeClient(udp, "pool.ntp.org", 0, 3600); // Synchronizacja z NTP

WiFiClientSecure client;

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

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

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

  timeClient.begin();
  timeClient.update();

  client.setInsecure();  // Ignorowanie certyfikatów SSL
}

void loop() {
  if (WiFi.status() == WL_CONNECTED) {
    if (client.connect(apiHost, apiPort)) {
      // Pobieranie aktualnego czasu NTP w milisekundach
      unsigned long timestamp = timeClient.getEpochTime() * 1000;  // Czas w milisekundach

      String signature = generateSignature(apiEndpoint, apiKey, timestamp);

      String requestBody = "{\"deviceSn\":\"" + String(deviceSerialNumber) + "\"}";

      client.println("POST " + String(apiEndpoint) + " HTTP/1.1");
      client.println("Host: " + String(apiHost));
      client.println("Content-Type: application/json");
      client.println("token: " + String(apiKey));
      client.println("timestamp: " + String(timestamp));  // Używamy czasu w milisekundach
      client.println("signature: " + signature);
      client.println("lang: en");
      client.println("Content-Length: " + String(requestBody.length()));
      client.println("Connection: close");
      client.println();
      client.println(requestBody);

      String response;
      while (client.connected() || client.available()) {
        if (client.available()) {
          response += client.readString();
        }
      }
      client.stop();

      Serial.println("Odpowiedź serwera:");
      Serial.println(response);

      int bodyIndex = response.indexOf("\r\n\r\n");
      if (bodyIndex > 0) {
        String responseBody = response.substring(bodyIndex + 4);
        StaticJsonDocument<1024> jsonResponse;
        DeserializationError error = deserializeJson(jsonResponse, responseBody);

        if (!error) {
          float voltage = jsonResponse["result"]["data"]["voltage"];
          Serial.print("Napięcie: ");
          Serial.println(voltage);
        } else {
          Serial.println("Błąd parsowania JSON");
        }
      }
    } else {
      Serial.println("Nie udało się połączyć z serwerem API.");
    }
  } else {
    Serial.println("Brak połączenia z WiFi.");
  }

  delay(60000);  // Odczekaj minutę przed kolejnym zapytaniem
}

String generateSignature(const char* url, const char* token, unsigned long timestamp) {
  String data = String(url) + "\r\n" + String(token) + "\r\n" + String(timestamp);
  MD5Builder md5;
  md5.begin();
  md5.add(data);
  md5.calculate();
  return md5.toString();
}
 
Może ktoś sprawdzić dlaczego mi nie działa ten kod?
Juszczaczek1
Posts: 12
Joined: Wed Jan 08, 2025 7:24 pm

Taki błąd mi zwraca
HTTP/1.1 200 OK
content-type: application/json;charset=utf-8
content-length: 81
date: Sat, 11 Jan 2025 12:27:50 GMT
x-envoy-upstream-service-time: 6
server: istio-envoy
connection: close

{"errno":40256,"msg":"Parameter could not be parsed correctly illegal timestamp"}
Napięcie: 0.00
Dave Foster
Posts: 1557
Joined: Thu Oct 13, 2022 7:21 pm

Juszczaczek1 wrote: Sat Jan 11, 2025 1:32 pm Taki błąd mi zwraca
HTTP/1.1 200 OK
content-type: application/json;charset=utf-8
content-length: 81
date: Sat, 11 Jan 2025 12:27:50 GMT
x-envoy-upstream-service-time: 6
server: istio-envoy
connection: close

{"errno":40256,"msg":"Parameter could not be parsed correctly illegal timestamp"}
Napięcie: 0.00
If it is reporting illegal timestamp, then likely your timestamp (which appears to be constructed correctly) may be more than 60 seconds out - that's the response you will get when it is wrong.
Is your getEpochTime() taking into account the local timezone the requests are being made from ?
Juszczaczek1
Posts: 12
Joined: Wed Jan 08, 2025 7:24 pm

Dzięki za podpowiedź poprawiłem kod ale mam teraz błąd nie udało się połączyć z serwerem API

Code: Select all

#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <MD5Builder.h>
#include <NTPClient.h>
#include <WiFiUdp.h>

// Dane Wi-Fi
const char* ssid = "xxxxxx";
const char* password = "xxxxxxxx";

// Dane API FoxESS
const char* apiHost = "www.foxesscloud.com";
const int apiPort = 443;
const char* apiEndpoint = "/op/v0/device/real/query";
const char* apiKey = "xxxxxxxx";
const char* deviceSerialNumber = "xxxxxxxxxxx";

WiFiClientSecure client;
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", 3600, 60000); // UTC+1 dla Polski

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

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

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

  // Inicjalizacja klienta NTP
  timeClient.begin();
  timeClient.update();
}

void loop() {
  if (WiFi.status() == WL_CONNECTED) {
    if (client.connect(apiHost, apiPort)) {
      // Pobranie aktualnego czasu z NTP
      timeClient.update();
      unsigned long timestamp = timeClient.getEpochTime();

      // Generowanie podpisu
      String signature = generateSignature(apiEndpoint, apiKey, timestamp);

      // Tworzenie treści żądania
      String requestBody = "{\"deviceSn\":\"" + String(deviceSerialNumber) + "\"}";

      // Wysyłanie żądania HTTP POST
      client.println("POST " + String(apiEndpoint) + " HTTP/1.1");
      client.println("Host: " + String(apiHost));
      client.println("Content-Type: application/json");
      client.println("token: " + String(apiKey));
      client.println("timestamp: " + String(timestamp));
      client.println("signature: " + signature);
      client.println("lang: en");
      client.println("Content-Length: " + String(requestBody.length()));
      client.println("Connection: close");
      client.println();
      client.println(requestBody);

      // Odbieranie odpowiedzi
      String response;
      while (client.connected() || client.available()) {
        if (client.available()) {
          response += client.readString();
        }
      }
      client.stop();

      Serial.println("Odpowiedź serwera:");
      Serial.println(response);

      // Przetwarzanie odpowiedzi JSON
      int bodyIndex = response.indexOf("\r\n\r\n");  // Znajdź początek ciała odpowiedzi
      if (bodyIndex > 0) {
        String responseBody = response.substring(bodyIndex + 4);
        StaticJsonDocument<1024> jsonResponse;
        DeserializationError error = deserializeJson(jsonResponse, responseBody);

        if (!error) {
          // Pobranie przykładowej wartości
          float voltage = jsonResponse["result"]["data"]["voltage"];
          Serial.print("Napięcie: ");
          Serial.println(voltage);
        } else {
          Serial.println("Błąd parsowania JSON");
        }
      }
    } else {
      Serial.println("Nie udało się połączyć z serwerem API.");
    }
  } else {
    Serial.println("Brak połączenia z WiFi.");
  }

  delay(60000);  // Odczekaj minutę przed kolejnym zapytaniem
}

String generateSignature(const char* url, const char* token, unsigned long timestamp) {
  String data = String(url) + "\r\n" + String(token) + "\r\n" + String(timestamp);
  MD5Builder md5;
  md5.begin();
  md5.add(data);
  md5.calculate();
  return md5.toString();
}
 
Dave Foster
Posts: 1557
Joined: Thu Oct 13, 2022 7:21 pm

Have you had any luck getting this working ?

The code looks ok, but be useful to see the exact response you get.

admittedly in python, but this is what I use for headers (token=apikey) which works fine, I don't include the Content-Length as you do

Code: Select all

        timestamp = round(time.time() * 1000)
        signature = fr'{path}\r\n{token}\r\n{timestamp}'
        # or use user_agent_rotator.get_random_user_agent() for user-agent
        result = {
            'token': token,
            'lang': lang,
            'timestamp': str(timestamp),
            'Content-Type': 'application/json',
            'signature': self.md5c(text=signature),
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                          'Chrome/117.0.0.0 Safari/537.36',
            'Connection': 'close'
        }
In the signature the \r\n must be included within the string as the characters '\r\n' and not encoded as their escape characters (CR,LF)
Juszczaczek1
Posts: 12
Joined: Wed Jan 08, 2025 7:24 pm

Wgrywając mój kod w monitorze szeregowym zwraca mi jedynie "nie udało się połączyć z serwerem API"
Juszczaczek1
Posts: 12
Joined: Wed Jan 08, 2025 7:24 pm

Dave Foster wrote: Sun Jan 12, 2025 12:14 pm Have you had any luck getting this working ?

The code looks ok, but be useful to see the exact response you get.

admittedly in python, but this is what I use for headers (token=apikey) which works fine, I don't include the Content-Length as you do

Code: Select all

        timestamp = round(time.time() * 1000)
        signature = fr'{path}\r\n{token}\r\n{timestamp}'
        # or use user_agent_rotator.get_random_user_agent() for user-agent
        result = {
            'token': token,
            'lang': lang,
            'timestamp': str(timestamp),
            'Content-Type': 'application/json',
            'signature': self.md5c(text=signature),
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                          'Chrome/117.0.0.0 Safari/537.36',
            'Connection': 'close'
        }
In the signature the \r\n must be included within the string as the characters '\r\n' and not encoded as their escape characters (CR,LF)
Masz cały gotowy kod na pythonie do komunikacji z foxess cloud ? Udostępnisz?
Dave Foster
Posts: 1557
Joined: Thu Oct 13, 2022 7:21 pm

Yes everything i’ve written is in here, this is the home assistant cloud integration code - https://github.com/macxq/foxess-ha/blo ... /sensor.py

The similar call you are making I make in GetRaw() which uses the base class GetAuth() to build the headers and signature md5 etc..
Juszczaczek1
Posts: 12
Joined: Wed Jan 08, 2025 7:24 pm

Kombinuje już na wszystkie sposoby za pomocną chatgpt i chyba sobie odpisze ta integrację:⁠-⁠(
Juszczaczek1
Posts: 12
Joined: Wed Jan 08, 2025 7:24 pm

Dlaczego ten kod nie zwraca mi danych

Code: Select all

# Ustawienie parametrów
$deviceSN = "xxxxxxxxx"  # Numer seryjny urządzenia
$token = "xxxxxxxxxx"  # Twój token API
$timestamp = (Get-Date -UFormat "%s") * 1000  # Aktualny timestamp w milisekundach
$path = "/op/v0/device/real/query"  # Ścieżka do API

# Połącz dane do generowania sygnatury
$dataToSign = "$path`r`n$token`r`n$timestamp"

# Generowanie sygnatury MD5
$signature = [BitConverter]::ToString([System.Security.Cryptography.MD5]::Create().ComputeHash([System.Text.Encoding]::UTF8.GetBytes($dataToSign))).Replace("-", "").ToLower()

# Przygotowanie nagłówków
$headers = @{
    'Token' = $token
    'Lang' = 'en'
    'User-Agent' = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
    'Timezone' = 'Europe/London'
    'Timestamp' = $timestamp
    'Content-Type' = 'application/json'
    'Signature' = $signature  # Sygnatura wygenerowana powyżej
}

# Przygotowanie ciała zapytania
$body = @{
    deviceSN = $deviceSN
} | ConvertTo-Json -Compress

# Wyświetlenie ciała zapytania (debugowanie)
Write-Output "Ciało zapytania: $body"

# Wykonanie zapytania HTTP do API FoxESS
try {
    $response = Invoke-RestMethod -Uri "https://www.foxesscloud.com/op/v0/device/real/query" -Method Post -Headers $headers -Body $body -ContentType "application/json"
    Write-Output "Odpowiedź: $($response | ConvertTo-Json)"
} catch {
    Write-Output "Błąd: $($_.Exception.Message)"
    
    if ($_.Exception.Response) {
        # Zapisz strumień odpowiedzi w zmiennej, aby go wyświetlić
        $responseStream = $_.Exception.Response.GetResponseStream()
        $reader = New-Object System.IO.StreamReader($responseStream)
        $responseText = $reader.ReadToEnd()
        Write-Output "Treść odpowiedzi: $responseText"
    } else {
        Write-Output "Brak odpowiedzi z serwera"
    }
} 
Post Reply