Skip to content

Instantly share code, notes, and snippets.

@noone2k
Last active June 26, 2024 11:06
Show Gist options
  • Save noone2k/2ddea4c9bf116aaaefb8626b064d9a41 to your computer and use it in GitHub Desktop.
Save noone2k/2ddea4c9bf116aaaefb8626b064d9a41 to your computer and use it in GitHub Desktop.
bc2500 info/control with esphome
esphome:
name: bc2500-ble-idf
friendly_name: bc2500-ble-idf
esp32:
board: az-delivery-devkit-v4
framework:
type: esp-idf
sdkconfig_options:
CONFIG_FREERTOS_UNICORE: y
advanced:
ignore_efuse_mac_crc: true
# Enable logging
logger:
# level: INFO
# level: DEBUG
# baud_rate: 0
ota:
password: !secret ota_password
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
reboot_timeout: 0s
fast_connect: True
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Bc2500-Ble Fallback Hotspot"
web_server:
port: 80
local: true
js_include: "./v2/www.js"
js_url: ""
version: 2
captive_portal:
mqtt:
id: mqtt_client
broker: !secret mqtt_broker
port: !secret mqtt_port
discovery: False
reboot_timeout: 0s
topic_prefix: b2500
log_topic: b2500/debug
time:
- platform: sntp
id: sntp_time
on_time:
# Every 10 seconds
- seconds: /10
then:
- script.execute: ble_process
- script.wait: ble_process
#- script.execute: power_zero
#- button.press: query_info3
globals:
- id: ble_1_connected
type: bool
initial_value: '0'
- id: ble_1_initialized
type: bool
initial_value: '0'
- id: ble_2_connected
type: bool
initial_value: '0'
- id: ble_2_initialized
type: bool
initial_value: '0'
- id: cmd30_xor_last_1
type: int
initial_value: '0'
- id: cmd30_xor_last_2
type: int
initial_value: '0'
- id: internal_console_dbg
type: bool
initial_value: '0'
- id: internal_console_hexdump
type: bool
initial_value: '1'
esp32_ble_tracker:
ble_client:
- mac_address: !secret hm2500_1_mac
id: bc2500_1
on_connect:
then:
- globals.set:
id: ble_1_connected
value: '1'
- binary_sensor.template.publish:
id: bool_ble_ok_1
state: ON
- script.execute:
id: ble_set_time
ble_device_nr: 1
- script.wait: ble_set_time
- script.execute:
id: ble_set_time
ble_device_nr: 1
- script.wait: ble_set_time
on_disconnect:
then:
- binary_sensor.template.publish:
id: bool_ble_ok_1
state: OFF
- globals.set:
id: ble_1_connected
value: '0'
- globals.set:
id: ble_1_initialized
value: '0'
- mac_address: !secret hm2500_2_mac
id: bc2500_2
on_connect:
then:
- globals.set:
id: ble_2_connected
value: '1'
- binary_sensor.template.publish:
id: bool_ble_ok_2
state: ON
- script.execute:
id: ble_set_time
ble_device_nr: 2
- script.wait: ble_set_time
- script.execute:
id: ble_set_time
ble_device_nr: 2
- script.wait: ble_set_time
on_disconnect:
then:
- binary_sensor.template.publish:
id: bool_ble_ok_2
state: OFF
- globals.set:
id: ble_2_connected
value: '0'
- globals.set:
id: ble_2_initialized
value: '0'
button:
- platform: restart
id: controller_restart
name: "Restart Controller"
number:
- platform: template
name: "D1-52: Entladeschwelle"
id: sensor_discharge_treshold_1
state_topic: b2500/1/battery/discharge_treshold
command_topic: b2500/1/battery/discharge_treshold/set
optimistic: True
min_value: 1
max_value: 500
step: 1
restore_value: True
on_value:
- script.execute:
id: ble_set_discharge_treshold
ble_device_nr: 1
discharge: !lambda return x;
- platform: template
name: "D1-53: DOD"
state_topic: b2500/1/battery/dod
command_topic: b2500/1/battery/dod/set
id: sensor_dod_1
optimistic: True
min_value: 10
max_value: 100
step: 1
restore_value: True
on_value:
- script.execute:
id: ble_set_dod
ble_device_nr: 1
dod: !lambda return x;
- platform: template
name: "D2-52: Entladeschwelle"
id: sensor_discharge_treshold_2
state_topic: b2500/2/battery/discharge_treshold
command_topic: b2500/2/battery/discharge_treshold/set
optimistic: True
min_value: 1
max_value: 500
step: 1
restore_value: True
on_value:
- script.execute:
id: ble_set_discharge_treshold
ble_device_nr: 2
discharge: !lambda return x;
- platform: template
name: "D2-53: DOD"
state_topic: b2500/2/battery/dod
command_topic: b2500/2/battery/dod/set
id: sensor_dod_2
optimistic: True
min_value: 10
max_value: 100
step: 1
restore_value: True
on_value:
- script.execute:
id: ble_set_dod
ble_device_nr: 2
dod: !lambda return x;
### power zero
- platform: template
name: "MQTT: opendtu set limit"
id: mqtt_opendtu_limit
internal: False
state_topic: !secret mqtt_opendtu_limit_cmd
command_topic: !secret mqtt_opendtu_limit_state
optimistic: True
min_value: 1
max_value: 75
step: 1
restore_value: True
- platform: template
name: "MQTT: opendtu set limit max"
id: mqtt_opendtu_limit_max
internal: False
optimistic: True
min_value: 1
max_value: 75
step: 1
restore_value: True
switch:
- platform: template
id: switch_powerout_1_1
name: "D1-01: Power Out 1"
state_topic: b2500/1/power1/enabled
command_topic: b2500/1/power1/enabled/set
optimistic: True
assumed_state: True
on_turn_on:
then:
- switch.turn_on: switch_powerout_1_1
- script.execute:
id: ble_powerout
ble_device_nr: 1
on_turn_off:
then:
- switch.turn_off: switch_powerout_1_1
- script.execute:
id: ble_powerout
ble_device_nr: 1
- platform: template
id: switch_powerout_1_2
name: "D1-02: Power Out 2"
state_topic: b2500/1/power2/enabled
command_topic: b2500/1/power2/enabled/set
optimistic: True
assumed_state: True
on_turn_on:
then:
- switch.turn_on: switch_powerout_1_2
- script.execute:
id: ble_powerout
ble_device_nr: 1
on_turn_off:
then:
- switch.turn_off: switch_powerout_1_2
- script.execute:
id: ble_powerout
ble_device_nr: 1
- platform: template
id: switch_powerout_2_1
name: "D2-01: Power Out 1"
state_topic: b2500/2/power1/enabled
command_topic: b2500/2/power1/enabled/set
optimistic: True
assumed_state: True
on_turn_on:
then:
- script.execute:
id: ble_powerout
ble_device_nr: 2
on_turn_off:
then:
- script.execute:
id: ble_powerout
ble_device_nr: 2
- platform: template
id: switch_powerout_2_2
name: "D2-02: Power Out 2"
state_topic: b2500/2/power2/enabled
command_topic: b2500/2/power2/enabled/set
optimistic: True
assumed_state: True
on_turn_on:
then:
- script.execute:
id: ble_powerout
ble_device_nr: 2
on_turn_off:
then:
- script.execute:
id: ble_powerout
ble_device_nr: 2
- platform: template
id: switch_pv2_passthrough_1
name: "D1-03: PV2 Passtrough"
state_topic: b2500/1/pv2/passtrough
command_topic: b2500/1/pv2/passtrough/set
optimistic: True
assumed_state: True
on_turn_on:
then:
- script.execute:
id: ble_passthrough
ble_device_nr: 1
switch_cmd: 0
on_turn_off:
then:
- script.execute:
id: ble_passthrough
ble_device_nr: 1
switch_cmd: 1
- platform: template
id: switch_pv2_passthrough_2
name: "D2-03: PV2 Passtrough"
state_topic: b2500/2/pv2/passtrough
command_topic: b2500/2/pv2/passtrough/set
optimistic: True
assumed_state: True
on_turn_on:
then:
- script.execute:
id: ble_passthrough
ble_device_nr: 2
switch_cmd: 0
on_turn_off:
then:
- script.execute:
id: ble_passthrough
ble_device_nr: 2
switch_cmd: 1
- platform: template
id: switch_debug_hexdump
name: "INTERNAL:DEBUG HEXDUMP"
optimistic: True
#assumed_state: True
- platform: template
id: switch_opendtu_limit
name: "MQTT: opendtu - zero power"
optimistic: True
#assumed_state: True
text:
- platform: template
name: "A1-t01 - Device Type"
id: txt_A01_1
state_topic: b2500/1/device/type
optimistic: true
max_length: 30
mode: text
- platform: template
name: "A1-t02 - Device ID"
state_topic: b2500/1/device/id
id: txt_A02_1
optimistic: true
max_length: 30
mode: text
- platform: template
name: "A1-t03 - MAC"
id: txt_A03_1
state_topic: b2500/1/device/ble_mac
optimistic: true
max_length: 30
mode: text
- platform: template
name: "A1-t04 - SSID"
id: txt_A11_1
state_topic: b2500/1/device/wifi_ssid
optimistic: true
max_length: 30
mode: text
- platform: template
name: "A2-t01 - Device Type"
id: txt_A01_2
state_topic: b2500/2/device/type
optimistic: true
max_length: 30
mode: text
- platform: template
name: "A2-t02 - Device ID"
id: txt_A02_2
state_topic: b2500/2/device/id
optimistic: true
max_length: 30
mode: text
- platform: template
name: "A2-t03 - MAC"
id: txt_A03_2
optimistic: true
state_topic: b2500/2/device/ble_mac
max_length: 30
mode: text
- platform: template
name: "A2-t04 - SSID"
id: txt_A11_2
state_topic: b2500/2/device/wifi_ssid
optimistic: true
max_length: 30
mode: text
- platform: template
name: "A1-t56: Szene"
id: txt_scene_1
state_topic: b2500/1/device/scene
optimistic: true
max_length: 32
mode: text
- platform: template
name: "A1-t57: Region"
id: txt_region_1
state_topic: b2500/1/device/region
optimistic: true
max_length: 8
mode: text
- platform: template
name: "A2-t56: Szene"
id: txt_scene_2
state_topic: b2500/2/device/scene
optimistic: true
max_length: 32
mode: text
- platform: template
name: "A2-t57: Region"
id: txt_region_2
state_topic: b2500/2/device/region
optimistic: true
max_length: 8
mode: text
binary_sensor:
- platform: template
name: "D1-i01: PV 1 - Aktiv"
id: bool_pv_active_1_1
state_topic: b2500/1/pv1/active
- platform: template
name: "D1-i11: PV 2 - Aktiv"
id: bool_pv_active_1_2
state_topic: b2500/1/pv2/active
- platform: template
name: "D1-i02: PV 1 - Transparent"
id: bool_pv_transparent_1_1
state_topic: b2500/1/pv1/transparent
- platform: template
name: "D1-i11: PV 2 - Transparent"
id: bool_pv_transparent_1_2
state_topic: b2500/1/pv2/transparent
- platform: template
name: "D1-i54: Wifi Connected (?)"
id: bool_wifi_ok_1
state_topic: b2500/1/device/wifi_ok
- platform: template
name: "D1-i55: MQTT1 Connected"
id: bool_mqtt1_ok_1
state_topic: b2500/1/device/mqtt_ok
- platform: template
name: "D1-i58: BLE Connected"
id: bool_ble_ok_1
state_topic: b2500/1/device/ble_ok
- platform: template
name: "D1-i21: Ausgang 1 - Aktiv"
id: bool_power_active_1_1
state_topic: b2500/1/power1/active
- platform: template
name: "D1-i31: Ausgang 2 - Aktiv"
id: bool_power_active_1_2
state_topic: b2500/1/power2/active
- platform: template
name: "D1-i40: Erweiterung 1 - angeschlossen"
id: bool_extern_connected_1_1
state_topic: b2500/1/extern1/connected
- platform: template
name: "D1-i41: Erweiterung 2 - angeschlossen"
id: bool_extern_connected_1_2
state_topic: b2500/1/extern2/connected
- platform: template
name: "D2-i01: PV 1 - Aktiv"
id: bool_pv_active_2_1
state_topic: b2500/2/pv1/active
- platform: template
name: "D2-i11: PV 2 - Aktiv"
id: bool_pv_active_2_2
state_topic: b2500/2/pv2/active
- platform: template
name: "D2-i02: PV 1 - Transparent"
id: bool_pv_transparent_2_1
state_topic: b2500/2/pv1/transparent
- platform: template
name: "D2-i12: PV 2 - Transparent"
id: bool_pv_transparent_2_2
state_topic: b2500/2/pv2/transparent
- platform: template
name: "D2-i54: Wifi Connected (?)"
id: bool_wifi_ok_2
state_topic: b2500/2/device/wifi_ok
- platform: template
name: "D2-i55: MQTT1 Connected"
id: bool_mqtt1_ok_2
state_topic: b2500/2/device/mqtt_ok
- platform: template
name: "D2-i58: BLE Connected"
id: bool_ble_ok_2
state_topic: b2500/2/device/ble_ok
- platform: template
name: "D2-i21: Ausgang 1 - Aktiv"
id: bool_power_active_2_1
state_topic: b2500/2/power1/active
- platform: template
name: "D2-i31: Ausgang 2 - Aktiv"
id: bool_power_active_2_2
state_topic: b2500/2/power2/active
- platform: template
name: "D2-i40: Erweiterung 1 - angeschlossen"
id: bool_extern_connected_2_1
state_topic: b2500/2/extern1/connected
- platform: template
name: "D2-i41: Erweiterung 2 - angeschlossen"
id: bool_extern_connected_2_2
state_topic: b2500/2/extern2/connected
sensor:
- platform: template
name: "D1-i05: PV 1 - Leistung"
id: sensor_pv_power_in_1_1
state_topic: b2500/1/pv1/power
accuracy_decimals: 0
- platform: template
name: "D1-i15: PV 2 - Leistung"
id: sensor_pv_power_in_1_2
state_topic: b2500/1/pv2/power
accuracy_decimals: 0
- platform: template
name: "D1-i50: Füllstand der Batterie in Prozent"
id: sensor_bat_remain_1
state_topic: b2500/1/battery/remaining_percent
accuracy_decimals: 0
- platform: template
name: "D1-i51: Füllstand der Batterie in Wh"
id: sensor_bat_capacity_1
state_topic: b2500/1/battery/remaining_capacity
accuracy_decimals: 0
- platform: template
name: "D1-i25: Ausgang 1 - Leistung"
id: sensor_power_out_1_1
state_topic: b2500/1/power1/power
accuracy_decimals: 0
- platform: template
name: "D1-i35: Ausgang 2 - Leistung"
id: sensor_power_out_1_2
state_topic: b2500/1/power2/power
accuracy_decimals: 0
- platform: template
name: "A1-t59: Geräte Version"
id: sensor_device_version_1
state_topic: b2500/1/device/fw_version
accuracy_decimals: 2
- platform: template
name: "D2-i05: PV 1 - Leistung"
id: sensor_pv_power_in_2_1
state_topic: b2500/2/pv1/power
accuracy_decimals: 0
- platform: template
name: "D2-i15: PV 2 - Leistung"
id: sensor_pv_power_in_2_2
state_topic: b2500/2/pv2/power
accuracy_decimals: 0
- platform: template
name: "D2-i50: Füllstand der Batterie in Prozent"
id: sensor_bat_remain_2
state_topic: b2500/2/battery/remaining_percent
accuracy_decimals: 0
- platform: template
name: "D2-i51: Füllstand der Batterie in Wh"
id: sensor_bat_capacity_2
state_topic: b2500/2/battery/remaining_capacity
accuracy_decimals: 0
- platform: template
name: "D2-i25: Ausgang 1 - Leistung "
id: sensor_power_out_2_1
state_topic: b2500/2/power1/power
accuracy_decimals: 0
- platform: template
name: "D2-i35: Ausgang 2 - Leistung "
id: sensor_power_out_2_2
state_topic: b2500/2/power2/power
accuracy_decimals: 0
- platform: template
name: "A2-t59: Geräte Version"
id: sensor_device_version_2
state_topic: b2500/2/device/fw_version
accuracy_decimals: 2
- platform: ble_client
ble_client_id: bc2500_1
internal: True
type: characteristic
name: "infoX2a"
id: infoX2a
service_uuid: 'ff00'
characteristic_uuid: 'ff02'
notify: True
lambda: |-
std::vector<char> tData;
for (auto b : x) { tData.push_back(b); }
id(ble_notify_parse).execute(1,tData);
return (float)x[0];
- platform: ble_client
ble_client_id: bc2500_2
internal: True
type: characteristic
name: "infoX2b"
id: infoX2b
service_uuid: 'ff00'
characteristic_uuid: 'ff02'
notify: True
lambda: |-
std::vector<char> tData;
for (auto b : x) { tData.push_back(b); }
id(ble_notify_parse).execute(2,tData);
return (float)x[0];
### power zero - mqtt grid power sensor ( any who publish the grid power to mqtt - defined in secrets,yaml )
- platform: mqtt_subscribe
name: "MQTT: Grid Power"
id: mqtt_grid_power
topic: !secret mqtt_grid_power
on_value:
then:
- script.execute: power_zero
###test
- platform: ble_client
ble_client_id: bc2500_1
internal: True
type: characteristic
name: "infoX6a"
id: infoX6a
service_uuid: 'ff00'
characteristic_uuid: 'ff06'
notify: True
lambda: |-
std::vector<char> tData;
for (auto b : x) { tData.push_back(b); }
id(ble_notify_parse_test).execute(1,tData);
return (float)x[0];
- platform: ble_client
ble_client_id: bc2500_2
internal: True
type: characteristic
name: "infoX6b"
id: infoX6b
service_uuid: 'ff00'
characteristic_uuid: 'ff06'
notify: True
lambda: |-
std::vector<char> tData;
for (auto b : x) { tData.push_back(b); }
id(ble_notify_parse_test).execute(1,tData);
return (float)x[0];
script:
# ble communication
#
# action ( 00f1 )
#
# head = 0x73
# length = len(paket)
# cntl = 0x23
# cmd = 0x02 set Region 1Byte (0x00 = EU / 0x01 = China / 0x02 = Non-EU)
# = 0x03 runtimeInfo 1Byte (0x01)
# = 0x04 DeviceInfo 1Byte (0x01)
# = 0x0B DOD 1Byte (0-100)
# = 0x0C Entladeschwelle 2Byte (0-500)
# = 0x0D PV2-Passtrough 1Byte (0x00 on / 0x01 off)
# = 0x0E PowerOut 1Byte (0x00 1-2 off / 0x01 1 on / 0x02 2 on / 0x03 1-2 on)
#
# = 0x05 Wifi-Config xByte ( ssid<.,.>pwd )
# = 0x08 Wifi-State 1Byte (0x01) ????
#
# q&d c&p - more details will be added, maybe ...
# = 0x14 set AWS MQTT xByte ( url<.,.>Port ) ....
# = 0x60 set MQTT Certs xByte ( 0x00 = client.key / 0x01 = client.crt / 0x02 = ca.crt + cert len )
# = 0x61 trans MQTT Certs xByte ( jeweils 128bytes des certs )
# = 0x62 end MQTT Certs xByte ( )
#
# testing / notes
# = 0x01 Debug ?!?! 1Byte (0x00 = off / 0x01 = on) - enables QBLEGATTSNOTIFY notify 1 / 81 ( entspricht ~ runtimeinfo )
# = 0x06
# = 0x07
# = 0x09
# = 0x0A
# = 0x0E HW-RESET ????? / send before head 0XAA ( deactivate output ??? )
# = 0x0F new in fw 131 1Byte ( 0x01 )
#
# = 0x30 found in logs ... unknown parm 0x01 ???? answers since fw 131
# = 0x14 maybe not for mqtt ... set localtime ??? for auth/certs/challenge requests ????? ( query/set wifi depends ????)
#
# data = xx xx xx xx xx xx .... / depends on cmd
# crc = xor len(paket) - 1
#
#
# responses ( ff02 ):
#
# head = 0x73
# length = len(paket)
# cntl = 0x23
# cmd = cmd
# data = xx xx xx xx xx ....
#
#
#
################ maybe direct for arm
# send ( ff01 )
#
# head1 = 0xAA
# head2(?) = 0x55 ( not length ?!?!? )
# cmd = 1x / 2x / 3x ( flash - 30 "open"/ 31 - write / 32 "close" ) / 5x
# data = xx xx xx xx xx ....
# crc = xor len(paket) -1
#
################ maybe direct for bms
# send/receive ( ff06 )
#
# head = 0xAA
# len = 0x05/0x03
# data = xx xx xxx ( xx xx )
# crc = x1 + x2 + ... + xn
#
#
#
# -> aa 05 01 00 01 01 00 08
# <- aa 01 00 01
#
# -> aa 05 01 00 01 00 00 07
# <- aa 01 00 01
#
- id: ble_command_simple
parameters:
ble_device_nr: int
ble_cmd: int
ble_cmd_parm: int
then:
- logger.log:
format: "ble command parse: %i [%i] %i"
args: [ 'ble_device_nr','ble_cmd','ble_cmd_parm' ]
- if:
condition:
lambda: 'return (ble_device_nr == 1);'
then:
- ble_client.ble_write:
id: bc2500_1
#service_uuid: 'ff00'
#characteristic_uuid: 'ff01'
service_uuid: 0000ff00-0000-1000-8000-00805f9b34fb
characteristic_uuid: 0000ff01-0000-1000-8000-00805f9b34fb
value: !lambda |-
std::vector<unsigned char> rdat1{ 0x73,0x06,0x23,(unsigned char)ble_cmd};
if (ble_cmd == 0x0C) {
rdat1.push_back((uint8_t)((ble_cmd_parm >> 0) & 0xFF));
rdat1.push_back((uint8_t)((ble_cmd_parm >> 8) & 0xFF));
} else {
rdat1.push_back((unsigned char)ble_cmd_parm);
}
int rlen = rdat1.size();
rdat1.at(1) = rlen+1;
int rxor = 0;
for (int i=0;i<rlen;i++) {
rxor = rxor ^ rdat1[i];
}
rdat1.push_back(rxor);
if (id(internal_console_dbg)) {
for (auto b : rdat1) {
ESP_LOGD("COMMAND", "%x - %i - %c", b,b,b);
}
}
return rdat1;
- if:
condition:
lambda: 'return (ble_device_nr == 2);'
then:
- ble_client.ble_write:
id: bc2500_2
service_uuid: 'ff00'
characteristic_uuid: 'ff01'
value: !lambda |-
std::vector<unsigned char> rdat2{ 0x73,0x06,0x23,(unsigned char)ble_cmd};
if (ble_cmd == 0x0C) {
rdat2.push_back((uint8_t)((ble_cmd_parm >> 0) & 0xFF));
rdat2.push_back((uint8_t)((ble_cmd_parm >> 8) & 0xFF));
} else {
rdat2.push_back((unsigned char)ble_cmd_parm);
}
int rlen = rdat2.size();
rdat2.at(1) = rlen+1;
int rxor = 0;
for (int i=0;i<rlen;i++) {
rxor = rxor ^ rdat2[i];
}
rdat2.push_back(rxor);
if (id(internal_console_dbg)) {
for (auto b : rdat2) {
ESP_LOGD("COMMAND", "%x - %i - %c", b,b,b);
}
}
return rdat2;
- id: ble_command_string
parameters:
ble_device_nr: int
ble_cmd: int
ble_cmd_parm: string
then:
- logger.log:
format: "ble command parse: %i [%i]"
args: [ 'ble_device_nr','ble_cmd']
- if:
condition:
lambda: 'return (ble_device_nr == 1);'
then:
- ble_client.ble_write:
id: bc2500_1
#service_uuid: 'ff00'
#characteristic_uuid: 'ff01'
service_uuid: 0000ff00-0000-1000-8000-00805f9b34fb
characteristic_uuid: 0000ff01-0000-1000-8000-00805f9b34fb
value: !lambda |-
std::vector<unsigned char> rdat1{ 0x73,0x06,0x23,(unsigned char)ble_cmd};
for (auto b : ble_cmd_parm) {
rdat1.push_back((unsigned char)b);
}
int rlen = rdat1.size();
rdat1.at(1) = rlen+1;
int rxor = 0;
for (int i=0;i<rlen;i++) {
rxor = rxor ^ rdat1[i];
}
rdat1.push_back(rxor);
if (id(internal_console_dbg)) {
for (auto b : rdat1) {
ESP_LOGD("COMMAND", "%x - %i - %c", b,b,b);
}
}
return rdat1;
- if:
condition:
lambda: 'return (ble_device_nr == 2);'
then:
- ble_client.ble_write:
id: bc2500_2
service_uuid: 'ff00'
characteristic_uuid: 'ff01'
#service_uuid: 0000ff00-0000-1000-8000-00805f9b34fb
#characteristic_uuid: 0000ff01-0000-1000-8000-00805f9b34fb
value: !lambda |-
std::vector<unsigned char> rdat2{ 0x73,0x06,0x23,(unsigned char)ble_cmd};
for (auto b : ble_cmd_parm) {
rdat2.push_back((unsigned char)b);
}
int rlen = rdat2.size();
rdat2.at(1) = rlen+1;
int rxor = 0;
for (int i=0;i<rlen;i++) {
rxor = rxor ^ rdat2[i];
}
rdat2.push_back(rxor);
if (id(internal_console_dbg)) {
for (auto b : rdat2) {
ESP_LOGD("COMMAND", "%x - %i - %c", b,b,b);
}
}
return rdat2;
- id: ble_set_time
parameters:
ble_device_nr: int
then:
- if:
condition:
lambda: 'return (ble_device_nr == 1);'
then:
- ble_client.ble_write:
id: bc2500_1
#service_uuid: 'ff00'
#characteristic_uuid: 'ff01'
service_uuid: 0000ff00-0000-1000-8000-00805f9b34fb
characteristic_uuid: 0000ff01-0000-1000-8000-00805f9b34fb
value: !lambda |-
std::vector<unsigned char> rdat1{ 0x73,0x0d,0x23,0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00 };
auto time = id(sntp_time).now();
rdat1.at(4) = time.year - 1900;
rdat1.at(5) = time.month;
rdat1.at(6) = time.day_of_month;
rdat1.at(7) = time.hour;
rdat1.at(8) = time.minute;
rdat1.at(9) = time.second + 1;
int rlen = rdat1.size();
rdat1.at(1) = rlen+1;
int rxor = 0;
for (int i=0;i<rlen;i++) {
rxor = rxor ^ rdat1[i];
}
rdat1.push_back(rxor);
if (id(internal_console_dbg)) {
for (auto b : rdat1) {
ESP_LOGD("COMMAND", "%x - %i - %c", b,b,b);
}
}
return rdat1;
- globals.set:
id: ble_1_initialized
value: '1'
- if:
condition:
lambda: 'return (ble_device_nr == 2);'
then:
- ble_client.ble_write:
id: bc2500_2
service_uuid: 'ff00'
characteristic_uuid: 'ff01'
#service_uuid: 0000ff00-0000-1000-8000-00805f9b34fb
#characteristic_uuid: 0000ff01-0000-1000-8000-00805f9b34fb
value: !lambda |-
std::vector<unsigned char> rdat2{ 0x73,0x0d,0x23,0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00 };
auto time = id(sntp_time).now();
rdat2.at(4) = time.year - 1900;
rdat2.at(5) = time.month;
rdat2.at(6) = time.day_of_month;
rdat2.at(7) = time.hour;
rdat2.at(8) = time.minute;
rdat2.at(9) = time.second + 1;
int rlen = rdat2.size();
rdat2.at(1) = rlen+1;
int rxor = 0;
for (int i=0;i<rlen;i++) {
rxor = rxor ^ rdat2[i];
}
rdat2.push_back(rxor);
if (id(internal_console_dbg)) {
for (auto b : rdat2) {
ESP_LOGD("COMMAND", "%x - %i - %c", b,b,b);
}
}
return rdat2;
- globals.set:
id: ble_2_initialized
value: '1'
- id: ble_command_raw_06
parameters:
ble_device_nr: int
ble_cmd_parm: char[]
then:
- logger.log:
format: "ble command parse (raw): %i"
args: [ 'ble_device_nr']
- if:
condition:
lambda: 'return (ble_device_nr == 1);'
then:
- ble_client.ble_write:
id: bc2500_1
#service_uuid: 'ff00'
#characteristic_uuid: 'ff06'
service_uuid: 0000ff00-0000-1000-8000-00805f9b34fb
characteristic_uuid: 0000ff06-0000-1000-8000-00805f9b34fb
value: !lambda |-
std::vector<unsigned char> rdat1;
for (auto b : ble_cmd_parm) {
rdat1.push_back((unsigned char)b);
}
/*
int rlen = rdat1.size();
rdat1.at(1) = rlen+1;
int rxor = 0;
for (int i=0;i<rlen;i++) {
rxor = rxor ^ rdat1[i];
}
rdat1.push_back(rxor);
*/
//if (id(internal_console_dbg)) {
for (auto b : rdat1) {
ESP_LOGD("COMMAND raw", "%x - %i - %c", b,b,b);
}
//}
return rdat1;
- if:
condition:
lambda: 'return (ble_device_nr == 2);'
then:
- ble_client.ble_write:
id: bc2500_2
#service_uuid: 'ff00'
#characteristic_uuid: 'ff06'
service_uuid: 0000ff00-0000-1000-8000-00805f9b34fb
characteristic_uuid: 0000ff06-0000-1000-8000-00805f9b34fb
value: !lambda |-
std::vector<unsigned char> rdat2;
for (auto b : ble_cmd_parm) {
rdat2.push_back((unsigned char)b);
}
/*
int rlen = rdat2.size();
rdat2.at(1) = rlen+1;
int rxor = 0;
for (int i=0;i<rlen;i++) {
rxor = rxor ^ rdat2[i];
}
rdat2.push_back(rxor);
*/
//if (id(internal_console_dbg)) {
for (auto b : rdat2) {
ESP_LOGD("COMMAND raw", "%x - %i - %c", b,b,b);
}
//}
return rdat2;
- id: ble_process
then:
- if:
condition:
- lambda: 'return (id(ble_1_connected) && id(ble_1_initialized));'
then:
- script.execute:
id: ble_runtime_query
ble_device_nr: 1
- script.wait: ble_runtime_query
### query cmd30 if firmware > 1.30
- if:
condition:
- lambda: 'return (id(sensor_device_version_1).state * 100 > 130);'
then:
- script.execute:
id: ble_runtime_query30
ble_device_nr: 1
- script.wait: ble_runtime_query30
- script.execute:
id: ble_runtime_query0F
ble_device_nr: 1
- script.wait: ble_runtime_query0F
### query deviceinfo if empty
- if:
condition:
- lambda: 'return (id(txt_A03_1).state == "");'
then:
- script.execute:
id: ble_command_simple
ble_device_nr: 1
ble_cmd: 0x04
ble_cmd_parm: 0x01
- script.wait: ble_command_simple
- if:
condition:
- lambda: 'return (id(ble_2_connected) && id(ble_2_initialized));'
then:
- script.execute:
id: ble_runtime_query
ble_device_nr: 2
- script.wait: ble_runtime_query
### query cmd30 if firmware > 1.30
- if:
condition:
- lambda: 'return (id(sensor_device_version_2).state * 100 > 130);'
then:
- script.execute:
id: ble_runtime_query30
ble_device_nr: 2
- script.wait: ble_runtime_query30
- script.execute:
id: ble_runtime_query0F
ble_device_nr: 2
- script.wait: ble_runtime_query0F
### query deviceinfo if empty
- if:
condition:
- lambda: 'return (id(txt_A03_2).state == "");'
then:
- script.execute:
id: ble_command_simple
ble_device_nr: 2
ble_cmd: 0x04
ble_cmd_parm: 0x01
- script.wait: ble_command_simple
- id: ble_runtime_query
parameters:
ble_device_nr: int
then:
- logger.log:
format: "runtime query: %i"
args: [ 'ble_device_nr' ]
- script.execute:
id: ble_command_simple
ble_device_nr: !lambda return ble_device_nr;
ble_cmd: 0x03
ble_cmd_parm: 0x01
- script.wait: ble_command_simple
- id: ble_runtime_query30
parameters:
ble_device_nr: int
then:
- logger.log:
format: "runtime query 30: %i"
args: [ 'ble_device_nr' ]
- script.execute:
id: ble_command_simple
ble_device_nr: !lambda return ble_device_nr;
ble_cmd: 0x30
ble_cmd_parm: 0x01
- script.wait: ble_command_simple
- id: ble_runtime_query0F
parameters:
ble_device_nr: int
then:
- logger.log:
format: "runtime query 0F: %i"
args: [ 'ble_device_nr' ]
- script.execute:
id: ble_command_simple
ble_device_nr: !lambda return ble_device_nr;
ble_cmd: 0x0F
ble_cmd_parm: 0x01
- script.wait: ble_command_simple
- id: ble_powerout
parameters:
ble_device_nr: int
then:
- lambda: |-
int ble_cmd_t = 0x00;
if ( ble_device_nr == 1 ) {
if ( ! id(switch_powerout_1_1).state && ! id(switch_powerout_1_2).state ) { ble_cmd_t = 0x00; }
if ( id(switch_powerout_1_1).state && ! id(switch_powerout_1_2).state ) { ble_cmd_t = 0x01; }
if ( ! id(switch_powerout_1_1).state && id(switch_powerout_1_2).state ) { ble_cmd_t = 0x02; }
if ( id(switch_powerout_1_1).state && id(switch_powerout_1_2).state ) { ble_cmd_t = 0x03; }
}
if ( ble_device_nr == 2 ) {
if ( ! id(switch_powerout_2_1).state && ! id(switch_powerout_2_2).state ) { ble_cmd_t = 0x00; }
if ( id(switch_powerout_2_1).state && ! id(switch_powerout_2_2).state ) { ble_cmd_t = 0x01; }
if ( ! id(switch_powerout_2_1).state && id(switch_powerout_2_2).state ) { ble_cmd_t = 0x02; }
if ( id(switch_powerout_2_1).state && id(switch_powerout_2_2).state ) { ble_cmd_t = 0x03; }
}
id(ble_command_simple).execute(ble_device_nr,0x0E,ble_cmd_t);
if (ble_cmd_t == 0x00) { ESP_LOGD("set_power_out", "Device %i - %s", ble_device_nr,"1 OFF / 2 OFF"); }
if (ble_cmd_t == 0x01) { ESP_LOGD("set_power_out", "Device %i - %s", ble_device_nr,"1 ON / 2 OFF"); }
if (ble_cmd_t == 0x02) { ESP_LOGD("set_power_out", "Device %i - %s", ble_device_nr,"1 OFF / 2 ON"); }
if (ble_cmd_t == 0x03) { ESP_LOGD("set_power_out", "Device %i - %s", ble_device_nr,"1 ON / 2 ON"); }
- id: ble_passthrough
parameters:
ble_device_nr: int
switch_cmd: bool
then:
- logger.log:
format: "PV2 Passthrough %i : %i"
args: [ble_device_nr,switch_cmd]
- script.execute:
id: ble_command_simple
ble_device_nr: !lambda return ble_device_nr;
ble_cmd: 0x0D
ble_cmd_parm: !lambda return switch_cmd;
- id: ble_set_dod
parameters:
ble_device_nr: int
dod: int
then:
- logger.log:
format: "set DOD: %i"
args: [ 'dod' ]
- if:
condition:
lambda: 'return ( dod <= 100 && dod >= 10);'
then:
- script.execute:
id: ble_command_simple
ble_device_nr: !lambda return ble_device_nr;
ble_cmd: 0x0B
ble_cmd_parm: !lambda return dod;
- id: ble_set_discharge_treshold
parameters:
ble_device_nr: int
discharge: int
then:
- logger.log:
format: "set discharge level: %i"
args: [ 'discharge' ]
- if:
condition:
lambda: 'return ( discharge <= 500 && discharge >= 1);'
then:
- script.execute:
id: ble_command_simple
ble_device_nr: !lambda return ble_device_nr;
ble_cmd: 0x0C
ble_cmd_parm: !lambda return discharge;
- id: ble_notify_parse_test
parameters:
ble_device_nr: int
x: char[]
then:
- logger.log:
format: "runtime parse: %i"
args: [ 'ble_device_nr' ]
- lambda: |-
//if (id(internal_console_dbg)) {
ESP_LOGD("parse test", "x[3] = %i", x[3]);
for (auto b : x) {
ESP_LOGD("data test", "%.2x \t %i \t %c", b,b,b);
}
//}
- id: ble_notify_parse
parameters:
ble_device_nr: int
x: char[]
then:
- logger.log:
format: "runtime parse: %i"
args: [ 'ble_device_nr' ]
- lambda: |-
ESP_LOGD("notify_parse", "Device: %i", ble_device_nr);
if (id(internal_console_dbg)) {
ESP_LOGD("parse", "x[3] = %i", x[3]);
for (auto b : x) {
ESP_LOGD("data", "%.2x \t %i \t %c", b,b,b);
}
}
if (id(switch_debug_hexdump).state == true) {
ESP_LOG_BUFFER_HEXDUMP("hexdump", &x[0], x.size(), ESP_LOG_ERROR);
}
if ((std::count (x.begin(), x.end(), '_') == 16) || (std::count (x.begin(), x.begin() + 10, '_') == 3))
{
ESP_LOGD("main", "Data: cmd 0x0F");
int pos = 0;
int soc = 0;
int t1 = 0;
int t2 = 0;
float cv = 0.0;
float cmin = std::numeric_limits<float>::max();
float cmax = std::numeric_limits<float>::min();
float ct = 0.0;
int found = -1;
char delimiter = '_';
std::string xstr;
std::vector<float> cellV;
xstr.assign(x.begin(), x.end()); // copy values from vector into string xstr, deep copy
xstr = xstr + delimiter; // append delimiter to xstr
found = xstr.find(delimiter); // search for position of the first delimiter
while (found != -1) // loop until no more delimiter found
{
if(pos == 0) soc = atoi( xstr.substr(0, found).c_str()); // pos 0 don't care
if(pos == 1) t1 = atoi( xstr.substr(0, found).c_str()); // pos 1 get int value of temperature sensor 1
if(pos == 2) t2 = atoi( xstr.substr(0, found).c_str()); // pos 2 get int value of temperature sensor 2
if((pos >= 3) && (pos <= 16)) // pos 3-16 parse pos for the 14 cell voltages
{
ct = atof( xstr.substr(0, found).c_str()); // get float value of pos x
cellV.push_back(ct);
//ESP_LOGD("cell voltage", ct.c_str());
cv += ct; // add actual value to var cv
if(ct > cmax) cmax = ct; // check for higher value as stored in cmax
if(ct < cmin) cmin = ct; // check for lower value as stored in cmin
}
xstr.erase(xstr.begin(), xstr.begin() + found + 1); // remove parsed string part
found = xstr.find(delimiter); // find next delimiter
pos++; // increment pos
}
/* calculate SoC from cell voltages
cell empty = 3.0 Volt = 0% SoC
cell full = 3.5 Volt = 100% SoC
*/
// float soccalc = (cv/14000 - 3.0) * 200;
float lowlimit = 3.0; // low voltage limit
float highlimit = 3.5; // high voltage limit
float soccalc = 100*((cv/14000)
- highlimit)/(highlimit - lowlimit) + 100; // equation of line with two points (0,lowlimit) (100,highlimit)
ESP_LOGD("cellVoltage","soc: %i, temp1: %i, temp2: %i",soc,t1,t2);
ESP_LOGD("cellVoltage","cell01: %.f, cell 02: %.f, cell 03: %.f, cell 04: %.f", cellV[0], cellV[1], cellV[2], cellV[3]);
ESP_LOGD("cellVoltage","cell05: %.f, cell 06: %.f, cell 07: %.f, cell 08: %.f", cellV[4], cellV[5], cellV[6], cellV[7]);
ESP_LOGD("cellVoltage","cell09: %.f, cell 10: %.f, cell 11: %.f, cell 12: %.f", cellV[8], cellV[9], cellV[10], cellV[11]);
ESP_LOGD("cellVoltage","cell13: %.f, cell 14: %.f", cellV[12], cellV[13]);
char mtopic[48];
for (int i=0; i<14; i++) {
snprintf(mtopic, 48,"b2500/%i/battery/cells/%02d/voltage",ble_device_nr,i+1);
//ESP_LOGD("cellVoltageX","%s : %f", mtopic, cellV[i]);
id(mqtt_client).publish(mtopic,to_string(cellV[i]/1000));
}
snprintf(mtopic, 48,"b2500/%i/battery/cells/sum/voltage",ble_device_nr);
id(mqtt_client).publish(mtopic,to_string(cv/1000));
snprintf(mtopic, 48,"b2500/%i/battery/cells/sum/cmin",ble_device_nr);
id(mqtt_client).publish(mtopic,to_string(cmin/1000));
snprintf(mtopic, 48,"b2500/%i/battery/cells/sum/cmax",ble_device_nr);
id(mqtt_client).publish(mtopic,to_string(cmax/1000));
snprintf(mtopic, 48,"b2500/%i/battery/cells/sum/cavg",ble_device_nr);
id(mqtt_client).publish(mtopic,to_string(cv/14000));
snprintf(mtopic, 48,"b2500/%i/battery/cells/sum/cdiff",ble_device_nr);
id(mqtt_client).publish(mtopic,to_string((cmax-cmin)/1000));
snprintf(mtopic, 48,"b2500/%i/battery/cells/sum/soccalc",ble_device_nr);
id(mqtt_client).publish(mtopic,to_string(soccalc));
snprintf(mtopic, 48,"b2500/%i/battery/temp1",ble_device_nr);
id(mqtt_client).publish(mtopic,to_string(t1));
snprintf(mtopic, 48,"b2500/%i/battery/temp2",ble_device_nr);
id(mqtt_client).publish(mtopic,to_string(t2));
/*
id(bcsoc).publish_state(soc); // SOC from device (%)
id(bcsoccalc).publish_state(soccalc); // SOC calculated from cell voltages (%)
id(bctemp1).publish_state(t1); // Temperature 1 (°C)
id(bctemp2).publish_state(t2); // Temperature 2 (°C)
id(bccvsum).publish_state(cv/1000); // sum of cellvoltages = battery Voltage(V)
id(bccvmin).publish_state(cmin/1000); // lowest cellvoltage (V)
id(bccvmax).publish_state(cmax/1000); // highest cellvoltage (V)
id(bccvdiff).publish_state((cmax-cmin)/1000);
id(bccvavg).publish_state(cv/14000); // avarage cellvoltage (V)
*/
}
else if (x[3] == 0x03) {
ESP_LOGD("main", "Data: runtimeInfo ");
//sensor
// pv_level 1 und 2
/*
[6][7] PV-Eingangsleistung 1 (2Byte)
[8][9] PV-Eingangsleistung 2 (2Byte)
x[Y] | x[Z] << 8;
*/
int pvPower1 = x[6] | x[7] << 8;
int pvPower2 = x[8] | x[9] << 8;
if (ble_device_nr==1) { id(sensor_pv_power_in_1_1).publish_state(pvPower1); id(sensor_pv_power_in_1_2).publish_state(pvPower2); }
if (ble_device_nr==2) { id(sensor_pv_power_in_2_1).publish_state(pvPower1); id(sensor_pv_power_in_2_2).publish_state(pvPower2); }
// Batterie Stand in %
/*
[10][11] Verbleibende Batteriekapazität in Prozent (2Byte)
x[Y] | x[Z] << 8;
*/
int batRemain = x[10] | x[11] << 8 ;
if (ble_device_nr==1) { id(sensor_bat_remain_1).publish_state(batRemain / 10); }
if (ble_device_nr==2) { id(sensor_bat_remain_2).publish_state(batRemain / 10); }
// Entladen bei weniger als ??? Watt PV Eingang
/*
[19][20] Entladeschwelle(2Byte)
x[Y] | x[Z] << 8;
*/
int disCharge = x[19] | x[20] << 8;
if (ble_device_nr==1) { id(sensor_discharge_treshold_1).publish_state(disCharge); }
if (ble_device_nr==2) { id(sensor_discharge_treshold_2).publish_state(disCharge); }
// Füllstand des Akkus in Wh
/*
[22][23] Gesamtkapazität der Batterie (1Byte)
x[Y] | x[Z] << 8;
*/
int batCapacity = x[22] | x[23] << 8;
if (ble_device_nr==1) { id(sensor_bat_capacity_1).publish_state(batCapacity); }
if (ble_device_nr==2) { id(sensor_bat_capacity_2).publish_state(batCapacity); }
// Ausgangsleistung in Watt
/*
[24][25] Ausgangsleistung 1(1Byte)
[26][27] Ausgangsleistung 2(1Byte)
x[Y] | x[Z] << 8;
*/
int powerOut1 = x[24] | x[25] << 8;
int powerOut2 = x[26] | x[27] << 8;
if (ble_device_nr==1) { id(sensor_power_out_1_1).publish_state(powerOut1); id(sensor_power_out_1_2).publish_state(powerOut2); }
if (ble_device_nr==2) { id(sensor_power_out_2_1).publish_state(powerOut1); id(sensor_power_out_2_2).publish_state(powerOut2); }
// Geräte Version ( Firmware ? )
/*
[12] B2500 Geräteversion (1Byte)
0-255 ( ~ anzeige als /100 )
*/
float dev_version = x[12];
if (ble_device_nr==1) { id(sensor_device_version_1).publish_state(dev_version / 100); }
if (ble_device_nr==2) { id(sensor_device_version_2).publish_state(dev_version / 100); }
//
/*
[18] Dod (1Byte)
0-100 Prozentualer Anteil der Entladeleistung an der Nennleistung
*/
int dod_level = x[18];
if (ble_device_nr==1) { id(sensor_dod_1).publish_state(dod_level); }
if (ble_device_nr==2) { id(sensor_dod_2).publish_state(dod_level); }
// binary sensor / bool
// pv 1 und 2 in
/*
[x4] PV IN 1 Zustand (1Byte)
[x5] PV IN 2 Zustand (1Byte)
0x00 (off)
0x01 (Aufladung)
0x02 (transparent für Wechselrichter)
*/
if (ble_device_nr==1) {
if( x[4] == 0x00 ) { id(bool_pv_active_1_1).publish_state(false);id(bool_pv_transparent_1_1).publish_state(false); }
if( x[4] == 0x01 ) { id(bool_pv_active_1_1).publish_state(true); id(bool_pv_transparent_1_1).publish_state(false); }
if( x[4] == 0x02 ) { id(bool_pv_active_1_1).publish_state(true); id(bool_pv_transparent_1_1).publish_state(true); }
if( x[5] == 0x00 ) { id(bool_pv_active_1_2).publish_state(false);id(bool_pv_transparent_1_2).publish_state(false); }
if( x[5] == 0x01 ) { id(bool_pv_active_1_2).publish_state(true); id(bool_pv_transparent_1_2).publish_state(false); }
if( x[5] == 0x02 ) { id(bool_pv_active_1_2).publish_state(true); id(bool_pv_transparent_1_2).publish_state(true); }
}
if (ble_device_nr==2) {
if( x[4] == 0x00 ) { id(bool_pv_active_2_1).publish_state(false);id(bool_pv_transparent_2_1).publish_state(false); }
if( x[4] == 0x01 ) { id(bool_pv_active_2_1).publish_state(true); id(bool_pv_transparent_2_1).publish_state(false); }
if( x[4] == 0x02 ) { id(bool_pv_active_2_1).publish_state(true); id(bool_pv_transparent_2_1).publish_state(true); }
if( x[5] == 0x00 ) { id(bool_pv_active_2_2).publish_state(false);id(bool_pv_transparent_2_2).publish_state(false); }
if( x[5] == 0x01 ) { id(bool_pv_active_2_2).publish_state(true); id(bool_pv_transparent_2_2).publish_state(false); }
if( x[5] == 0x02 ) { id(bool_pv_active_2_2).publish_state(true); id(bool_pv_transparent_2_2).publish_state(true); }
}
// pv 2 durchleiten
/*
[13] Einstellung des Ladevorgangs (1Byte)
0x00 (PV1 Aufladung PV2 Durchleitung)
0x01 (Volles Laden und Entladen)
*/
if (ble_device_nr==1) {
if( x[13] == 0x00 ) { id(switch_pv2_passthrough_1).turn_on(); }
if( x[13] == 0x01 ) { id(switch_pv2_passthrough_1).turn_off(); }
}
if (ble_device_nr==2) {
if( x[13] == 0x00 ) { id(switch_pv2_passthrough_2).turn_on(); }
if( x[13] == 0x01 ) { id(switch_pv2_passthrough_2).turn_off(); }
}
// RESERVED ( wifi / mqtt )
/*
[15] Reserve(1Byte)
0x00 wifi funktioniert nicht
0x01 wifi ok, mqtt nicht verbunden
0x02 wifi ok, mqtt connect ok
??? 0x03 wifi ok, mqtt1 connect ok, mqtt2 connect ok
maybe wifi / mqtt
00 = false / false
01 = true / false
02 = false / true
03 = true / true
-------
first part means not wifi connected ?!?!?
00 = ??? / mqtt not connected
01 = ??? / mqtt not connected
02 = ??? / mqtt connected
03 = ??? / mqtt connected
*/
// wifi and mqtt, 03 maybe webserver
if (ble_device_nr==1) {
if( x[15] == 0x00 ) { id(bool_wifi_ok_1).publish_state(false); id(bool_mqtt1_ok_1).publish_state(false); }
if( x[15] == 0x01 ) { id(bool_wifi_ok_1).publish_state(true); id(bool_mqtt1_ok_1).publish_state(false);}
if( x[15] == 0x02 ) { id(bool_wifi_ok_1).publish_state(false); id(bool_mqtt1_ok_1).publish_state(true); }
if( x[15] == 0x03 ) { id(bool_wifi_ok_1).publish_state(true); id(bool_mqtt1_ok_1).publish_state(true); }
}
if (ble_device_nr==2) {
if( x[15] == 0x00 ) { id(bool_wifi_ok_2).publish_state(false); id(bool_mqtt1_ok_2).publish_state(false); }
if( x[15] == 0x01 ) { id(bool_wifi_ok_2).publish_state(true); id(bool_mqtt1_ok_2).publish_state(false); }
if( x[15] == 0x02 ) { id(bool_wifi_ok_2).publish_state(false); id(bool_mqtt1_ok_2).publish_state(true); }
if( x[15] == 0x03 ) { id(bool_wifi_ok_2).publish_state(true); id(bool_mqtt1_ok_2).publish_state(true); }
}
// power 1 und 2 enabled/disabled
/*
[14] Entlade-Modus / Enabled (1Byte)
0x00 OUT1&OUT2 Sperren
0x01 nur OUT1 Freigabe
0x02 nur OUT2 Freigabe
0x03 OUT1&OUT2 Freigabe
*/
if (ble_device_nr==1) {
if( x[14] == 0x00 ) { id(switch_powerout_1_1).turn_off(); id(switch_powerout_1_2).turn_off();}
if( x[14] == 0x01 ) { id(switch_powerout_1_1).turn_on(); id(switch_powerout_1_2).turn_off();}
if( x[14] == 0x02 ) { id(switch_powerout_1_1).turn_off(); id(switch_powerout_1_2).turn_on(); }
if( x[14] == 0x03 ) { id(switch_powerout_1_1).turn_on(); id(switch_powerout_1_2).turn_on(); }
}
if (ble_device_nr==2) {
if( x[14] == 0x00 ) { id(switch_powerout_2_1).turn_off(); id(switch_powerout_2_2).turn_off();}
if( x[14] == 0x01 ) { id(switch_powerout_2_1).turn_on(); id(switch_powerout_2_2).turn_off();}
if( x[14] == 0x02 ) { id(switch_powerout_2_1).turn_off(); id(switch_powerout_2_2).turn_on(); }
if( x[14] == 0x03 ) { id(switch_powerout_2_1).turn_on(); id(switch_powerout_2_2).turn_on(); }
}
// power 1 und 2 active
/*
[16] Ausgang Port 1 Status (1Byte)
[17] Ausgang Port 2 Status (1Byte)
0x00(Aus)
0x01(Entladung)
*/
if (ble_device_nr==1) {
if( x[16] == 0x00 ) { id(bool_power_active_1_1).publish_state(false);}
if( x[16] == 0x01 ) { id(bool_power_active_1_1).publish_state(true); }
if( x[17] == 0x00 ) { id(bool_power_active_1_2).publish_state(false);}
if( x[17] == 0x01 ) { id(bool_power_active_1_2).publish_state(true); }
}
if (ble_device_nr==2) {
if( x[16] == 0x00 ) { id(bool_power_active_2_1).publish_state(false);}
if( x[16] == 0x01 ) { id(bool_power_active_2_1).publish_state(true); }
if( x[17] == 0x00 ) { id(bool_power_active_2_2).publish_state(false);}
if( x[17] == 0x01 ) { id(bool_power_active_2_2).publish_state(true); }
}
// zusatzakku 1 und 2
/*
[28] Ist Netzgerät 1 angeschlossen (1Byte)
[29] Ist Netzgerät 2 angeschlossen (1Byte)
0x00(Kein Akkupack angeschlossen)
0x01(Verbinden Sie das Netzteil)
*/
if (ble_device_nr==1) {
if( x[28] == 0x00 ) { id(bool_extern_connected_1_1).publish_state(false);}
if( x[28] == 0x01 ) { id(bool_extern_connected_1_1).publish_state(true); }
if( x[29] == 0x00 ) { id(bool_extern_connected_1_2).publish_state(false);}
if( x[29] == 0x01 ) { id(bool_extern_connected_1_2).publish_state(true); }
}
if (ble_device_nr==2) {
if( x[28] == 0x00 ) { id(bool_extern_connected_2_1).publish_state(false);}
if( x[28] == 0x01 ) { id(bool_extern_connected_2_1).publish_state(true); }
if( x[29] == 0x00 ) { id(bool_extern_connected_2_2).publish_state(false);}
if( x[29] == 0x01 ) { id(bool_extern_connected_2_2).publish_state(true); }
}
if (ble_device_nr==1) {
auto call_21 = id(txt_scene_1).make_call();
if( x[21] == 0x00 ) { call_21.set_value("Tag"); }
if( x[21] == 0x01 ) { call_21.set_value("Nacht"); }
if( x[21] == 0x02 ) { call_21.set_value("Morgens/Abends"); }
call_21.perform();
}
if (ble_device_nr==2) {
auto call_21 = id(txt_scene_2).make_call();
if( x[21] == 0x00 ) { call_21.set_value("Tag"); }
if( x[21] == 0x01 ) { call_21.set_value("Nacht"); }
if( x[21] == 0x02 ) { call_21.set_value("Morgens/Abends"); }
call_21.perform();
}
if (ble_device_nr==1) {
auto call_30 = id(txt_region_1).make_call();
if( x[30] == 0x00 ) { call_30.set_value("EU"); }
if( x[30] == 0x01 ) { call_30.set_value("China"); }
if( x[30] == 0x02 ) { call_30.set_value("non-EU"); }
call_30.perform();
}
if (ble_device_nr==2) {
auto call_30 = id(txt_region_2).make_call();
if( x[30] == 0x00 ) { call_30.set_value("EU"); }
if( x[30] == 0x01 ) { call_30.set_value("China"); }
if( x[30] == 0x02 ) { call_30.set_value("non-EU"); }
call_30.perform();
}
}
else if (x[3] == 0x04) {
ESP_LOGD("main", "Data: deviceInfo ");
//for (auto b : x) {
// ESP_LOGD("data", "%i", b);
//}
// 's<#?type=<5>,id=<24>,mac=<12>t'
// ESP_LOGD("data", "%s", vType);
int data_len = x.size();
unsigned char vType[8];
for (int i=9;i<14;i++) {
vType[i-9] = x[i];
}
vType[5] = 0x00;
unsigned char vID[32];
for (int i=18;i<42;i++) {
vID[i-18] = x[i];
}
vID[24]=0x00;
unsigned char vMac[16];
for (int i=47;i<59;i++) {
vMac[i-47] = x[i];
}
vMac[12] = 0x00;
ESP_LOGD("deviceInfo", "%i: %s [%s] %s", data_len,vType,vMac,vID);
std::string sType(reinterpret_cast<char*>(vType));
std::string sID(reinterpret_cast<char*>(vID));
std::string sMac(reinterpret_cast<char*>(vMac));
if (ble_device_nr==1) { id(txt_A01_1).publish_state(sType); id(txt_A02_1).publish_state(sID); id(txt_A03_1).publish_state(sMac); }
if (ble_device_nr==2) { id(txt_A01_2).publish_state(sType); id(txt_A02_2).publish_state(sID); id(txt_A03_2).publish_state(sMac); }
}
// get wifi info - "admin mode" only
else if (x[3] == 0x08) {
ESP_LOGD("main", "Data: wifiInfo ");
int data_len = x.size();
unsigned char vSSID[32];
for (int i=4;i<data_len-1;i++) {
vSSID[i-4] = x[i];
}
vSSID[data_len-5] = 0x00;
ESP_LOGD("deviceInfo", "%i: %s", data_len,vSSID);
std::string sSSID(reinterpret_cast<char*>(vSSID));
if (ble_device_nr==1) { id(txt_A11_1).publish_state(sSSID); }
if (ble_device_nr==2) { id(txt_A11_2).publish_state(sSSID); }
for (auto b : x) {
ESP_LOGD("data", "%x \t %i \t %x", b,b,b);
}
}
else if (x[3] == 0x30) {
ESP_LOGD("main", "Data: cmd 0x30 ");
int data_len = x.size();
int data_pos = 0;
int rxor = 0;
for (int i=0;i<data_len;i++) {
rxor = rxor ^ x[i];
}
/*
//if( rxor != id(cmd30_xor_last_1) ) {
ESP_LOGD("data 30 - raw" , "Device %i",ble_device_nr);
ESP_LOGD("data 30 - raw" , "0x%.2x 0x%.2x 0x%.2x 0x%.2x", x[0], x[1], x[2], x[3]);
for(int i=4;i<data_len-1;i++) {
ESP_LOGD("data 30 - raw" , "0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x", x[i], x[i+1], x[i+2], x[i+3], x[i+4],x[i+5],x[i+6],x[i+7],x[i+8]);
i += 8;
}
//ESP_LOGD("data 30 - raw" , " ");
id(cmd30_xor_last_1) = rxor;
//}
*/
}
/*
else if (x[3] == 0x30) {
ESP_LOGD("main", "Data: cmd 0x30");
int data_len = x.size();
for(int i=0;i<data_len;i++) {
int d1 = x[i];
ESP_LOGD("data 30" , "%x \t %i \t %c" , d1, d1, char(d1));
}
}
*/
// debug ???
else if (x[3] == 0x01) {
ESP_LOGD("main", "Data: cmd 0x01");
int data_len = x.size();
for(int i=0;i<data_len;i++) {
int d1 = x[i];
ESP_LOGD("data 01" , "%x \t %i \t %c" , d1, d1, char(d1));
}
}
else if (x[3] == 0x81) {
ESP_LOGD("main", "Data: cmd 0x81");
int data_len = x.size();
for(int i=0;i<data_len;i++) {
int d1 = x[i];
ESP_LOGD("data 81" , "%x \t %i \t %c" , d1, d1, char(d1));
}
}
else {
/*int data_len = x.size();
for(int i=0;i<data_len;i++) {
int d1 = x[i];
ESP_LOGD("unknown" , "%x \t %i \t %c" , d1, d1, char(d1));
}
*/
ESP_LOG_BUFFER_HEXDUMP("hexdump", &x[0], x.size(), ESP_LOG_ERROR);
}
- id: power_zero
then:
### Nulleinspeisung - Powerzero by neromatrix
### - mqtt only adaption by noone2k
### first attempt, use at your own risk !
### Ver. 0.01m
- lambda: |-
if(id(switch_opendtu_limit).state)
{
int ptu_min_value = 5;
int ptu_max_value = id(mqtt_opendtu_limit_max).state; // 50; // <- nax rel value -> id(npw2500_zeropower_max_powerlimit_rel).state;
int ptu_limit = 0;
int ptu_max_power = 900; // max:2 (x:4*2 for 4port using 2port)
int grid_to_ptu_ratio = ptu_max_power/100;
int grid_min_value = 20;
static int ptu_old_limit = 0;
/*
<- actual power mqtt -> prev. int(id(npw2500_grid_power).state);
keep over grid_min_value
*/
int grid_value = int(id(mqtt_grid_power).state) - grid_min_value;;
ptu_limit = grid_value / grid_to_ptu_ratio + ptu_old_limit;
if(ptu_limit > ptu_max_value) ptu_limit = ptu_max_value;
if(ptu_limit < ptu_min_value) ptu_limit = ptu_min_value;
// change only if diff more than +/-1%
if ( ptu_limit - ptu_old_limit > 1 || ptu_old_limit - ptu_limit > 1 ) {
ESP_LOGD("npw2500","PowerZero PTU old limit %d, PTU new limit %d, Grid value %d " ,ptu_old_limit, ptu_limit, grid_value);
ptu_old_limit = ptu_limit;
//char mtopic[64];
//snprintf(mtopic, 64,"openDTU/XXXXXXXXXXX/cmd/limit_persistent_relative");
//id(mqtt_client).publish(mtopic,to_string(ptu_limit));
id(mqtt_opendtu_limit).publish_state(ptu_limit);
}
}
@sensiebel
Copy link

