Skip to content

Instantly share code, notes, and snippets.

@noone2k
Last active June 21, 2024 09:48
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);
}
}
@knickohr
Copy link

knickohr commented Jun 17, 2024

Tja, wenn die Connand_Topics auch bei den Buttons mit drin wären, würde es auch mit der Nachbarin, ähhh den MQTT-Reboots funktionieren 😉 Wenn ich das richtig gesehen habe fehlen alle esp32-Command_topics.

@noone2k
Copy link
Author

noone2k commented Jun 17, 2024

habe mal gepushed ...

die liste entstand aus meinen lokalen versionen.
anscheinend habe ich da was übersehen, beim aufräumen / einbetten / entfernen ...

einiges von den commands sind auch nicht in den öffentlichen versionen verfügbar ...

ich gehe die liste nochmals durch und entferne sachen. sonst kommt man da durcheinander ...

@knickohr
Copy link

Kein Blutdruck ! Solange ich das noch selbst raus finde und einbauen kann ist alles OK. Nur laufen halt Deine Version und meine immer weiter auseinander. Man kann das jetzt schon nicht mehr automatisch zusammenführen 😢

@noone2k
Copy link
Author

noone2k commented Jun 17, 2024

fehler passieren ... wenn man nicht darauf hingewiesen wird, kann man diese auch nicht beheben ( wenn es welche sind und es notwendig ist ).

mein selbstwertgefühl ist stark genug um fehler einzugestehen 😁

//edit

meine "produktive" version ist auch anders als die im git ... das ist ne grundlage für alle ...
nur funktionen, die allgemein nützlich sind, werden ins git portiert.
und dabei passieren fehler ;)

wenn du was allgemein nützliches hast, kannst du auch pull request machen ( oder fehler für alle korrigieren )...
nicht alle änderungen, die ich hier nutze, sind für alle nützlich ...

@jmk777jmk
Copy link

@noone2k
Erstmal super Arbeit...ich wünschte ich könnte das auch so...
Da ich leider gar nicht programmieren kann und auch eher nur so ein Bisschen in FHEM rum bastele, hab ich versucht über diese Möglichkeit und MQTT die Speicher in FHEM einzubinden, was Dank deiner Arbeit auch super funktioniert hat.
Da der ESP aber alle 5sek published und ich noch eine ganze Menge anderer Sensoren und Aktoren habe, ist der Raspberry recht ausgelastet.
Und daher meine Frage ob und wo man was verändern kann, damit der ESP nicht ganz so viel "redet". Mir würde das durchaus auch alle 30 sek reichen...
schöne Grüße

@noone2k
Copy link
Author

noone2k commented Jun 18, 2024

suche mal im script nach interval ...

bei der version für den v2: https://github.com/noone2k/hm2500pub/blob/c9b159f5cc4d9c7b8cc980e8c650165c81389f42/config/b2500-v2-ble-idf.yaml#L104

habe gerade gesehen, das bei der v1 version noch die timer-funktion des sntp genutzt wird.
da nach "sntp" suchen:
https://github.com/noone2k/hm2500pub/blob/c9b159f5cc4d9c7b8cc980e8c650165c81389f42/config/bc2500-ble-idf.yaml#L87

@jmk777jmk
Copy link

suche mal im script nach interval ...

bei der version für den v2: https://github.com/noone2k/hm2500pub/blob/c9b159f5cc4d9c7b8cc980e8c650165c81389f42/config/b2500-v2-ble-idf.yaml#L104

habe gerade gesehen, das bei der v1 version noch die timer-funktion des sntp genutzt wird. da nach "sntp" suchen: https://github.com/noone2k/hm2500pub/blob/c9b159f5cc4d9c7b8cc980e8c650165c81389f42/config/bc2500-ble-idf.yaml#L87

Klasse ... Danke für den Hinweis

@robbe1912
Copy link

