Esp8266
-
- 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?
-
- 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
6 x HV2600 v2 batteries
16 x JA Solar 405w panels
7 x Tigo TS4-A-O optimisers
-
- 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
6 x HV2600 v2 batteries
16 x JA Solar 405w panels
7 x Tigo TS4-A-O optimisers
-
- 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();
}
-
- 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
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
-
- Posts: 1557
- Joined: Thu Oct 13, 2022 7:21 pm
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.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
Is your getEpochTime() taking into account the local timezone the requests are being made from ?
-
- 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();
}
-
- 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
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)
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'
}
-
- 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"
-
- Posts: 12
- Joined: Wed Jan 08, 2025 7:24 pm
Masz cały gotowy kod na pythonie do komunikacji z foxess cloud ? Udostępnisz?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
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)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' }
-
- 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..
The similar call you are making I make in GetRaw() which uses the base class GetAuth() to build the headers and signature md5 etc..
-
- Posts: 12
- Joined: Wed Jan 08, 2025 7:24 pm
Kombinuje już na wszystkie sposoby za pomocną chatgpt i chyba sobie odpisze ta integrację:-(
-
- 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"
}
}