Hallo und vielen Dank für das tolle Projekt!
Allerdings scheitere ich am Programmieren meines wemos_d1_mini32 über ESPHome: "Error - The program size (1844213 bytes) is greater than maximum allowed (1835008 bytes)".
dabei soll das Gerät 2MB haben... Wie kann ich das beheben? Alle ESP-Modelle und ESP-Home sind ja mit 320KiB definiert?
Vielen Dank von einem HA-Newbie!

@tbretz65
Copy link

tbretz65 commented Jun 21, 2024

@sensiebel
Ist/War das ein neuer wemos ?
Wenn neu, dann deaktiviere mal folgende Zeilen:
`web_server:
port: 80
local: true
js_include: "./v2/www.js"
js_url: ""
version: 2

captive_portal:`
einfach vor jede Zeile ein # machen
Danach noch mal kompilieren und auf den wemos aufspielen

Ich habe es an einem wemosD1-mini32 getestet.
Bei mir funktioniert alles. (ohne deaktivieren des web-server)

@gine78
Copy link

gine78 commented Jun 21, 2024

Morgen oder übermorgen kommt das Smartmeter, mal sehen ob das schon vernünftig funktioniert…

@vogty79 kannst du berichten ob das Ding was taugt?

@azazul1980
Copy link

Morgen oder übermorgen kommt das Smartmeter, mal sehen ob das schon vernünftig funktioniert…

