Esp8266
Posted: Wed Jan 08, 2025 7:29 pm
Witam udało się komuś napisać kod na esp8266 do komunikacji z falownikiem za pomocą API?
This is a private, informal group designed as a support network for all FoxESS owners and installers
https://foxesscommunity.com/
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();
}
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
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();
}
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'
}
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' }
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"
}
}