sollte der power knopf am b2500 was machen? in der anleitung steht nichts davon und aus geht der vom drücken nicht. was ist der unterschied zwischen passthrough und charge and discharge? steht auch gar nichts in der anleitung dazu. schon mal vielen dank für die hilfe!
@Larvy soll ich bei den timern in der batterie einfach nur den ersten anhaben und von 0:00 bis 23:59 auf 800W setzen? habe mir jetzt auch einen Hoymiles HMS-2000-4T zugelegt, jetzt fehlen nur noch ein paar verlängerungskabel und das openDTU. spricht was dagegen den wechselrichter output sekundengenau anzupassen? mein auslesegerät am zähler sendet auch jede sekunde updates.
wie sollte ich die solarplatten, die batterie und den wechselrichter am besten zusammenstecken damit diese am effizientesten zusammenarbeiten? Ich habe 4x 415W und 1x 440W, die batterie und jetzt den HMS-2000-4T.

@RALFISBORN
Copy link

RALFISBORN commented Jun 20, 2024

Kann der hier anwesenden IOBroker Benutzer mir vielleicht mal Screenshots der MQTT Instanz zeigen?
Wenn ich nämlich folgendes Tool verwende: https://tomquist.github.io/esphome-b2500/
Dann wird zwar die Bluetooth Verbindung sowie auch die MQTT Verbindung aufgebaut. Allerdings werden nicht alle Topics angelegt.

Wenn ich die hier zur Verfügung gestellte Yaml Datei (V2) auf den ESP flashe dann wird keine Bluetooth Verbindung aufgebaut bzw. steht das hier im Log:

[11:13:49][I][app:100]: ESPHome version 2024.6.1 compiled on Jun 20 2024, 11:12:41
[11:13:49][I][app:102]: Project esphome.web version 1.0
[11:13:49][W][component:170]: Component mqtt cleared Warning flag
[11:13:49][W][component:170]: Component mqtt cleared Warning flag
[11:13:49][W][component:170]: Component mqtt cleared Warning flag
[11:13:49][W][component:170]: Component mqtt cleared Warning flag
[11:13:49][W][component:170]: Component mqtt cleared Warning flag
[11:13:49][W][component:170]: Component mqtt cleared Warning flag
[11:13:50][W][component:170]: Component mqtt cleared Warning flag
[11:13:50][W][component:170]: Component mqtt cleared Warning flag
[11:13:50][W][component:170]: Component mqtt cleared Warning flag
[11:13:50][W][component:170]: Component mqtt cleared Warning flag
[11:13:50][W][component:170]: Component mqtt cleared Warning flag
[11:13:50][W][component:170]: Component mqtt cleared Warning flag
[11:13:50][W][component:170]: Component mqtt cleared Warning flag
[11:13:50][W][component:170]: Component mqtt cleared Warning flag
[11:13:50][W][component:170]: Component mqtt cleared Warning flag
[11:13:50][W][component:170]: Component mqtt cleared Warning flag
[11:13:50][W][component:170]: Component mqtt cleared Warning flag
[11:13:50][W][component:170]: Component mqtt cleared Warning flag
[11:13:50][W][component:170]: Component mqtt cleared Warning flag
[11:13:50][W][component:170]: Component mqtt cleared Warning flag
[11:13:50][W][component:170]: Component mqtt cleared Warning flag
[11:13:50][W][component:170]: Component mqtt cleared Warning flag
[11:13:50][W][component:170]: Component mqtt cleared Warning flag
[11:13:50][W][component:170]: Component mqtt cleared Warning flag
[11:13:50][W][component:170]: Component mqtt cleared Warning flag
[11:14:04][I][main:3181]: ble command send: 1 [0x0F] 1
[11:14:04][W][ble_client.automation:141]: Cannot write to BLE characteristic - not connected
[11:14:05][I][main:3181]: ble command send: 1 [0x13] 0
[11:14:05][W][ble_client.automation:141]: Cannot write to BLE characteristic - not connected
[11:14:09][I][main:3181]: ble command send: 1 [0x0F] 1
[11:14:09][W][ble_client.automation:141]: Cannot write to BLE characteristic - not connected
[11:14:10][I][main:3181]: ble command send: 1 [0x13] 0
[11:14:10][W][ble_client.automation:141]: Cannot write to BLE characteristic - not connected
[11:14:11][W][ble_sensor:123]: [infoX6a] Cannot poll, not connected

Was muss denn bei den MAC Adressen genau eingetragen werden? Es gibt ja hm2500_3_mac und hm2500_4_mac. An sich habe ich ja nur einen Speicher und dadurch eine MAC.
Vielen Dank

@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!

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