@vogty79 kannst du berichten ob das Ding was taugt?

Also in der Facebook Gruppe wird gesagt das der Smartmeter nicht richtig funktioniert.

@gine78
Copy link

gine78 commented Jun 21, 2024

Mich interessiert vielmehr. Welchen Wert das Ding ändert, also wie spricht das Ding den Speicher an. Dann könnte man das über einen bitshake, Shelly oder ähnlichen, nachbauen.

Kannst du die FB Gruppe hier verlinken?

@azazul1980
Copy link

@7Netler
Copy link

7Netler commented Jun 21, 2024

https://github.com/tomquist/b2500-meter?fbclid=IwZXh0bgNhZW0CMTEAAR17eCk2GI_oz3gHHtdxkb8wVwZcVlXXHTC8zKoB_F8u9ya7RzjA_y8OWzI_aem_ZmFrZWR1bW15MTZieXRlcw

Ich verlinke mal das Projekt zum Thema smart Meter.

Ist ja nice. Ist das Script auch auf homeassistant selber installierbar ? Mir scheint da der ssh zugriff zu eingeschränkt zu sein oder täusche ich mich da oder bin einfach nicht fähig ;) ?!

@fefi-byte
Copy link

Gibt auch was für node red. Und loft bei mir.
Finde aber das es semi gut läuft. Das Script macht seine Arbeit gut. Nur scheint der Speicher nicht so gut regeln zu können. Kann aber auch an meinem Software stand liegen. V163

