V125 hat ein anderes Protokoll als V118 / 119. Es wird nicht funktionieren. Ich kann es nicht testen, da ich kein Gerät habe.
in der aktuellen Tasmota Changelog v15.2.0 ist von einem:
Support for MakeSkyBlue Solar Charger Energy Monitor #24151
die Rede. Leider finde ich nirgends weitere Informationen welche Firmwareversionen (V118…V125) unterstützt werden bzw. wie die Verkabelung oder Einrichtung zu erfolgen hat.
Hallo,
ich habe in der Zwischenzeit ein bisschen rumgespielt, um den MSB V118 auszulesen.
Meine Implementierung umfasst auch einen AM2301 Klimasensor, da ich auch Temperatur und Luftfeuchte überwachen möchte. Ein anderer Sensor wäre vermutlich besser geeignet, aber die Werte sind brauchbar.
Leider konnte ich dem Regler nicht die Nachkommastelle von “Total Production” entlocken.
Inzwischen nutze ich den ESP8266 unter ESPHome.
Viele Grüße
Christian
esphome:
name: makeskyblue-v118
comment: MakeSkyBlue V118 + DHT21 (AM2301) via ESPHome
esp8266:
board: nodemcuv2
logger:
baud_rate: 0 level: DEBUG logs: sensor: INFO uart: DEBUGwifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
min_auth_mode: WPA2
ap:
ssid: "MSB-V118-Fallback" password: !secret fallback_passwordcaptive_portal:
api:
encryption:
key: !secret api_keyreboot_timeout: 15min # Neustart nach 15 Min ohne API
ota:
platform: esphome
password: !secret ota_password
web_server:
port: 80
uart:
id: v118_uart
baud_rate: 9600
rx_pin: RX
tx_pin: TX
rx_buffer_size: 512
sensor:
# --- DHT21 / AM2301 ---
platform: dht
pin: D5
model: DHT22
temperature:
name: "MSB Umgebungstemperatur"
id: amb_temp
device_class: temperature
state_class: measurement
accuracy_decimals: 1
humidity:
name: "MSB Luftfeuchtigkeit"
id: amb_hum
device_class: humidity
state_class: measurement
accuracy_decimals: 0
update_interval: 30s
# --- V118 Sensoren (Templates werden im Lambda befüllt) ---
platform: template
name: "MSB Akku Spannung"
id: batt_voltage
unit_of_measurement: "V"
device_class: voltage
state_class: measurement
accuracy_decimals: 1
platform: template
name: "MSB Akku Strom"
id: batt_current
unit_of_measurement: "A"
device_class: current
state_class: measurement
accuracy_decimals: 1
platform: template
name: "MSB PV Spannung"
id: pv_voltage
unit_of_measurement: "V"
device_class: voltage
state_class: measurement
accuracy_decimals: 1
platform: template
name: "MSB PV Leistung"
id: pv_power
unit_of_measurement: "W"
device_class: power
state_class: measurement
accuracy_decimals: 0
platform: template
name: "MSB PV Energie"
id: pv_energy
accuracy_decimals: 0
unit_of_measurement: "kWh"
device_class: energy
state_class: total_increasing
platform: template
name: "MSB Regler Temperatur"
id: ctrl_temp
unit_of_measurement: "°C"
device_class: temperature
state_class: measurement
accuracy_decimals: 1
platform: integration
name: "MSB PV-Erzeugung"
sensor: pv_power
id: v_power_cum
time_unit: h
unit_of_measurement: "kWh"
device_class: energy
state_class: total_increasing
accuracy_decimals: 3
integration_method: left
filters:
- multiply: 0.001
restore: true
platform: template
name: "MSB Code 12"
id: error_byte12
accuracy_decimals: 0
state_class: measurement
entity_category: diagnostic
platform: template
name: "MSB Code 13"
id: error_byte13
accuracy_decimals: 0
state_class: measurement
entity_category: diagnostic
platform: template
name: "MSB Statusflag"
id: status_byte15
accuracy_decimals: 0
state_class: measurement
entity_category: diagnostic
# --- ALLE TEXT SENSOREN IN EINEM BLOCK ---
text_sensor:
platform: template
name: "MSB Fehler"
id: error_byte12_text
entity_category: diagnostic
platform: template
name: "MSB Lademodus"
id: charger_mode
icon: "mdi:battery-charging"
entity_category: diagnostic
platform: template
name: "MSB Code 13 Status"
id: error_byte13_text
entity_category: diagnostic
time:
platform: sntp
id: sntp_time
timezone: "Europe/Berlin"
on_time:
seconds: 0
minutes: 0
hours: 3
then:
sensor.integration.reset: v_power_cum
logger.log: "Energiezähler um Mitternacht zurückgesetzt und NodeMCU neu gestartet."
delay: 3s
lambda: |-
App.safe_reboot();
sun:
latitude: 49.44
longitude: 7.74
interval:
interval: 10s
then:
lambda: |-
// Buffer komplett leeren vor neuer Anfrage
while (id(v118_uart).available()) {
uint8_t dummy; id(v118_uart).read_byte(&dummy);}
# Anfrage senden
uart.write:
id: v118_uart
data: [0xAA, 0x55, 0x00, 0x00, 0x00, 0x55]
# WICHTIG: Warten auf Antwort
- delay: 350ms
# Antwort verarbeiten
lambda: |-
static uint8_t buf[18];
uint8_t b;
static float last_energy = -1;
int attempts = 0;
bool found_header = false;
// Timeout-Schutz: max 50 Bytes durchsuchen
while (id(v118_uart).available() > 0 && attempts < 50) {
attempts++; // Suche nach 0xAA Header if (!id(v118_uart).read_byte(&b)) { ESP_LOGW("MSB", "Lesefehler beim Header-Suchen"); break; } if (b == 0xAA) { // Prüfe ob genug Daten für komplette Nachricht vorhanden if (id(v118_uart).available() < 19) { delay(10); } if (id(v118_uart).available() < 19) { ESP_LOGW("MSB", "Nicht genug Daten nach Header"); break; } // Header 2: 0xBB if (!id(v118_uart).read_byte(&b) || b != 0xBB) { ESP_LOGW("MSB", "Ungültiger zweiter Header: 0x%02X", b); continue; // Weitersuchen } found_header = true; break; }}
static uint8_t fail_count = 0;
if (!found_header) {
fail_count++; if (fail_count >= 3) { ESP_LOGW("MSB", "Kein gültiger Header gefunden (%d)", fail_count); fail_count = 0; } return;}
fail_count = 0;
// Payload lesen
for (int i = 0; i < 18; i++) {
if (!id(v118_uart).read_byte(&buf\[i\])) { ESP_LOGW("MSB", "Lesefehler bei Byte %d", i); return; }}
// Checksumme prüfen
int checksum = 0xBB;
for (int i = 0; i < 17; i++) checksum += buf[i];
if ((checksum & 0xFF) != buf[17]) {
ESP_LOGW("MSB", "Checksumme fehlerhaft (erwartet 0x%02X, erhalten 0x%02X)", checksum & 0xFF, buf\[17\]); return;}
ESP_LOGD("MSB", "Raw data - B12:%d B13:%d B14:%d B15:%d", buf[12], buf[13], buf[14], buf[15]);
// Ab hier dein bestehender Code für Mapping und Sensoren
int battV = buf[0] | (buf[1] << 8);
int battA = buf[2] | (buf[3] << 8);
int pvV = buf[4] | (buf[5] << 8);
int pvW = buf[6] | (buf[7] << 8);
int temp = buf[8] | (buf[9] << 8);
int ener_raw = buf[10] | (buf[11] << 8);
int byte12 = buf[12];
int byte13 = buf[13];
int mode_raw = buf[14];
int byte15 = buf[15];
id(batt_voltage).publish_state(battV * 0.1f);
id(batt_current).publish_state(battA * 0.1f);
id(pv_voltage).publish_state(pvV * 0.1f);
id(pv_power).publish_state(pvW);
id(ctrl_temp).publish_state(temp * 0.1f);
id(error_byte12).publish_state(byte12);
id(error_byte13).publish_state(byte13);
id(status_byte15).publish_state(byte15);
// Fehlertext
switch (byte12) {
case 0: id(error_byte12_text).publish_state("OK"); break; case 18: id(error_byte12_text).publish_state("Solar-Eingangsspannung zu niedrig"); break; case 60: id(error_byte12_text).publish_state("Übertemperatur"); break; case 63: id(error_byte12_text).publish_state("Batteriespannung zu hoch"); break; case 65: id(error_byte12_text).publish_state("Batteriespannung zu gering"); break; case 71: id(error_byte12_text).publish_state("Solar-Eingangsspannung zu hoch"); break; case 73: id(error_byte12_text).publish_state("Ladestrom zu hoch"); break; case 74: id(error_byte12_text).publish_state("Kurzschluss Lastausgang"); break; default: { char txt\[16\]; sprintf(txt, "Code %d", byte12); id(error_byte12_text).publish_state(txt); }}
// Energie (Spike-Schutz)
float e = (float)ener_raw;
if (last_energy < 0 || (e >= last_energy && e - last_energy < 2.0f)) {
id(pv_energy).publish_state(e); last_energy = e;}
static int last_mode = -1;
if (mode_raw != last_mode) {
last_mode = mode_raw; if (mode_raw == 0) id(charger_mode).publish_state("Standby"); else if (mode_raw == 4) id(charger_mode).publish_state("Hauptladung"); else if (mode_raw == 3) id(charger_mode).publish_state("Absorption"); else if (mode_raw == 6) id(charger_mode).publish_state("Float"); else { char m\[12\]; sprintf(m, "Code %d", mode_raw); id(charger_mode).publish_state(m); }}
ESP_LOGD("MSB", "Erfolgreich gelesen - PV: %.1fV, %.0fW", pvV*0.1f, (float)pvW);