Może komuś udało się uzyskać komunikacje z tym inwerterem? Mam przygotowany zestaw, kabel USB A do konwertera rs232 do ttl esp32. Zapytania gmod\r itd. Odpowiedź jest, ale same krzaki.
Typowy objaw niedopasowania prędkości portów szeregowych. Sprawdź ustawienia UARTa.
Sprawdziłem już wszystkie kombinacje RX/TX po obu stronach z prędkością od 2400 do 19200 .
Kombinacja RX/TX jest tylko jedna - ta która działa, ta druga nie działa.
UART oprócz prędkości ma też inne ustawienia - długość słowa, parzystośc i bit stopu.
Robisz to na podstawie jakiejkolwiek dokumentacji (gdzie jest link, gdzie są zdjęcia) lub masz jako-takie doświadczenie by rozpoznać (np. na podstawie konstrukcji płyty głównej) gdzie się podpinasz i czy to w ogóle jest RS232?
Inwerter ma gniazdo USB A. Pinout mam z githuba.
red - +5v
white - RX inv
green - TX inv
black - GND
Rx do gnd i tx do gnd ±10V. Czyli raczej rs232. Podłączone też standardowe jak w innych projektach.
id: jd_uart
tx_pin: ${uart_tx_pin}
rx_pin: ${uart_rx_pin}
baud_rate: 2400
stop_bits: 1
data_bits: 8
parity: NONE
Podaj może repo z którego korzstasz.
To coś nie jest YAMLem (źle wklejasz), w każdym razie taka konstrukcja tx_pin: ${uart_tx_pin} wymaga definicji pinu przez Substitutions
8N1 wydaje się być dość typowe, napięcia sugerują RS232, ale więcej pewności byś nabrał analizując płytę główną (musi mieć transceiver RS232)
między ESP32 a inwerterem masz moduł MAX3232? Bez niego komunikacja nie zadziała poprawnie.
ma
To jakiś eufemizm - MCU po prostu dym wypuści.
esphome:
name: jsdsolar
friendly_name: jsdsolar
esp32:
board: esp32dev
framework:
type: esp-idflogger:
level: VERY_VERBOSE
api:
encryption:
key: ""ota:
platform: esphome
password: “”
web_server:
port: 80
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
ap:
ssid: "Jsdsolar Fallback Hotspot" password: "cLrUqMuwMunB"captive_portal:
uart:
id: uart_jsd
tx_pin: GPIO18
rx_pin: GPIO19
baud_rate: 2400
data_bits: 8
stop_bits: 1
parity: NONE
interval:
interval: 5s
then:
uart.write: “GBAT\r”
delay: 1500ms
uart.write: “GMOD\r”
interval: 1s
then:
lambda: |-
std::string str = “”;
while (id(uart_jsd).available()) {
char c; id(uart_jsd).read_byte((uint8_t\*)&c); str += c;}
if (!str.empty()) {
ESP_LOGD("UART", "%s", str.c_str());}
Jak prawidłowo zamieszczać YAML, inny kod lub logi w postach na forum
To issue to piękny przykład dlaczego nie pisać na githubie po polsku, ukraińsku, czy chińsku…
ale OK widzę z jakiego YAMLa wystartowałeś
substitutions:
hostname: jdsolar-j5500hpc
device_name: "Jdsolar J5500HPC"
uart_rx_pin: GPIO16
uart_tx_pin: GPIO17
esphome:
name: ${hostname}
friendly_name: ${device_name}
esp32:
board: esp32dev
framework:
type: arduino
logger:
level: DEBUG
baud_rate: 0
api:
encryption:
key: !secret api_key
ota:
- platform: esphome
password: !secret ota_password
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
ap:
ssid: "${hostname} Fallback"
password: "12345678"
captive_portal:
web_server:
port: 80
uart:
- id: jd_uart
tx_pin: ${uart_tx_pin}
rx_pin: ${uart_rx_pin}
baud_rate: 2400
stop_bits: 1
data_bits: 8
parity: NONE
# ========== СЕНСОРИ ==========
sensor:
- platform: uptime
name: "${device_name} Uptime"
- platform: wifi_signal
name: "${device_name} WiFi Signal"
update_interval: 60s
# === БАТАРЕЯ ===
- platform: template
name: "${device_name} Battery Voltage"
id: battery_voltage
unit_of_measurement: "V"
device_class: voltage
state_class: measurement
accuracy_decimals: 1
- platform: template
name: "${device_name} Battery Current"
id: battery_current
unit_of_measurement: "A"
device_class: current
state_class: measurement
accuracy_decimals: 2
- platform: template
name: "${device_name} Battery Cells"
id: battery_cells
state_class: measurement
- platform: template
name: "${device_name} Battery EOD Voltage"
id: battery_eod
unit_of_measurement: "V"
device_class: voltage
state_class: measurement
accuracy_decimals: 1
- platform: template
name: "${device_name} Battery Low Alarm"
id: battery_low_alarm
unit_of_measurement: "V"
device_class: voltage
state_class: measurement
accuracy_decimals: 1
- platform: template
name: "${device_name} Battery Capacity"
id: battery_capacity
unit_of_measurement: "%"
device_class: battery
state_class: measurement
# === МЕРЕЖА ===
- platform: template
name: "${device_name} Grid Voltage"
id: grid_voltage
unit_of_measurement: "V"
device_class: voltage
state_class: measurement
accuracy_decimals: 1
- platform: template
name: "${device_name} Grid Frequency"
id: grid_frequency
unit_of_measurement: "Hz"
device_class: frequency
state_class: measurement
accuracy_decimals: 2
- platform: template
name: "${device_name} Load Percentage"
id: load_percentage
unit_of_measurement: "%"
state_class: measurement
- platform: template
name: "${device_name} Grid Daily Energy"
id: grid_daily_energy
unit_of_measurement: "Wh"
device_class: energy
state_class: total_increasing
- platform: template
name: "${device_name} Grid Total Energy"
id: grid_total_energy
unit_of_measurement: "Wh"
device_class: energy
state_class: total_increasing
# === ВИХІД ===
- platform: template
name: "${device_name} Output Voltage"
id: output_voltage
unit_of_measurement: "V"
device_class: voltage
state_class: measurement
accuracy_decimals: 1
- platform: template
name: "${device_name} Output Frequency"
id: output_frequency
unit_of_measurement: "Hz"
device_class: frequency
state_class: measurement
accuracy_decimals: 2
- platform: template
name: "${device_name} Output Current"
id: output_current
unit_of_measurement: "A"
device_class: current
state_class: measurement
accuracy_decimals: 2
- platform: template
name: "${device_name} Output Power"
id: output_power
unit_of_measurement: "W"
device_class: power
state_class: measurement
- platform: template
name: "${device_name} Output Apparent Power"
id: output_apparent_power
unit_of_measurement: "VA"
device_class: apparent_power
state_class: measurement
- platform: template
name: "${device_name} Output Daily Energy"
id: output_daily_energy
unit_of_measurement: "Wh"
device_class: energy
state_class: total_increasing
- platform: template
name: "${device_name} Output Total Energy"
id: output_total_energy
unit_of_measurement: "Wh"
device_class: energy
state_class: total_increasing
# === PV ===
- platform: template
name: "${device_name} PV Voltage"
id: pv_voltage
unit_of_measurement: "V"
device_class: voltage
state_class: measurement
accuracy_decimals: 1
- platform: template
name: "${device_name} PV Current"
id: pv_current
unit_of_measurement: "A"
device_class: current
state_class: measurement
accuracy_decimals: 2
- platform: template
name: "${device_name} PV Charge Current"
id: pv_charge_current
unit_of_measurement: "A"
device_class: current
state_class: measurement
accuracy_decimals: 2
- platform: template
name: "${device_name} PV Power"
id: pv_power
unit_of_measurement: "W"
device_class: power
state_class: measurement
- platform: template
name: "${device_name} PV Daily Energy"
id: pv_daily_energy
unit_of_measurement: "Wh"
device_class: energy
state_class: total_increasing
- platform: template
name: "${device_name} PV Total Energy"
id: pv_total_energy
unit_of_measurement: "Wh"
device_class: energy
state_class: total_increasing
# === ЗАРЯД ===
- platform: template
name: "${device_name} Bus Voltage"
id: bus_voltage
unit_of_measurement: "V"
device_class: voltage
state_class: measurement
accuracy_decimals: 1
- platform: template
name: "${device_name} Charge Voltage"
id: charge_voltage
unit_of_measurement: "V"
device_class: voltage
state_class: measurement
accuracy_decimals: 1
- platform: template
name: "${device_name} Charge Current"
id: charge_current
unit_of_measurement: "A"
device_class: current
state_class: measurement
accuracy_decimals: 1
- platform: template
name: "${device_name} Max Charge Current"
id: max_charge_current
unit_of_measurement: "A"
device_class: current
state_class: measurement
accuracy_decimals: 2
# === ІНВЕРТОР ===
- platform: template
name: "${device_name} Inverter Voltage"
id: inv_voltage
unit_of_measurement: "V"
device_class: voltage
state_class: measurement
accuracy_decimals: 1
- platform: template
name: "${device_name} Inverter Frequency"
id: inv_frequency
unit_of_measurement: "Hz"
device_class: frequency
state_class: measurement
accuracy_decimals: 2
- platform: template
name: "${device_name} Inverter Current"
id: inv_current
unit_of_measurement: "A"
device_class: current
state_class: measurement
accuracy_decimals: 1
# === ТЕМПЕРАТУРА ===
- platform: template
name: "${device_name} PV Temp"
id: temp_pv
unit_of_measurement: "°C"
device_class: temperature
state_class: measurement
accuracy_decimals: 1
- platform: template
name: "${device_name} Charger Temp"
id: temp_charger
unit_of_measurement: "°C"
device_class: temperature
state_class: measurement
accuracy_decimals: 1
- platform: template
name: "${device_name} Ambient Temp"
id: temp_ambient
unit_of_measurement: "°C"
device_class: temperature
state_class: measurement
accuracy_decimals: 1
- platform: template
name: "${device_name} MPPT1 Temp"
id: temp_mppt1
unit_of_measurement: "°C"
device_class: temperature
state_class: measurement
accuracy_decimals: 1
# === ВЕНТИЛЯТОР ===
- platform: template
name: "${device_name} Fan Speed"
id: fan_speed
unit_of_measurement: "%"
state_class: measurement
- platform: template
name: "${device_name} Fan1 RPM"
id: fan1_rpm
unit_of_measurement: "RPM"
state_class: measurement
- platform: template
name: "${device_name} Fan2 RPM"
id: fan2_rpm
unit_of_measurement: "RPM"
state_class: measurement
# ===== ТЕКСТОВІ СЕНСОРИ =====
text_sensor:
- platform: wifi_info
ip_address:
name: "${device_name} IP"
- platform: template
name: "${device_name} Mode"
id: working_mode
- platform: template
name: "${device_name} Battery Type"
id: battery_type
- platform: template
name: "${device_name} Charge Stage"
id: charge_stage
- platform: template
name: "${device_name} PV Status"
id: pv_status
- platform: template
name: "${device_name} Fault"
id: fault_code
- platform: template
name: "${device_name} Warning"
id: warning_code
# ===== БІНАРНІ СЕНСОРИ =====
binary_sensor:
- platform: template
name: "${device_name} Grid OK"
id: grid_ok
device_class: connectivity
- platform: template
name: "${device_name} PV Charging"
id: pv_charging
device_class: battery_charging
- platform: template
name: "${device_name} Battery Charging"
id: battery_charging
device_class: battery_charging
- platform: template
name: "${device_name} EQ Mode"
id: eq_mode
- platform: template
name: "${device_name} Fan1 Fault"
id: fan1_fault
device_class: problem
- platform: template
name: "${device_name} Fan2 Fault"
id: fan2_fault
device_class: problem
- platform: template
name: "${device_name} Overload"
id: overload
device_class: problem
- platform: template
name: "${device_name} Over Temp"
id: over_temp
device_class: problem
- platform: template
name: "${device_name} Battery Low"
id: battery_low
device_class: problem
# ===== SWITCH =====
switch:
- platform: template
name: "${device_name} Power"
id: inverter_power
optimistic: true
turn_on_action:
- uart.write:
id: jd_uart
data: "SON\r"
turn_off_action:
- uart.write:
id: jd_uart
data: "SOFF\r"
# ===== ОПИТУВАННЯ =====
interval:
- interval: 10s
then:
- uart.write: {id: jd_uart, data: "GBAT\r"}
- delay: 500ms
- uart.write: {id: jd_uart, data: "GLINE\r"}
- delay: 500ms
- uart.write: {id: jd_uart, data: "GOP\r"}
- delay: 500ms
- uart.write: {id: jd_uart, data: "GPV\r"}
- delay: 500ms
- uart.write: {id: jd_uart, data: "GCHG\r"}
- delay: 500ms
- uart.write: {id: jd_uart, data: "GTMP\r"}
- delay: 500ms
- uart.write: {id: jd_uart, data: "GINV\r"}
- delay: 500ms
- uart.write: {id: jd_uart, data: "GBUS\r"}
- delay: 500ms
- uart.write: {id: jd_uart, data: "FAN???\r"}
- delay: 500ms
- uart.write: {id: jd_uart, data: "BL\r"}
- delay: 500ms
- uart.write: {id: jd_uart, data: "GMOD\r"}
# ===== ПАРСИНГ ВІДПОВІДЕЙ =====
- interval: 100ms
then:
- lambda: |-
static std::string buffer;
while (id(jd_uart).available()) {
uint8_t c;
id(jd_uart).read_byte(&c);
if (c == '\r') {
if (buffer.length() > 0) {
ESP_LOGD("jdsolar", "RX: %s", buffer.c_str());
if (buffer[0] == '(') {
std::string data = buffer.substr(1);
std::vector<std::string> parts;
size_t pos = 0;
while ((pos = data.find(" ")) != std::string::npos) {
parts.push_back(data.substr(0, pos));
data.erase(0, pos + 1);
}
if (data.length() > 0) parts.push_back(data);
// GBAT - (AAA.A BBB.BB CC DD.D EE.E)
if (parts.size() == 5 && parts[0].find(".") != std::string::npos && parts[0].length() <= 5) {
id(battery_voltage).publish_state(atof(parts[0].c_str()));
id(battery_current).publish_state(atof(parts[1].c_str()));
id(battery_cells).publish_state(atoi(parts[2].c_str()));
id(battery_eod).publish_state(atof(parts[3].c_str()));
id(battery_low_alarm).publish_state(atof(parts[4].c_str()));
}
// GLINE - (AAA.A BB.BB CCC.C DDD.D EEE.E FFF.F GG.GG HH.HH IIIII JJJ KKKKK LLLLL MMMMM)
else if (parts.size() == 13) {
id(grid_voltage).publish_state(atof(parts[0].c_str()));
id(grid_frequency).publish_state(atof(parts[1].c_str()));
id(load_percentage).publish_state(atof(parts[9].c_str()));
id(grid_daily_energy).publish_state(atof(parts[10].c_str()) * 10);
uint32_t ge_h = atoi(parts[11].c_str());
uint32_t ge_l = atoi(parts[12].c_str());
id(grid_total_energy).publish_state((ge_h * 100000 + ge_l) * 10);
}
// GOP - (AAA.A BB.BB CCC.CC DD.DD EEEEE FFFFF GGGGG HHHHH IIIII JJJ KKKKK LLLLL MMMMM NNNNN OOOOO)
else if (parts.size() >= 15 && parts[0].find(".") != std::string::npos) {
id(output_voltage).publish_state(atof(parts[0].c_str()));
id(output_frequency).publish_state(atof(parts[1].c_str()));
id(output_current).publish_state(atof(parts[2].c_str()));
id(output_power).publish_state(atof(parts[4].c_str()));
id(output_apparent_power).publish_state(atof(parts[6].c_str()));
id(output_daily_energy).publish_state(atof(parts[13].c_str()) * 10);
if (parts.size() >= 16) {
uint32_t oe_h = atoi(parts[14].c_str());
uint32_t oe_l = atoi(parts[15].c_str());
id(output_total_energy).publish_state((oe_h * 100000 + oe_l) * 10);
}
}
// GCHG - (AAA.A BBB.B CC DDD.D EEE.EE FFF.FF GG.G HH.H II.I JJJ.JJ KKKK LLL MMM NNN O P Q R ...)
else if (parts.size() >= 18) {
id(bus_voltage).publish_state(atof(parts[0].c_str()));
id(charge_voltage).publish_state(atof(parts[1].c_str()));
id(charge_current).publish_state(atof(parts[3].c_str()));
id(max_charge_current).publish_state(atof(parts[9].c_str()));
id(eq_mode).publish_state(atoi(parts[14].c_str()) == 1);
int btype = atoi(parts[15].c_str());
id(battery_type).publish_state(
btype == 0 ? "Lead Acid" :
btype == 1 ? "Flooded" :
btype == 2 ? "Lithium" : "Custom"
);
int cmode = atoi(parts[17].c_str());
id(charge_stage).publish_state(
cmode == 0 ? "Stop" :
cmode == 1 ? "CC" :
cmode == 2 ? "CV" : "Float"
);
id(battery_charging).publish_state(cmode >= 1 && cmode <= 3);
}
// GPV - (AAA.A BBB.B CC.CC DD.DD EEEEE FF G H ...)
else if (parts.size() >= 20 && parts[4].length() <= 5) {
id(pv_voltage).publish_state(atof(parts[0].c_str()));
id(pv_charge_current).publish_state(atof(parts[2].c_str()));
id(pv_current).publish_state(atof(parts[3].c_str()));
id(pv_power).publish_state(atof(parts[4].c_str()));
int pvst = atoi(parts[5].c_str());
id(pv_status).publish_state(
pvst == 0 ? "Standby" :
pvst == 1 ? "Ready" :
pvst == 2 ? "CV" : "MPPT"
);
id(pv_charging).publish_state(atoi(parts[6].c_str()) == 1);
if (parts.size() >= 21) {
id(pv_daily_energy).publish_state(atof(parts[18].c_str()) * 10);
uint32_t pe_h = atoi(parts[19].c_str());
uint32_t pe_l = atoi(parts[20].c_str());
id(pv_total_energy).publish_state((pe_h * 100000 + pe_l) * 10);
}
}
// GTMP - (NNN.N MMM.M AAA.A III.I ZZZ.Z)
else if (parts.size() == 5 && parts[0].length() > 3) {
id(temp_pv).publish_state(atof(parts[0].c_str()));
id(temp_charger).publish_state(atof(parts[1].c_str()));
id(temp_ambient).publish_state(atof(parts[2].c_str()));
id(temp_mppt1).publish_state(atof(parts[3].c_str()));
id(over_temp).publish_state(
atof(parts[0].c_str()) > 70 ||
atof(parts[1].c_str()) > 70 ||
atof(parts[2].c_str()) > 50
);
}
// GINV - (AAA.A BB.BB CCC.C)
else if (parts.size() == 3 && parts[1].find(".") != std::string::npos) {
id(inv_voltage).publish_state(atof(parts[0].c_str()));
id(inv_frequency).publish_state(atof(parts[1].c_str()));
id(inv_current).publish_state(atof(parts[2].c_str()));
}
// FAN - (AAA BBB CCC D E)
else if (parts.size() == 5 && parts[0].length() == 3) {
id(fan_speed).publish_state(atof(parts[0].c_str()));
id(fan1_rpm).publish_state(atof(parts[1].c_str()));
id(fan2_rpm).publish_state(atof(parts[2].c_str()));
id(fan1_fault).publish_state(atoi(parts[3].c_str()) == 1);
id(fan2_fault).publish_state(atoi(parts[4].c_str()) == 1);
}
}
// GMOD - (M)
else if (buffer.length() == 3 && buffer[0] == '(') {
char mode = buffer[1];
id(working_mode).publish_state(
mode == 'P' ? "Power On" :
mode == 'S' ? "Standby" :
mode == 'L' ? "Line Mode" :
mode == 'B' ? "Battery Mode" :
mode == 'F' ? "Fault" :
mode == 'D' ? "Shutdown" : "Test"
);
id(grid_ok).publish_state(mode == 'L');
}
// BL - BLAAA
else if (buffer.substr(0, 2) == "BL" && buffer.length() == 5) {
int capacity = atoi(buffer.substr(2, 3).c_str());
id(battery_capacity).publish_state(capacity);
id(battery_low).publish_state(capacity < 20);
}
}
buffer.clear();
} else {
buffer += (char)c;
}
}
Nie da się tego stwierdzić na czuja jak napisy na układach są nieczytelne, trochę sobie poprawiłem to drugie zdjęcie
i układ wygląda na TPT3232E
więc, tak - to jest w jakimś stopniu zgodne z RS232 (przynajmniej jeśli chodzi o najbardziej interesujące linie Rx i Tx), nie udało mi się zgadnąć czym są te 2 układy na lewo (też jakieś wypusty 3PEAK) bo nawet intensywne poprawianie grafiki nie pomogło, a niemal cała reszta to transoptory odpowiadające za izolację galwaniczną.
Natomiast układ z 1 zdjęcia to ESP32-S3 (i nie wiem czy on stanowi tam główny kontroler, czy tylko tzw. datalogger WiFi, stawiam na drugie), to jest stosunkowo świeży układ na rynku, więc to może być zarówno dobra jak i zła wiadomość (dobra, bo wśród hobbystów jest dobrze znany, więc może się kiedyś pojawi na niego alternatywny wsad; a zła bo to dość nowa konstrukcja i może chińczykowi było wygodniej skorzystać np. z jakiegoś nowego protokołu danych własnego pomysłu częściowo lub całkowicie niezgodnego ze starszymi modelami) ← w nawiasie tylko potencjalne domysły.
Ale ze zgłoszeniem issue o takiej treści, to raczej masz tam marne szanse na pomoc
I get nothing but rubbish from the UART port USB A, marked as com.
bo z tego co widzę, to normalna komunikacja z takim inwerterem jak tam opisano na pierwszy rzut oka wygląda jak śmieci.
Kolejna próba. Znalazłem podobny układ i na tej bazie podłączyłem moje ESP. Gnd i 3.3V się zgadza. RX i TX kolejne dwa skrajne. Cisza.
Tak to formułujesz, że nawet gdybym miał szklaną kulę to nie zrozumiem co robisz nie mając na stole podobnego inwertera.
Dokumentacja, która jest w issue nie wygląda jak dokumentacja fabryczna, tylko jak zapiski z reverse-enigineeringu, ale skorzystaj z niej.
https://github.com/user-attachments/files/24748347/_20240131.pdf
może wygodniejsza do tłumaczenia z chińskiego jest ta wersja
https://github.com/user-attachments/files/24690715/protocol.JSDSOLAR.docx
Sorry mój błąd. Pierwsze co zrobiłem, to skorzystanie z tej dokumentacji. Zapewne jest do starszych wersji inwerterów jsdsolar.
Może przekierować DNS i dane z loggera wysyłać do HA. Tylko ten inwerter obsługuje wattseek, a nie smartess.
Ta komunikacja to takie śmieci, ale ktoś do tego napisał parser, widzę że próbowałeś z tego korzystać (ale tak jak wkleiłeś ten YAML, to się nie da nawet tego przeczytać…).
Natomiast sam fakt, że się generują “śmieci” może wynikać z działania fabrycznego loggera (który też żąda dane równolegle z twoją samoróbką). Sprawdzałeś czy jest możliwa praca bez loggera?
Mam mały sukces. Mimo informacje producenta, że to gniazdko USB a to rs232, działa z konwerterem rs485. Udało mi się odczytać kilka parametrów. AC 230 , 50Hz i kilka napięcie z baterii. Ogólnie te, które mają wartość różną od 0. Tylko mam problem z parserem. Dane z różnych ramek się nadpisując.
esphome:
name: jsdsolar
friendly_name: jsdsolar
esp32:
board: esp32dev
framework:
type: esp-idf
# Enable logging
logger:
level: VERY_VERBOSE
baud_rate: 0
# Enable Home Assistant API
api:
encryption:
key: ""
ota:
- platform: esphome
password: ""
web_server:
port: 80
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
ap:
ssid: "Jsdsolar Fallback Hotspot"
password: "cLrUqMuwMunB"
captive_portal:
uart:
id: uart_bus
rx_pin: GPIO18
baud_rate: 9600
globals:
- id: buffer
type: std::vector<uint8_t>
restore_value: no
sensor:
- platform: template
name: "AC Voltage"
id: ac_voltage
unit_of_measurement: "V"
accuracy_decimals: 1
- platform: template
name: "Battery Voltage"
id: battery_voltage
unit_of_measurement: "V"
accuracy_decimals: 1
- platform: template
name: "Frequency"
id: frequency
unit_of_measurement: "Hz"
accuracy_decimals: 1
- platform: template
name: "Output Current"
id: current
unit_of_measurement: "A"
accuracy_decimals: 1
- platform: template
name: "Grid Charge Current"
id: grid_charge_current
unit_of_measurement: "A"
- platform: template
name: "Max Charge Current"
id: max_charge_current
unit_of_measurement: "A"
- platform: template
name: "Battery Max Voltage"
id: battery_max_voltage
unit_of_measurement: "V"
- platform: template
name: "Float Voltage"
id: float_voltage
unit_of_measurement: "V"
- platform: template
name: "Battery Low Voltage"
id: battery_low_voltage
unit_of_measurement: "V"
- platform: template
name: "Battery Cutoff Voltage"
id: battery_cutoff_voltage
unit_of_measurement: "V"
- platform: template
name: "Max Discharge Current"
id: max_discharge_current
unit_of_measurement: "A"
interval:
- interval: 200ms
then:
- lambda: |-
while (id(uart_bus).available()) {
uint8_t byte;
id(uart_bus).read_byte(&byte);
id(buffer).push_back(byte);
}
if (id(buffer).size() > 400) {
id(buffer).erase(id(buffer).begin(), id(buffer).begin() + 150);
}
for (size_t i = 0; i + 6 < id(buffer).size(); i++) {
if (id(buffer)[i] == 0x01 && id(buffer)[i+1] == 0x03) {
uint8_t len = id(buffer)[i+2];
if (i + 3 + len <= id(buffer).size()) {
std::vector<uint16_t> regs;
for (int j = 0; j < len; j += 2) {
uint16_t val = (id(buffer)[i+3+j] << 8) | id(buffer)[i+4+j];
regs.push_back(val);
}
for (int r = 0; r < regs.size(); r++) {
ESP_LOGD("MAP", "[%d] = %d", r, regs[r]);
}
for (auto val : regs) {
if (val > 2000 && val < 2600) {
id(ac_voltage).publish_state(val / 10.0);
}
else if (val > 400 && val < 600) {
id(frequency).publish_state(val / 10.0);
}
else if (val > 4000 && val < 6000) {
id(battery_voltage).publish_state(val / 100.0);
}
else if (val > 0 && val < 200) {
id(current).publish_state(val / 10.0);
}
}
if (regs.size() > 15) {
id(grid_charge_current).publish_state(regs[5] / 10.0);
id(max_charge_current).publish_state(regs[6] / 10.0);
id(battery_low_voltage).publish_state(regs[7] / 10.0);
id(battery_cutoff_voltage).publish_state(regs[8] / 10.0);
id(battery_max_voltage).publish_state(regs[9] / 10.0);
id(float_voltage).publish_state(regs[10] / 10.0);
id(max_discharge_current).publish_state(regs[11] / 10.0);
}
id(buffer).erase(id(buffer).begin(), id(buffer).begin() + i + 3 + len);
break;
}
}
}