@sensiebel
Copy link

Gibt auch was für node red. Und loft bei mir. Finde aber das es semi gut läuft. Das Script macht seine Arbeit gut. Nur scheint der Speicher nicht so gut regeln zu können. Kann aber auch an meinem Software stand liegen. V163

Was gibt's denn für node-Red? Damit regle ich momentan meine 5 Solarpanels, wovon 2 am B2500 hängen.

@sensiebel
Copy link

@tbretz65

@sensiebel Ist/War das ein neuer wemos ? Wenn neu, dann deaktiviere mal folgende Zeilen: web_server: port: 80 local: true js_include: "./v2/www.js" js_url: "" version: 2 captive_portal: einfach vor jede Zeile ein # machen Danach noch mal kompilieren und auf den wemos aufspielen

Hallo Danke für die Hilfe: Es war ein funkelangelneuer wemos, allerdings mit Web ESP Home schon mit Firmware bespielt - habe ein neues Gerät in ESPHome angelegt, und damit ging's dann....
Die auszukommentierenden Zeilen hatte ich schon weggelöscht, um jedes Byte zu sparen. Die Frage nach "neu" hat mich dann auf die richtige Spur gebracht!

ABER: In der Config habe ich keine Credentials für den mqtt-Broker mitgegeben und erhalte auch keine mqtt-Nachrichten vom Wemos. Wie kann ich denn das Abonnenten-PW für mosquitto in die yaml schreiben?
Vielen Dank!!!!

@tbretz65
Copy link

tbretz65 commented Jun 21, 2024

Die Daten für MQTT Broker sollten in der secrets.yaml stehen.
Hier im yaml Zeile 44 und 45
Wenn noch ein PW benötigt wird sollte da noch password: xxx mit dazu (glaube ich)
z.B. Zeile 46 password: !secret mqtt_password

so steht es bei esphome auf der Seite:

Example configuration entry

mqtt:
broker: 10.0.0.2
username: livingroom
password: !secret mqtt_password

@sensiebel
Copy link

@tbretz65

mqtt: broker: 10.0.0.2 username: livingroom password: !secret mqtt_password

Danke - so habe ich's schon versucht, aber das funktioniert nicht - oder sendet der Client nur Nachrichten, wenn mit Bluetooth Daten ankommen? Im Moment liegt der noch auf meinem Schreibtisch....
Meine yaml:
mqtt:
id: mqtt_client
broker: !secret mqtt_broker
port: !secret mqtt_port
password: !secret mqtt_pw
discovery: False
reboot_timeout: 0s
topic_prefix: b2500

@tbretz65
Copy link

Sorry da hab ich keine Ahnung :-(
Ich selbst nutze das yaml von neromatrix (wegen HA)
Aber ich denke wenn der nix bekommt (liegt auf Schreibtisch) dann sendet der auch nix.
Musst Du halt mal mit dem Akku verbinden (denke daran nur eine BT Verbindung ist möglich, also APP aus)

@gine78
Copy link

gine78 commented Jun 21, 2024

@noone2k, über welches topic sage ich dem Speicher, dass er die selbstsnpassung nutzen soll? (Ich möchte das „smartmeter“ mal probieren)

@sensiebel
Copy link

@tbretz65 ...ich hab's - es fehlte:
mqtt:
username: !secret mqtt_user

Und er sendet vom Schreibtisch status: offline

@vogty79
Copy link

vogty79 commented Jun 21, 2024

Ich habe ja das originale Smartmeter und v210 also neuste Firmware auf dem Speicher, kann man stand jetzt noch absolut vergessen, gibt auch derzeit noch kein Update

@noone2k
Copy link
Author

noone2k commented Jun 21, 2024

@gine78

bin noch am wachwerden ... ☕
wenn meine birne nachher mitspielt, pushe ich die änderungen zur umschaltung in den adaptiven modus ins git ...
habe da aber noch nicht alle werte identifiziert ...
aber vllt. wirds einfacher zusammen mit euren logs ... umso mehr logs, umso einfacher ist ein pattern matching ;)

@noone2k
Copy link
Author

noone2k commented Jun 21, 2024

@vogty79

hast du in der app irgendwelche einstellmöglichkieten mit dem ct001 ?

@gine78
Copy link

gine78 commented Jun 21, 2024

Ich habe ja das originale Smartmeter und v210 also neuste Firmware auf dem Speicher, kann man stand jetzt noch absolut vergessen, gibt auch derzeit noch kein Update

Danke für die Info - darf ich fragen wie du zur v210 gekommen bist?

@gine78

bin noch am wachwerden ... ☕ wenn meine birne nachher mitspielt, pushe ich die änderungen zur umschaltung in den adaptiven modus ins git ... habe da aber noch nicht alle werte identifiziert ... aber vllt. wirds einfacher zusammen mit euren logs ... umso mehr logs, umso einfacher ist ein pattern matching ;)

Guten Morgen und vielen Dank.

@vogty79
Copy link

vogty79 commented Jun 21, 2024

@gine78

über Feedback Update angefragt

@noone2k
Copy link
Author

noone2k commented Jun 22, 2024

habe mal paar sachen für den adaptive mode eingecheckt ( alles untestet und noch nicht alle werte sind klar ) ...

neue topics:
b2500v2/1/smartmeter/enabled
b2500v2/1/smartmeter/enabled/set
b2500v2/1/smartmeter/connected
b2500v2/1/smartmeter/value

hoffe, wenn nächste mal zeit, das ich den rest ins git bekomme ;)

@azazul1980
Copy link

@noone2k ist das nun die Steuerung der Power über den Accu V2 ?

@noone2k
Copy link
Author

noone2k commented Jun 22, 2024

jaein, kommt darauf an, was du meinst ...

im adaptive modus ( selbstanpassung ) verbindet sich die kiste mit dem smartmeter ...
du brauchst also dazu entweder den smartmeter oder eine andere lösung,
die das udp/tcp protocol spricht ( u.a. die python-lösung von @tomquist )

ich ermögliche hiermit nur den adaptiven modus zu aktivieren und die werte,
die der speicher hat, auszulesen. ( ggf. müssen die noch etwas anders interpretiert werden ).

bei mir funktioniert die adaptive lösung momentan nicht gut genug, um damit wirklich arbeiten zu können.
damit ihr aber auch mal das testen könnt, habe ich das mal auf die schnelle eingebaut. ( oder man nimmt die app )
da brauch es ggf. noch eine fw-update ...

@noone2k
Copy link
Author

noone2k commented Jun 24, 2024

gerade die version 211.1 und 211.2 entdeckt für den v2 ... anscheinend wurde die versionierung geändert ...
mal testweise die 211.2 installiert ...
und nach nem kurzen test mit dem python-script für den smartmeter: gleiches verhalten ...

entweder haben wir bei smartmeter logs was übersehen oder es bedarf noch ne neuere firmware ....

@olympic1337
Copy link

@vogty79 Ich hab die Smartmeter-Emulation von @tomquist mal ausprobiert - prinzipiell funktioniert das bei mir mit v3-Speicher und Version v210. Allerdings führen negative Werte vom "Smart-Meter" zu nem Overflow im Speicher. Bei Cropping auf 0 ist der Speicher der Meinung, die aktuelle Einspeisung ist okay, was zu viel zu hoher Ausgangsleistung führt, wenn im Haus der Stromverbrauch sinkt. Hast du die Möglichkeit, von deinem Smartmeter nen Paketmitschnitt zu machen, was das liefert, wenn der Stromverbrauch ins negative geht?

@tomquist
Copy link

@olympic1337 Haben wir schon versucht zu erstellen, aber aus irgendeinem Grund hat der Smart Meter nie negativ gemessen, egal wie eingespeist wurde. Kann entweder daran liegen, dass er falsch verbaut ist, oder wir verstehen irgendetwas fundamental noch nicht 🤷‍♂️

@vogty79
Copy link

vogty79 commented Jun 24, 2024

Kann gerne weiter testen und nochmal einen Mitschnitt starten, aber negative Werte kann ja irgendwie nicht sein also das ich ihn falsch herum angeschlossen habe, dann würde er ja nicht hoch oder runterregeln und das spiegelverkehrt machen so meine Logik

@vogty79
Copy link

vogty79 commented Jun 24, 2024

Das Smartmeter zeigt irgendwie auch wesentlich Höhe werte als der Tasmota den ich auch verbaut habe

@tomquist
Copy link

Eine Theorie die ich hatte ist, dass der Smart Meter (warum auch immer) die Ausgangsleistung des Speichers auf den Messwert addiert, bevor er ihn zum Speicher schickt. Allerdings lässt sich das aus dem Paketmitschnitt nicht bestätigen. Der Smart Meter scheint nur mit dem Speicher zu kommunizieren.

@fefi-byte
Copy link

Hätte auch noch eine Theorie.
Vielleicht schickt der smartmeter nicht den aktuellen Verbrauch/Überschuss zum Akku sondern gleich das was der Akku ausgeben soll.

@tomquist
Copy link

Hätte auch noch eine Theorie. Vielleicht schickt der smartmeter nicht den aktuellen Verbrauch/Überschuss zum Akku sondern gleich das was der Akku ausgeben soll.

🤦‍♂️ manchmal sieht man den Wald vor lauter Bäumen nicht. Das ergibt natürlich total Sinn. Und ist eigentlich auch besser weil das bedeutet, wir können selbst die Nulleinspeisung umsetzen, ohne auf ein Update zu warten.

@olympic1337
Copy link

olympic1337 commented Jun 24, 2024

Was mich gewundert hat, ist, dass in der App 1:1 der übermittelte Wert als "Abtastleistung" ausgegeben wird. Aber vielleicht teilt der Speicher den Zahlenraum auch irgendwie auf, vl. untere 8 Bit gesetzt: Absolutleistung, obere 8 Bit gesetzt: Negativer Bereich/whatever.
Bei einzuspeisender Leistung müsste das Smartmeter irgendwie die eingespeiste Leistung des Speichers kennen, oder? Außer er trackt das differenziell, ausgehend davon, dass der Speicher immer 0W einspeist, wenn den Zähler das Ack erreicht.

Edit: Meine beiden Theorien passen nicht. Wenn man -1 übermittelt, sagt die App irgendwas bei 32767 rum, also keine Aufteilung der Bits. Und wenn man 0 oder 1 übermittelt, behält er fröhlich weiter den letzten eingespeisten Wert bei.

@jmk777jmk
Copy link

Nabend zusammen.
Mir ist ein seltsames Verhalten meiner Speicher aufgefallen seit ich den ESP geflasht hab.
und zwar hatte ich mich irgendwann mal gewundert, warum nur die Hälfte der eingestellten Leistung abgegeben wird und bin
darauf gestoßen, das der Ausgang 2 bei beiden Speichern über einen 24 Std.-lauf abgeschaltet wird.
Da ich die Speicher per MQTT in FHEM integriert hab, konnte ich mal eine Aufzeichnung der Readings machen.
Das sieht dann so aus...
2024-06-24 21_41_20-Home, Sweet Home und 4 weitere Seiten - Persönlich – Microsoft​ Edge

als ob die Ausgänge laufend an und aus geschaltet werden.
Die Speicher sind beides V1 mit 137 und 138 Firmware.
Ich bin etwas ratlos. Ohne den ESP laufen sie einwandfrei....

Hat das auch schon mal jmd beobachtet?

@knickohr
Copy link

Ja, ab der V136 habe ich auch so seltsame Aussetzer. Ob es jetzt „nur“ das Ein-/Ausschalten der Ausgänge ist, oder ob der Speicher sogar rebootet kann ich nicht feststellen.

Bei mir machte es das aber nur bei niedriger Leistungsabgabe.

Ich habe das schon an Schuss gemeldet, mit der V135 tritt dieses Problem nicht auf.

@vogty79
Copy link

vogty79 commented Jun 24, 2024

Das Smartmeter zeigt auch ca 70 Watt zuviel an als ein Tasmota der ja die Werte direkt vom Zähler nimmt… er zeigt auch keine negativen Werte an, Zange habe ich auch mal gedreht trotzdem nicht

IMG_3804
IMG_3803

@vogty79
Copy link

vogty79 commented Jun 24, 2024

Phase 2 und 3 sind bei mir einmal die Herdplatten und einmal der Backofen, sind im Moment ausgeschaltet, wird wenn an aber angezeigt

@olympic1337
Copy link

@vogty79 versteh ich das richtig, dass das SmartMeter ca 70W zu viel misst, aber der gemessene Wert mit dem ünereinstimmt, was es aufs Netzwerk schreibt? Phase 2 und 3 nehme ich an landen getrennt in dem String, der aufs Netzwerk geht? Zeigt dein Speicher dann auch den zu hohen gemessenen Wert als Abtastleistung an, oder passt der wieder zum Stromzähler?

@tomquist
Copy link

tomquist commented Jun 24, 2024

So, habe heute mal viel herumprobiert und dabei folgendes beobachtet:
Wenn man dem Speicher einen Wert schickt, der bei negativem Netzbezug auf 0 gerundet wird, regelt er auf Dauer immer nur hoch, aber nie wieder runter. Ich habe dann versucht stattdessen einen Absolutwert zu schicken, und siehe da, der Speicher regelt hoch und runter. Es sieht so aus, als würde er einfach immer versuchen einen Smart Meter Wert <=100VA anzupeilen. Es ist ihm dabei aber völlig egal, ob es +100VA oder -100VA sind, ist wohl beides nah genug an der 0. Es gibt da vermutlich irgendeine Heuristik, die versucht abzuschätzen, ob es sich beim aktuellen Verbrauch um einen negativen oder positiven Wert handelt. Z.B. wenn der Netzbezug kleiner als die eingespeiste Leistung ist, und der Speicher bei 800W ist, dann muss er wohl runter regeln. Wenn das Runterregeln den Verbrauch verkleinert hat, dann weiter runter regeln usw.

Das ganze funktioniert so zwar einigermaßen, ist aber halt extreeeem träge und durch die +-100VA sehr ungenau.

Ich kann morgen mal eine Option in das Script einbauen, die den Absolut-Wert verschickt.

@vogty79
Copy link

vogty79 commented Jun 25, 2024

@vogty79 versteh ich das richtig, dass das SmartMeter ca 70W zu viel misst, aber der gemessene Wert mit dem ünereinstimmt, was es aufs Netzwerk schreibt? Phase 2 und 3 nehme ich an landen getrennt in dem String, der aufs Netzwerk geht? Zeigt dein Speicher dann auch den zu hohen gemessenen Wert als Abtastleistung an, oder passt der wieder zum Stromzähler?

Ja er zeigt den zu hoch gemessenen Wert als Abtastleistung an

@jmk777jmk
Copy link

Ja, ab der V136 habe ich auch so seltsame Aussetzer. Ob es jetzt „nur“ das Ein-/Ausschalten der Ausgänge ist, oder ob der Speicher sogar rebootet kann ich nicht feststellen.

Bei mir machte es das aber nur bei niedriger Leistungsabgabe.

Ich habe das schon an Schuss gemeldet, mit der V135 tritt dieses Problem nicht auf.

Bei mir zeigt er das Verhalten aber nur wenn ich den ESP laufen lasse.
Daher hab ich so bisschen den Verdacht dass der ESP irgendwas abfragt und der Speicher damit nicht klar kommt.
und bei beiden das identische Verhalten...

@noone2k
Copy link
Author

noone2k commented Jun 25, 2024

@jmk777jmk

welchen wr hast du im einsatz ? wie angeschlossen und welche einstellungen sind aktiv ?
vllt. kann ich das morgen mal nachstellen ...

ansonsten bei schuss anfragen, ob sie dir die fw 1.35 wieder einstellen können.
es gibt auch eine 1.39, vllt. ist da der fehler bereits behoben ...
ggf. dieses erstmal einspielen und wenn das immer noch auftritt erstmal zurück 1.35 ....

//edit bin für heute afk

@robbe1912
Copy link

robbe1912 commented Jun 25, 2024

Ja, ab der V136 habe ich auch so seltsame Aussetzer. Ob es jetzt „nur“ das Ein-/Ausschalten der Ausgänge ist, oder ob der Speicher sogar rebootet kann ich nicht feststellen.

Bei mir machte es das aber nur bei niedriger Leistungsabgabe.

Ich habe das schon an Schuss gemeldet, mit der V135 tritt dieses Problem nicht auf.

ich habe heute festgestellt, dass bei V157 des marstek alles unter 150W output nicht funktioniert. die spannung fällt dabei unter 22V, wo mein wechselrichter dann die verbindung verliert.
image
die batterie kann doch bestimmt per firmware eingestellt werden, dass spannung immer über 22V bleibt, Ich hoffe die werden das patchen. Es wird ja schließlich auch die Stromstärke hoch und runter gedreht wenn man die vollen 800W einstellt.
EDIT: alles unter 190W output ist instabil. sobald die spannung im HMS-2000-4T unter 28V fällt. geht die umwandlungseffiziens runter auf 50%. dann schwankt der output extrem, und immer wieder schaltet der wechselrichter die ports ab. nach neustart gibt die batterie wieder sofort strom, aber wieder stark schwankend bis die spannung dann wieder flöten geht. ich lasse es jetzt erst mal auf 190W, auch wenn ich in der nacht nur eine grundlast von 100W habe. hauptsache das gerät läuft erst mal stabil bis das repariert wird.

@noone2k
Copy link
Author

noone2k commented Jun 26, 2024

@robbe1912

am besten erstmal die firmware updaten (lassen) .... 163 oder 210 ... ( oder 211.2, wenn offiziell verfügbar ).
bei dem v2 habe ich eine stabile spannung von ~22V, bei 80W ( mit der fw210 ca. 30 V ) ...

allerdings teste ich den v2 nur an einen string am hm600.
beide outs per sperrdiode im + an einem eingang des wr , hole da konstant nur ~ 100 watt raus,
den mehrverbrauch decken die v1 mit nulleinspeisung.

wäre mal interessant das verhalten an einem hm-1[025)00 zu testen .... momentan hängen da aber zwei v1 dran ...
bei gelegenheit mal umstecken ...

@knickohr
Copy link

Das verstehe ich jetzt aber nicht. Wie können da nur 22V raus kommen ? Also bei mir ist die Ausgangsspannung immer gleich de Batteriesummenspannung und die fällt nie unter 40V, selbst wenn das Ding leer ist 🤔

@noone2k
Copy link
Author

noone2k commented Jun 26, 2024

du hast nen v1 ? da sind die zellen mehr oder weniger direkt mit den ausgängen verbunden ...
d.h. du misst immer die aktuelle gesamte zellspannung ... ( ~ 40-50) ....
der v2 hat dc-dc wandler vorgeschaltet, um die ausspeisung zu regeln ...
es wird anscheinend nicht nur der strom, sondern auch die spannung angepasst.

durch senkung der ausgangsspannung in den neuen firmware versionen, kann man theor. auch ausgangspower absenken.
das würde auch bedeuten, wenn man da bessere werte findet, könnte man den adaptiven modus verbessern.
ob das jetzt der hintergrund der anpassung war, weiss ich jedoch nicht ...

@tomquist
Copy link

Ich kann morgen mal eine Option in das Script einbauen, die den Absolut-Wert verschickt.

Ich habe das mal gepushed, sowohl in den Node-RED flow, als auch in das Python script: https://github.com/tomquist/b2500-meter/

@knickohr
Copy link

Für V2 macht das ja alles Sinn. Ich frage mich halt warum V1 auch diese Aussetzer hat wenn es da DC-seitig nichts zu regeln gibt ? 🤔

@noone2k
Copy link
Author

noone2k commented Jun 26, 2024

habe ich schon wieder die persönliche anrede vergessen oder was überlesen ? 😁

die aussetzer müssen ja nichts miteinander zu tun haben ... es ging jetzt primär um die frage nach den 22V von @robbe1912 ...

@knickohr
Copy link

Joo, irgendwie haben wir was gemeinsam, ich sollte mir auch angewöhnen zu taggen 😇

Schuss sollte die Firmware nicht ähnlich benennen. Halt Moment, ich glaube die Versionen für die V2 fangen jetzt mit 2xx an ?

@noone2k
Copy link
Author

noone2k commented Jun 26, 2024

ja, die codebasis für den v2 und v3 wurden gemerged ...
ab 210 gibs auch subs ... also 210.22 / 210.23 / 210.26 bzw. 211.1 / 211.2 ...

die aktuellste bei der v1 scheint die 1.39 zu sein ...

hätte natürlich den vorteil, das man genauer erkennen kann, wenn es neue funktionen gibt oder es "nur" bugfix-releases sind ( wenn man sich streng an das schema hält ) ...

@knickohr
Copy link

knickohr commented Jun 26, 2024

Ich habe leider den Eindruck das sich die Entwickler seit der Vermarktung von V2 nicht mehr so richtig um V1 kümmern. Wäre natürlich schade die V1-Nutzer im Regen zurück zu lassen ☹️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment