Skip to content

Instantly share code, notes, and snippets.

@neromatrix
Last active November 12, 2024 10:00
Show Gist options
  • Save neromatrix/6ec812f35418c4b38ebbad4e92cac888 to your computer and use it in GitHub Desktop.
Save neromatrix/6ec812f35418c4b38ebbad4e92cac888 to your computer and use it in GitHub Desktop.
# No Power Wasted 2500 V0.322 ONLY FOR TESTING !!!!
# ESPHome Software für alle gängigen Versionen des Balkonspeichers xy2500.
# Diese Version ist speziell für Verwendung mit dem Home Assistant ausgelegt und
# inkludiert die Kommunikation mit diesem, Regelung für Nulleinspeisung
# und in Zukunft einiges mehr.
# Die Kommunikation mit dem Balkonspeichers xy2500 basiert auf der Arbeit von noone2K.
# Die Hauptseite für neue Entwicklungen, Integration MQTT, openhab usw. findet ihr unter:
# https://gist.github.com/noone2k/2ddea4c9bf116aaaefb8626b064d9a41
#
# Mögen euch die Bits gnädig sein,
# neromatrix
esphome:
name: esphome-npw2500
friendly_name: No Power Wasted 2500
on_boot:
priority: 600
then:
- lambda: |-
id(npw2500_ble_disconnects).publish_state(0);
id(npw2500_wifi_disconnects).publish_state(0);
id(npw2500_api_disconnects).publish_state(0);
id(npw2500_battery_wifi_disconnects).publish_state(0);
id(npw2500_battery_control_status).publish_state("");
id(npw2500_command_sent_count).publish_state(0);
esp32:
board: esp32dev
framework:
type: esp-idf
#ota: #remove '#' to use ota
# Enable wifi
wifi:
id: npw2500_wifi
ssid: !secret wifi_ssid
password: !secret wifi_password
reboot_timeout: 0s
fast_connect: True
# Enable Home Assistant API
api:
id: api_server
# Enable logging
logger:
esp32_ble_tracker:
#web_server: #remove '#' to use web_server
# port: 80
# local: true
# js_include: "./v2/www.js"
# js_url: "/0.js"
# version: 2
ble_client:
# mac address of the batterie from secrets
mac_address: !secret battery_ble_mac
id: npw2500_ble
########## globals ##########
globals:
# - <<: !include developer/globals.yaml
# helper for npw2500_config_limit_nonpersistent_relative name
- id: npw2500_config_limit_nonpersistent_relative
type: std::string
restore_value: yes
initial_value: !secret inverter_rel_power_limit
# communication with all devices ready
- id: npw2500_communication_ready
type: bool
restore_value: no
initial_value: '0'
# communication with all devices just started
- id: npw2500_communication_started
type: bool
restore_value: no
initial_value: '0'
# response 0x03 received
- id: npw2500_response_0x03_data_ready
type: bool
restore_value: no
initial_value: '0'
# response 0x0f received
- id: npw2500_response_0x0f_data_ready
type: bool
restore_value: no
initial_value: '0'
# state for output ch1
- id: npw2500_set_output_state_ch1
type: bool
restore_value: no
initial_value: '0'
# state for output ch2
- id: npw2500_set_output_state_ch2
type: bool
restore_value: no
initial_value: '0'
# flag for pending output update
- id: npw2500_update_output_state
type: bool
restore_value: no
initial_value: 'false'
# output update enabled
- id: npw2500_enable_output_control
type: bool
restore_value: no
initial_value: 'false'
# use gridsensor for home consumption
- id: npw2500_enable_gridsensor
type: bool
restore_value: no
initial_value: 'true' #set to false, if you have no valid grid sensor in secrets.yaml
########## text_sensors ##########
text_sensor:
# - <<: !include developer/text_sensor.yaml
# should report NPW Version, does not work
- platform: version
id: npw2500_version
name: No Power Wasted 2500
hide_timestamp: true
# reports the internal PowerZero Status
- platform: template
id: npw2500_powerzero_status
name: PowerZero Status
# reports the Battery Control Status
- platform: template
id: npw2500_battery_control_status
name: PowerZero Battery Control Status
########## binary_sensors ##########
binary_sensor:
# - <<: !include developer/binary_sensor.yaml
# Bluetooth connected
- platform: template
name: ESP Ble connected
id: npw2500_ble_connected
on_state:
- lambda: |-
static bool ble_first_started = true;
if(!x && !ble_first_started) id(npw2500_ble_disconnects).publish_state(id(npw2500_ble_disconnects).state + 1);
else ble_first_started = false;
# Wifi connected
- platform: template
name: ESP Wifi connected
id: npw2500_wifi_connected
on_state:
- lambda: |-
static bool wifi_first_started = true;
if(!x && !wifi_first_started) id(npw2500_wifi_disconnects).publish_state(id(npw2500_wifi_disconnects).state + 1);
else wifi_first_started = false;
# HA Api connected
- platform: template
name: ESP HA connected
id: npw2500_api_connected
on_state:
- lambda: |-
static bool api_first_started = true;
if(!x && !api_first_started) id(npw2500_api_disconnects).publish_state(id(npw2500_api_disconnects).state + 1);
else api_first_started = false;
# Battery connected to Wifi
- platform: template
name: Battery WiFi connected
id: npw2500_battery_wifi
on_state:
- lambda: |-
if(!x) id(npw2500_battery_wifi_disconnects).publish_state(id(npw2500_battery_wifi_disconnects).state + 1);
# Input Ch1 active
- platform: template
name: Input Ch1 active
id: npw2500_input_ch1_active
# Input Ch2 active
- platform: template
name: Input Ch2 active
id: npw2500_input_ch2_active
# Input Ch1 transparent - Passthrough active/inactive
- platform: template
name: Input Ch1 transparent
id: npw2500_input_ch1_transparent
# Input Ch2 transparent - Passthrough active/inactive
- platform: template
name: Input Ch2 transparent
id: npw2500_input_ch2_transparent
# Output Ch1 active - does not show status in Passthrough Modus
- platform: template
name: Output Ch1 active
id: npw2500_output_ch1_active
# Output Ch1 power out flow
- platform: template
name: Output Ch1 Power Flow
id: npw2500_output_ch1_power_flow
# Output Ch2 power out flow
- platform: template
name: Output Ch2 Power Flow
id: npw2500_output_ch2_power_flow
# Output Ch2 active - does not show status in Passthrough Modus
- platform: template
name: Output Ch2 active
id: npw2500_output_ch2_active
# Battery connected to MQTT
- platform: template
name: Battery MQTT connected
id: npw2500_battery_mqtt
# Status of Passthrough switch
- platform: template
name: PassThrough active
id: npw2500_passthrough_active
# PowerZero enabled/disabled
- platform: template
name: PowerZero active
id: npw2500_zeropower_active
# OpenDTU status of inverter producing
- platform: homeassistant
name: PowerZero Inverter producing
id: npw2500_powerzero_inverter_producing
entity_id: !secret inverter_producing
internal: false
########## sensors ##########
sensor:
# - <<: !include developer/sensor.yaml
- platform: template
name: Command sent count
id: npw2500_command_sent_count
internal: true
accuracy_decimals: 0
# Battery Input Power (Ch1 + Ch2)
- platform: template
name: Input Power
id: npw2500_input_power
unit_of_measurement: W
device_class: power
icon: mdi:solar-power
accuracy_decimals: 0
# Battery Input Power Ch1
- platform: template
name: Input Ch1 Power
id: npw2500_input_power_ch1
unit_of_measurement: W
device_class: power
accuracy_decimals: 0
# Battery Input Power Ch2
- platform: template
name: Input Ch2 Power
id: npw2500_input_power_ch2
unit_of_measurement: W
device_class: power
accuracy_decimals: 0
# Battery Ouput Power (Ch1 + Ch2)
- platform: template
name: Output Power
id: npw2500_output_power
unit_of_measurement: W
device_class: power
accuracy_decimals: 0
# Battery Ouput Power Ch1
- platform: template
name: Output Power Ch1
id: npw2500_output_power_ch1
unit_of_measurement: W
device_class: power
accuracy_decimals: 0
# Battery Ouput Power Ch2
- platform: template
name: Output Power Ch2
id: npw2500_output_power_ch2
unit_of_measurement: W
device_class: power
accuracy_decimals: 0
# Battery InOutput Power (Input power - Output power)
- platform: template
name: Power InOut
id: npw2500_inout_power
unit_of_measurement: W
device_class: power
accuracy_decimals: 0
# Battery SOC
- platform: template
name: Battery SOC
id: npw2500_battery_soc
unit_of_measurement: '%'
device_class: battery
accuracy_decimals: 0
# Battery SOC dynamic
- platform: template
name: Battery SOC dynamic.
id: npw2500_battery_soc_dynamic
unit_of_measurement: '%'
device_class: battery
accuracy_decimals: 1
# Battery remaining capacity
- platform: template
name: Battery remaining capacity
id: npw2500_battery_remaining
unit_of_measurement: Wh
device_class: energy
accuracy_decimals: 0
# Grid Power Import
- platform: template
name: Grid Power Import
id: npw2500_grid_power_import
unit_of_measurement: W
device_class: power
accuracy_decimals: 0
internal: true
# Grid Power Export
- platform: template
name: Grid Power Export
id: npw2500_grid_power_export
unit_of_measurement: 'W'
device_class: power
accuracy_decimals: 0
internal: true
# Grid Power Export
- platform: template
name: Grid Power Average Export
id: npw2500_grid_power_avg_export
unit_of_measurement: 'W'
device_class: power
accuracy_decimals: 0
internal: false
filters:
- sliding_window_moving_average:
window_size: 35
send_every: 1
# Ha Integration import grid power
- platform: homeassistant
name: Grid Power
id: npw2500_grid_power
entity_id: !secret npw2500_grid_power
unit_of_measurement: W
device_class: power
icon: mdi:transmission-tower
accuracy_decimals: 0
internal: false
# Grid Power offset for PowerZero
- platform: template
name: Grid Power Offset
id: npw2500_grid_power_offset
unit_of_measurement: W
device_class: power
accuracy_decimals: 0
# Ha Integration openDTU Power limit rel.
- platform: homeassistant
name: openDTU Power limit rel. actual value
id: npw2500_limit_nonpersistent_relative
entity_id: !secret inverter_rel_power_limit_2
unit_of_measurement: '%'
device_class: power_factor
accuracy_decimals: 0
internal: false
# Internal sensor openDTU Power limit rel. Target value
- platform: template
name: openDTU Power limit rel. target value
id: opendtu_limit_nonpersistent_relative_target_value
unit_of_measurement: '%'
device_class: power_factor
accuracy_decimals: 0
internal: false
# Battery Temperature 1
- platform: template
name: Temperature Sensor 1
id: npw2500_temperature_1
unit_of_measurement: '°C'
device_class: temperature
accuracy_decimals: 0
# Battery Temperature 2
- platform: template
name: Temperature Sensor 2
id: npw2500_temperature_2
unit_of_measurement: '°C'
device_class: temperature
accuracy_decimals: 0
# Battery summation of Cell Voltages
- platform: template
name: Cell Voltage sum
id: npw2500_cell_vsum
unit_of_measurement: V
device_class: voltage
accuracy_decimals: 3
# Battery maximum of all Cell Voltages
- platform: template
name: Cell Voltage max
id: npw2500_cell_vmax
unit_of_measurement: V
device_class: voltage
accuracy_decimals: 3
# Battery maximumminimum of all Cell Voltages
- platform: template
name: Cell Voltage min
id: npw2500_cell_vmin
unit_of_measurement: V
device_class: voltage
accuracy_decimals: 3
# Battery average value of all Cell Voltages
- platform: template
name: Cell Voltage avg
id: npw2500_cell_vavg
unit_of_measurement: V
device_class: voltage
accuracy_decimals: 3
# Battery max difference between all Cell Voltages
- platform: template
name: Cell Voltage diff
id: npw2500_cell_vdiff
unit_of_measurement: V
device_class: voltage
accuracy_decimals: 3
# Battery Discharge threshold
- platform: template
name: Discharge threshold
id: npw2500_discharge_treshold
unit_of_measurement: '%'
device_class: power_factor
accuracy_decimals: 0
# Battery Solar Charge threshold
- platform: template
name: Solar Charge threshold
id: npw2500_solar_charge_treshold
unit_of_measurement: W
device_class: power
accuracy_decimals: 0
# Battery Software Version
- platform: template
name: Battery Version
id: npw2500_device_version
accuracy_decimals: 3
# Home Power usage
- platform: template
name: Home Power Consumption
id: npw2500_home_power_consuption
unit_of_measurement: W
device_class: 'power'
accuracy_decimals: 0
#Ble disconnects
- platform: template
name: ESP Ble disconnects
id: npw2500_ble_disconnects
accuracy_decimals: 0
# Wifi disconnects
- platform: template
name: ESP Wifi disconnects
id: npw2500_wifi_disconnects
accuracy_decimals: 0
# HA Api disconnects
- platform: template
name: ESP HA disconnects
id: npw2500_api_disconnects
accuracy_decimals: 0
# Battery disconnects to Wifi
- platform: template
name: Battery WiFi disconnects
id: npw2500_battery_wifi_disconnects
accuracy_decimals: 0
# Battery Ouput Energy Ch1
- platform: integration
name: Output Ch1 Energy Daily
id: npw2500_output_energy_ch1_daily
sensor: npw2500_output_power_ch1
unit_of_measurement: 'kWh'
state_class: total_increasing
device_class: energy
time_unit: h
accuracy_decimals: 3
integration_method: left
restore: false
filters:
- multiply: 0.001
- skip_initial: 1
- lambda: "return id(npw2500_communication_ready) ? x : 0;"
# Battery Ouput Energy Ch2
- platform: integration
name: Output Ch2 Energy Daily
id: npw2500_output_energy_ch2_daily
sensor: npw2500_output_power_ch2
unit_of_measurement: 'kWh'
state_class: total_increasing
device_class: energy
time_unit: h
accuracy_decimals: 3
integration_method: left
restore: false
filters:
- multiply: 0.001
- skip_initial: 3
- lambda: "return id(npw2500_communication_ready) ? x : 0;"
# Battery Output Energy (Ch1 + Ch2)
- platform: integration
name: Output Energy Daily
id: npw2500_output_energy_daily
sensor: npw2500_output_power
unit_of_measurement: 'kWh'
state_class: total_increasing
device_class: energy
time_unit: h
accuracy_decimals: 3
integration_method: left
restore: false
filters:
- multiply: 0.001
- skip_initial: 1
- lambda: "return id(npw2500_communication_ready) ? x : 0;"
# Battery Input Energy Ch1
- platform: integration
name: Input Ch2 Energy Daily
id: npw2500_input_energy_ch2_daily
sensor: npw2500_input_power_ch2
unit_of_measurement: 'kWh'
state_class: total_increasing
device_class: energy
time_unit: h
accuracy_decimals: 3
integration_method: left
restore: false
filters:
- multiply: 0.001
- skip_initial: 1
- lambda: "return id(npw2500_communication_ready) ? x : 0;"
# Battery Input Energy Ch1
- platform: integration
name: Input Ch1 Energy Daily
id: npw2500_input_energy_ch1_daily
sensor: npw2500_input_power_ch1
unit_of_measurement: 'kWh'
state_class: total_increasing
device_class: energy
time_unit: h
accuracy_decimals: 3
integration_method: left
restore: false
filters:
- multiply: 0.001
- skip_initial: 1
- lambda: "return id(npw2500_communication_ready) ? x : 0;"
# Battery Input Energy (Ch1 + Ch2)
- platform: integration
name: Input Energy Daily
id: npw2500_input_energy_daily
sensor: npw2500_input_power
unit_of_measurement: 'kWh'
state_class: total_increasing
device_class: energy
time_unit: h
accuracy_decimals: 3
integration_method: left
restore: false
filters:
- multiply: 0.001
- skip_initial: 1
- lambda: "return id(npw2500_communication_ready) ? x : 0;"
# Battery Energy
- platform: integration
name: Battery InOut Energy Daily
id: npw2500_inout_energy_daily
sensor: npw2500_inout_power
unit_of_measurement: 'kWh'
state_class: total
device_class: energy
time_unit: h
accuracy_decimals: 3
integration_method: left
restore: false
filters:
- multiply: 0.001
- skip_initial: 1
- lambda: "return id(npw2500_communication_ready) ? x : 0;"
# Home Energy Consumption Daily
- platform: integration
name: Home Energy Consumption Daily
id: npw2500_home_energy_daily
sensor: npw2500_home_power_consuption
unit_of_measurement: kWh
state_class: total_increasing
device_class: energy
time_unit: h
accuracy_decimals: 3
integration_method: left
restore: false
filters:
- multiply: 0.001
- skip_initial: 1
- lambda: "return id(npw2500_communication_ready) ? x : 0;"
# Grid Energy Daily
- platform: integration
name: Grid Energy Daily
id: npw_grid_energy_daily
sensor: npw2500_grid_power
unit_of_measurement: kWh
state_class: total
device_class: energy
time_unit: h
accuracy_decimals: 3
icon: mdi:transmission-tower
integration_method: left
restore: false
filters:
- multiply: 0.001
- skip_initial: 1
- lambda: "return id(npw2500_communication_ready) ? x : 0;"
# Grid Export Energy Daily
- platform: integration
name: Grid Export Energy Daily
id: npw_grid_export_energy_daily
sensor: npw2500_grid_power_export
unit_of_measurement: 'kWh'
state_class: total_increasing
device_class: energy
time_unit: h
accuracy_decimals: 3
icon: mdi:transmission-tower-import
integration_method: left
restore: false
filters:
- multiply: 0.001
- skip_initial: 1
- lambda: "return id(npw2500_communication_ready) ? x : 0;"
# Grid Import Energy Daily
- platform: integration
name: Grid Import Energy Daily
id: npw_grid_import_energy_daily
sensor: npw2500_grid_power_import
unit_of_measurement: 'kWh'
state_class: total_increasing
device_class: energy
time_unit: h
icon: mdi:transmission-tower-export
accuracy_decimals: 3
integration_method: left
restore: false
filters:
- multiply: 0.001
- skip_initial: 1
- lambda: "return id(npw2500_communication_ready) ? x : 0;"
# ESP Bluetooth client
- platform: ble_client
ble_client_id: npw2500_ble
type: characteristic
name: "npw2500Info"
id: npw2500_Info
service_uuid: 'ff00'
characteristic_uuid: 'ff02'
update_interval: never
internal: True
notify: True
lambda: |-
std::vector<char> xdata;
for (auto b : x) { xdata.push_back(b); }
id(ble_parse_response).execute(xdata);
return (float)x[0];
########## button ##########
button:
# - <<: !include developer/button.yaml
# Reset Daily Energy
- platform: template
name: Reset Daily Energy
id: npw2500_reset_daily_energy
on_press:
- script.execute:
id: reset_energy_sensors
# Restart Inverter
- platform: template
name: Restart Inverter
id: npw2500_restart_inverter
icon: mdi:restart
on_press:
- logger.log: Restart Inverter Button Pressed
- script.execute:
id: restart_inverter
# Restart ESP
- platform: restart
name: Restart ESP
id: npw2500_restart_esp
# Restart Batterie
- platform: template
name: Restart Battery
id: npw2500_restart_battery
icon: mdi:restart
on_press:
- logger.log: Restart Battery Button Pressed
- script.execute:
id: restart_battery
########## switches ##########
switch:
# - <<: !include developer/switch1.yaml
# - <<: !include developer/switch2.yaml
# - <<: !include developer/switch3.yaml
# - <<: !include developer/switch4.yaml
# Battery Enable Battery Control
- platform: template
name: Enable Battery Control
id: npw2500_enable_battery_control_switch
icon: mdi:toggle-switch
optimistic: True
restore_mode: RESTORE_DEFAULT_OFF
on_turn_on:
then:
lambda: 'id(npw2500_battery_control_status).publish_state("Battery Control enabled");'
on_turn_off:
then:
lambda: 'id(npw2500_battery_control_status).publish_state("Battery Control disabled");'
# Battery Output switch Ch1
- platform: template
name: Set Power Out Switch Ch1
id: npw2500_powerout_switch_ch1
icon: mdi:toggle-switch
optimistic: True
restore_mode: RESTORE_DEFAULT_OFF
on_turn_on:
then:
- script.execute:
id: ble_switch_powerout
on_turn_off:
then:
- script.execute:
id: ble_switch_powerout
# Battery Output switch Ch2
- platform: template
name: Set Power Out Switch Ch2
id: npw2500_powerout_switch_ch2
icon: mdi:toggle-switch
optimistic: True
restore_mode: RESTORE_DEFAULT_ON
on_turn_on:
then:
- script.execute:
id: ble_switch_powerout
on_turn_off:
then:
- script.execute:
id: ble_switch_powerout
# Battery Output switch Passtrough
- platform: template
name: Set PV2 Passtrough Switch
id: npw2500_powerout_pv2_switch
icon: mdi:toggle-switch
optimistic: True
restore_mode: RESTORE_DEFAULT_ON
on_turn_on:
then:
- script.execute:
id: ble_command
ble_cmd: 0x0D
ble_cmd_parm: 0x00
- script.wait: ble_command
on_turn_off:
then:
- script.execute:
id: ble_command
ble_cmd: 0x0D
ble_cmd_parm: 0x01
- script.wait: ble_command
# PowerZero enable
- platform: template
name: PowerZero enabled
id: npw2500_zeropower_enabled
optimistic: True
restore_mode: RESTORE_DEFAULT_OFF
# ble client enable
- platform: ble_client
ble_client_id: npw2500_ble
name: "Enable Bluetooth"
internal: False
########## numbers ##########
number:
# - <<: !include developer/number.yaml
# Slider Discharge threshold
- platform: template
name: Set Discharge threshold
id: npw2500_discharge_slider
min_value: 10
max_value: 90
step: 10
optimistic: true
initial_value : 90
restore_value : true
unit_of_measurement: '%'
device_class: 'battery'
icon: 'mdi:speedometer'
on_value:
- script.execute:
id: ble_command
ble_cmd: 0x0B
ble_cmd_parm: !lambda 'return x;'
- script.wait: ble_command
# Slider Solar Charge threshold
- platform: template
name: Set Solar Charge threshold
id: npw2500_solar_charge_slider
min_value: 0
max_value: 990
step: 10
initial_value : 990
restore_value : true
optimistic: true
unit_of_measurement: 'W'
device_class: 'energy'
icon: 'mdi:speedometer'
on_value:
- script.execute:
id: ble_command
ble_cmd: 0x0C
ble_cmd_parm: !lambda 'return int(x);'
- script.wait: ble_command
# Slider Power Limit rel.
- platform: template
name: Set Power Limit rel.
id: npw2500_powerlimit_slider
min_value: 2
max_value: 100
step: 1
initial_value: 10
restore_value: true
optimistic: true
unit_of_measurement: '%'
device_class: 'power_factor'
icon: 'mdi:speedometer'
# Slider Max Cell Voltage
- platform: template
name: Set max Cell Voltage
id: npw2500_max_cell_voltage_slider
min_value: 3.2
max_value: 3.6
step: 0.01
initial_value: 3.4
restore_value: true
optimistic: true
unit_of_measurement: 'V'
device_class: 'voltage'
icon: 'mdi:speedometer'
# Slider Set Grid Power Offset
- platform: template
name: Set Grid Power Offset
id: npw2500_power_offset_slider
min_value: -800
max_value: 200
step: 10
initial_value: 0
restore_value: true
optimistic: true
unit_of_measurement: 'W'
device_class: 'power'
icon: 'mdi:speedometer'
# - platform: homeassistant
# id: homeassistant_time
### synchronize ESP time with SNTP time
time:
- platform: sntp
id: sntp_time
timezone: Europe/Berlin
on_time_sync:
then:
- logger.log: "Synchronized system clock"
on_time:
- hours: 23
minutes: 59
seconds: 0
then:
- script.execute:
id: reset_energy_sensors
- logger.log: "Energy Sensors Reset"
########## intervals ##########
interval:
# - <<: !include developer/interval.yaml
- interval: 5 sec
then:
- logger.log: "Auf gehts..."
- lambda: |-
id(npw2500_wifi_connected).publish_state(id(npw2500_wifi).is_connected()); // publish state of wifi
id(npw2500_ble_connected).publish_state(id(npw2500_ble).connected()); // publish state of ble
id(npw2500_api_connected).publish_state(global_api_server->is_connected()); // publish state of HA Api
id(npw2500_communication_ready) = id(npw2500_wifi_connected).state && // set global npw2500_communication_ready
id(npw2500_ble_connected).state && id(npw2500_api_connected).state;
ESP_LOGD("npw2500","service HA api: %d wifi: %d ble: %d", // log values
id(npw2500_api_connected).state,id(npw2500_wifi_connected).state,id(npw2500_ble_connected).state);
- if:
condition:
lambda: 'return id(npw2500_communication_ready);'
then:
- script.execute:
id: ble_command
ble_cmd: 0x03 # Request Command 0x03
ble_cmd_parm: 0x01
- logger.log: "Request command 0x03 sent"
- delay: 1 sec
- script.execute:
id: ble_command
ble_cmd: 0x0f # Request Command 0x0f
ble_cmd_parm: 0x01
- logger.log: "Request command 0x0f sent"
- delay: 1 sec
- script.execute:
id: ble_set_outputs # Set Outputs
- interval: 10 sec # do not change time !!!
then:
- if:
condition:
lambda: 'return id(npw2500_communication_ready);'
then:
- script.execute:
id: power_zero # Call script powerzero
- interval: 10 sec # do not change time !!!
then:
- script.execute:
id: watch_task # Call script watch_task
- interval: 600 sec
then:
- script.execute:
id: check_dod # # Call script check_dod
script:
#- <<: !include developer/script1.yaml
#- <<: !include developer/script2.yaml
- id: ble_parse_response
parameters:
x: char[]
then:
lambda: |-
//ESP_LOG_BUFFER_HEXDUMP("npw2500", &x[0], x.size(), ESP_LOG_ERROR);
//### Cell parser by neromatrix ###
//### Ver. 0.4 ###
//### highlimit now from slider id(npw2500_max_cell_voltage_slider).state ###
if ((std::count (x.begin(), x.end(), '_') == 16) || (std::count (x.begin(), x.begin() + 10, '_') == 3))
{
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;
ESP_LOGD("npw2500","Parsing cell information, response of request command 0xf");
id(npw2500_response_0x0f_data_ready) = true;
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 get int value of device SOC
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
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 = lowlimit = 0% SoC
cell full = highlimit = 100% SoC = id(npw2500_max_cell_voltage_slider).state
*/
float lowlimit = 3.0; // low voltage limit
float highlimit = id(npw2500_max_cell_voltage_slider).state ; // changed V0.4 - high voltage limit from slider
float soccalc = 100*((cv/14000)
- highlimit)/(highlimit - lowlimit) + 100; // equation of line with two points (0,lowlimit) (100,highlimit)
id(npw2500_battery_soc_dynamic).publish_state(soccalc); // id changed V0.4 - dynamic SOC calculated from cell voltages (%)
id(npw2500_temperature_1).publish_state(t1); // Temperature 1 (°C)
id(npw2500_temperature_2).publish_state(t2); // Temperature 2 (°C)
id(npw2500_cell_vsum).publish_state(cv/1000); // sum of cellvoltages = battery Voltage(V)
id(npw2500_cell_vmin).publish_state(cmin/1000); // lowest cellvoltage (V)
id(npw2500_cell_vmax).publish_state(cmax/1000); // highest cellvoltage (V)
id(npw2500_cell_vdiff).publish_state((cmax-cmin)/1000); // difference high-low (V)
id(npw2500_cell_vavg).publish_state(cv/14000); // avarage cellvoltage (V)
}
else if((x[3] == 3))
{
ESP_LOGD("npw2500","Parsing response of request command 0x3");
id(npw2500_response_0x03_data_ready) = true;
// Input power ch1
int inputpower1 = x[6] | x[7] << 8;
id(npw2500_input_power_ch1).publish_state(inputpower1);
// Input power ch2
int inputpower2 = x[8] | x[9] << 8;
id(npw2500_input_power_ch2).publish_state(inputpower2);
// Input power ch1 + ch2
id(npw2500_input_power).publish_state(inputpower1 + inputpower2);
// Output power Ch1
int outputpower1 = x[24] | x[25] << 8;
id(npw2500_output_power_ch1).publish_state(outputpower1);
// Output power Ch2
int outputpower2 = x[26] | x[27] << 8;
id(npw2500_output_power_ch2).publish_state(outputpower2);
// Output power Ch1 + Ch2
id(npw2500_output_power).publish_state(outputpower1 + outputpower2);
// Input-Output power
id(npw2500_inout_power).publish_state(inputpower1 + inputpower2 - outputpower1 - outputpower2);
//int dod_level = x[18];
id(npw2500_discharge_treshold).publish_state(x[18]);
//Solar Treshold
id(npw2500_solar_charge_treshold).publish_state(x[19] | x[20] << 8);
// Battery state of charge %
id(npw2500_battery_soc).publish_state((x[10] | x[11] << 8 ) / 10);
// Battery remaining capacity
id(npw2500_battery_remaining).publish_state(x[22] | x[23] << 8);
// update active and transparent state of input channels
if( x[4] == 0x00 ) { id(npw2500_input_ch1_active).publish_state(false); id(npw2500_input_ch1_transparent).publish_state(false); }
if( x[4] == 0x01 ) { id(npw2500_input_ch1_active).publish_state(true); id(npw2500_input_ch1_transparent).publish_state(false); }
if( x[4] == 0x02 ) { id(npw2500_input_ch1_active).publish_state(true); id(npw2500_input_ch1_transparent).publish_state(true); }
if( x[5] == 0x00 ) { id(npw2500_input_ch2_active).publish_state(false); id(npw2500_input_ch2_transparent).publish_state(false); }
if( x[5] == 0x01 ) { id(npw2500_input_ch2_active).publish_state(true); id(npw2500_input_ch2_transparent).publish_state(false); }
if( x[5] == 0x02 ) { id(npw2500_input_ch2_active).publish_state(true); id(npw2500_input_ch2_transparent).publish_state(true); }
//device software version
float dev_version = x[12];
id(npw2500_device_version).publish_state(dev_version / 100);
// Passthrough stateS
id(npw2500_passthrough_active).publish_state(x[13] == 0);
// update output channels state
if( x[15] == 0x00 ) { id(npw2500_battery_wifi).publish_state(false); id(npw2500_battery_mqtt).publish_state(false); }
if( x[15] == 0x01 ) { id(npw2500_battery_wifi).publish_state(true); id(npw2500_battery_mqtt).publish_state(false); }
if( x[15] == 0x02 ) { id(npw2500_battery_wifi).publish_state(true); id(npw2500_battery_mqtt).publish_state(true); }
if( x[15] == 0x03 ) { id(npw2500_battery_wifi).publish_state(true); id(npw2500_battery_mqtt).publish_state(false); }
ESP_LOGD("npw2500","wifi state = %d ", x[15]);
if( x[16] == 0x00 ) { id(npw2500_output_ch1_active).publish_state(false);}
if( x[16] == 0x01 ) { id(npw2500_output_ch1_active).publish_state(true); }
if( x[17] == 0x00 ) { id(npw2500_output_ch2_active).publish_state(false);}
if( x[17] == 0x01 ) { id(npw2500_output_ch2_active).publish_state(true); }
}
else
{
ESP_LOG_BUFFER_HEXDUMP("npw2500", &x[0], x.size(), ESP_LOG_ERROR);
}
# set ouputs synchronized with other ble commands
- id: ble_set_outputs
then:
lambda: |-
int act_ble_cmd =0;
if( id(npw2500_enable_output_control) && id(npw2500_enable_battery_control_switch).state &&
( (id(npw2500_set_output_state_ch1) != id(npw2500_output_ch1_active).state ) ||
(id(npw2500_set_output_state_ch2) != id(npw2500_output_ch2_active).state)) && id(npw2500_update_output_state))
{
if ( ! id(npw2500_set_output_state_ch1) && ! id(npw2500_set_output_state_ch2)) { act_ble_cmd = 0x00; }
if ( id(npw2500_set_output_state_ch1) && ! id(npw2500_set_output_state_ch2)) { act_ble_cmd = 0x01; }
if ( ! id(npw2500_set_output_state_ch1) && id(npw2500_set_output_state_ch2)) { act_ble_cmd = 0x02; }
if ( id(npw2500_set_output_state_ch1) && id(npw2500_set_output_state_ch2)) { act_ble_cmd = 0x03; }
if(act_ble_cmd !=0)
{ // do not allow setting both outputs to zero
id(ble_command).execute(0x0E, act_ble_cmd); // synchronized with other automatic sent ble commands
ESP_LOGD("npw2500","ble_switch_out_set_state output changed");
}
id(npw2500_update_output_state) = false; // reset global update flag
ESP_LOGD("npw2500","npw2500_powerout_switch cmd = %d ", act_ble_cmd);
}
# get the position of the output switches and calculate the ble_cmd to be sent
# for updating the battery switch states.
- id: ble_switch_powerout
then:
- lambda: |-
if(id(npw2500_communication_ready))
{
int ble_cmd = 0x00;
if ( ! id(npw2500_powerout_switch_ch1).state && ! id(npw2500_powerout_switch_ch2).state ) { ble_cmd = 0x00; }
if ( id(npw2500_powerout_switch_ch1).state && ! id(npw2500_powerout_switch_ch2).state ) { ble_cmd = 0x01; }
if ( ! id(npw2500_powerout_switch_ch1).state && id(npw2500_powerout_switch_ch2).state ) { ble_cmd = 0x02; }
if ( id(npw2500_powerout_switch_ch1).state && id(npw2500_powerout_switch_ch2).state ) { ble_cmd = 0x03; }
id(ble_command).execute(0x0E, ble_cmd);
ESP_LOGD("npw2500","npw2500_powerout_switch cmd = %d ", ble_cmd);
}
else
ESP_LOGD("npw2500","ble_switch_powerout Communication not ready");
# Script for sending ble commands to battery
- id: ble_command
#mode: queued
parameters:
ble_cmd: int
ble_cmd_parm: int
then:
- if:
condition:
lambda: 'return id(npw2500_communication_ready);'
then:
- lambda: 'ESP_LOGD("NPW2500","ble_command cmd = %d parm = %d" ,ble_cmd, ble_cmd_parm); '
- ble_client.ble_write:
id: npw2500_ble
service_uuid: 'ff00'
characteristic_uuid: 'ff01'
value: !lambda |-
int rlen = 0;
int rxor = 0;
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);
}
rlen = rdat1.size();
rdat1.at(1) = rlen+1;
for (int i=0;i<rlen;i++) {
rxor = rxor ^ rdat1[i];
}
rdat1.push_back(rxor);
return rdat1;
else:
- lambda: 'ESP_LOGE("NPW2500","ble_command Communication not ready"); '
#####################################################################
### PowerZero Nulleinspeisung - by neromatrix ###
### Ver. 0.3 ###
## Now includes ChargeControl for ###
### loadvoltage preregulation ###
#####################################################################
- id: power_zero
then:
- lambda: |-
if(id(npw2500_zeropower_enabled).state && id(npw2500_communication_ready) &&
id(npw2500_response_0x03_data_ready) && id(npw2500_response_0x0f_data_ready))
{
int dtu_limit_min_value = 2;
int dtu_limit_max_value = id(npw2500_powerlimit_slider).state;
int dtu_limit_calculated_value = dtu_limit_min_value;
int dtu_max_power = 800;
int grid_to_dtu_limit_npr_ratio = dtu_max_power / 50;
int grid_power_offset_target_value = id(npw2500_power_offset_slider).state;
int dtu_max_slew_rate = 40;
int send_every_number_of_cycles = 6;
bool use_slewrate_limiter = 0;
std::string powerzero_status = "";
static int grid_power_offset_old_value = id(npw2500_power_offset_slider).state;
static int dtu_old_limit_value = dtu_limit_min_value;
static int grid_old_power_value = 100;
static int cycle_counter = 0;
// ************************* NPW ChargeControl ***********************************
// Inputs
float cell_voltage_target_value = id(npw2500_max_cell_voltage_slider).state;
float cell_vmax_act_value = id(npw2500_cell_vmax).state;
float cell_voltage_diff_to_power_ratio = 8000; // cell voltage difference to grid power ratio factor
// Outputs // factor 8000 enables soft regulation
int grid_power_offset_act_value = id(npw2500_power_offset_slider).state;
// Local
int grid_power_offset_new_value = id(npw2500_power_offset_slider).state;
float cell_vmax_diff = cell_vmax_act_value - cell_voltage_target_value; // calculate difference
if(id(npw2500_response_0x0f_data_ready)) // sanity check of response 0x0f
{
if((cell_vmax_act_value > cell_voltage_target_value)) // actual cell voltage higher then traget value
{ // calculate grid power offset for PowerZero
grid_power_offset_new_value = grid_power_offset_old_value - cell_vmax_diff * cell_voltage_diff_to_power_ratio;
grid_power_offset_act_value = round(( id(npw2500_power_offset_slider).state + grid_power_offset_new_value)/2);
powerzero_status = "Loadregulation";
}
else
{
if(cell_vmax_act_value < cell_voltage_target_value) // actual cell voltage lower then traget value
{
if(grid_power_offset_act_value != grid_power_offset_target_value)
{ // calculate grid power offset for PowerZero
grid_power_offset_act_value = round(( id(npw2500_power_offset_slider).state - grid_power_offset_old_value)/2);
}
if(id(npw2500_inout_power).state > 0)
powerzero_status = "Charge";
else
powerzero_status = "Discharge";
}
}
// Limit grid_power_offset_act_value to +- dtu_max_power
if(grid_power_offset_act_value > dtu_max_power) grid_power_offset_act_value = dtu_max_power;
if(grid_power_offset_act_value < - dtu_max_power) grid_power_offset_act_value = - dtu_max_power;
grid_power_offset_old_value = grid_power_offset_act_value;
}
else
ESP_LOGD("npw2500", "NPW Charge control - Cell data not available");
// ************************* End NPW ChargeControl ***************************
// ************************* NPW PowerZero ***********************************
int grid_actual_power_value = int(id(npw2500_grid_power).state);
//limit max grid power
int power_limit = 50000; // enable max +/-50KW grid power
if(abs(grid_actual_power_value) > power_limit) // also filters out HA sensor status message with value of INT_MAX on start
{
if(grid_actual_power_value != INT_MAX)
ESP_LOGE("npw2500", "Grid Power out of limit %d > %d" ,int(grid_actual_power_value),power_limit);
grid_actual_power_value = 0;
}
// calculate new dtu limit
dtu_limit_calculated_value = ((grid_actual_power_value - grid_power_offset_act_value ) / grid_to_dtu_limit_npr_ratio ) + dtu_old_limit_value ;
if(dtu_limit_calculated_value > dtu_limit_max_value) dtu_limit_calculated_value = dtu_limit_max_value; // limit dtu_limit upper limit to dtu_max_value
if(dtu_limit_calculated_value < dtu_limit_min_value) dtu_limit_calculated_value = dtu_limit_min_value; // limit dtu_limit lower limit to dtu_min_value
grid_old_power_value = grid_actual_power_value; //save dtu limit
ESP_LOGD("npw2500","PowerZero dtu old limit %d, dtu new limit %d, Grid value %d ",
dtu_old_limit_value, dtu_limit_calculated_value, grid_actual_power_value);
if(id(npw2500_input_ch1_transparent).state && id(npw2500_input_ch2_transparent).state) // check for 2 channel passthrough
{
dtu_limit_calculated_value = 100; // set dtu relativ power limit 100%
powerzero_status = "2 Channel PT"; // report status
grid_power_offset_act_value = 0; // no function in passthrough
}
else
{
if(id(npw2500_input_ch1_transparent).state || id(npw2500_input_ch2_transparent).state) // check for 1 channel passthrough
{
dtu_limit_calculated_value = 100; // set dtu relativ power limit 100%
powerzero_status = "1 Channel PT"; // report status
grid_power_offset_act_value = 0; // set grid_power_offset_act_value,
} // no function in passthrough
}
id(npw2500_grid_power_offset).publish_state(grid_power_offset_act_value); // publish value of actual grid power offset
id(npw2500_powerzero_status).publish_state(powerzero_status);
if(grid_actual_power_value >= 0)
{
id(npw2500_grid_power_import).publish_state(grid_actual_power_value);
id(npw2500_grid_power_export).publish_state(0);
}
if(grid_actual_power_value <= 0)
{
id(npw2500_grid_power_export).publish_state(-grid_actual_power_value);
id(npw2500_grid_power_import).publish_state(0);
}
id(npw2500_home_power_consuption).publish_state(id(npw2500_output_power).state + grid_actual_power_value );
// ************************* Slew Rate Limiter *************************
// Limits ptu limit power changes to dtu_max_slew_rate / cycle
// default limits battery output power changes to 320W /cycle
// *********************************************************************
if(use_slewrate_limiter)
{
int dtu_limited_value = dtu_limit_calculated_value - dtu_old_limit_value;
if (dtu_limited_value > dtu_max_slew_rate)
dtu_limited_value = dtu_max_slew_rate;
if (dtu_limited_value < -dtu_max_slew_rate)
dtu_limited_value = -dtu_max_slew_rate;
dtu_limit_calculated_value = dtu_old_limit_value + dtu_limited_value;
}
if( id(npw2500_powerzero_inverter_producing).state )
{
if( dtu_old_limit_value != dtu_limit_calculated_value ||
id(npw2500_limit_nonpersistent_relative).state != id(opendtu_limit_nonpersistent_relative_target_value).state || cycle_counter == 0)
{
// cannot use id(npw2500_hm_800_limit_nonpersistent_relative).publish_state(dtu_limit)
// any longer because entity id is a string now from !secret inverter_rel_power_limit
//**** update HA dtu limit value *****/
HomeassistantServiceResponse resp;
HomeassistantServiceMap entity_id_kv;
resp.service = "number.set_value";
entity_id_kv.key = "entity_id";
entity_id_kv.value = id(npw2500_config_limit_nonpersistent_relative);
resp.data.push_back(entity_id_kv);
entity_id_kv.key = "value";
entity_id_kv.value = to_string(dtu_limit_calculated_value);
resp.data.push_back(entity_id_kv);
id(opendtu_limit_nonpersistent_relative_target_value).publish_state(dtu_limit_calculated_value);
ESP_LOGD("npw2500", "Power Zero dtu limit calculated %d ",dtu_limit_calculated_value);
if(cycle_counter == 0) ESP_LOGD("npw2500","Cycle sent");
id(api_server).send_homeassistant_service_call(resp);
//*************************************
dtu_old_limit_value = dtu_limit_calculated_value; // save calculated dtu limit
}
}
if(cycle_counter >= send_every_number_of_cycles)
{
cycle_counter = 0;
}
else
cycle_counter++;
// Report internal PowerZero status
if( !id(npw2500_powerzero_inverter_producing).state)
{
if(id(npw2500_input_ch1_transparent).state && id(npw2500_input_ch2_transparent).state)
powerzero_status = "PT active, waitung for OpenDTU";
else
powerzero_status = "Inverter not producing";
}
else
if(!(id(npw2500_input_ch1_active).state || id(npw2500_input_ch2_active).state))
powerzero_status = "Inputs not active";
}
else
{
ESP_LOGD("npw2500", "PowerZero - Communication not ready");
id(npw2500_response_0x03_data_ready) = 0;
id(npw2500_response_0x0f_data_ready) = 0;
}
// npw switch disabled, but communication ready
if(!id(npw2500_zeropower_enabled).state && id(npw2500_enable_gridsensor) && id(npw2500_communication_ready))
{
id(npw2500_home_power_consuption).publish_state(id(npw2500_output_power).state + int(id(npw2500_grid_power).state));
ESP_LOGD("npw2500", "Home Power Consuption updated");
}
- id: reset_energy_sensors
then:
- sensor.integration.reset: npw2500_output_energy_ch1_daily
- sensor.integration.reset: npw2500_output_energy_ch2_daily
- sensor.integration.reset: npw2500_output_energy_daily
- sensor.integration.reset: npw2500_inout_energy_daily
- sensor.integration.reset: npw2500_input_energy_ch1_daily
- sensor.integration.reset: npw2500_input_energy_ch2_daily
- sensor.integration.reset: npw2500_input_energy_daily
- sensor.integration.reset: npw2500_inout_energy_daily
- sensor.integration.reset: npw2500_home_energy_daily
- sensor.integration.reset: npw_grid_energy_daily
- sensor.integration.reset: npw_grid_export_energy_daily
- sensor.integration.reset: npw_grid_import_energy_daily
- id: restart_inverter
then:
- logger.log: Restart Inverter
- homeassistant.service:
service: button.press
data_template:
entity_id: !secret inverter_restart
- id: restart_battery
then:
lambda: |-
id(ble_command).execute(0x25, 0x01);
ESP_LOGD("npw2500", "Restart Battery Command sent");
- id: check_dod
then:
lambda: |-
// BugFix - Battery Discharge randomly 100%
bool enable_dodfix = true; // set enable_dodfix to false if you dont need bugfix
if(id(npw2500_response_0x03_data_ready) && enable_dodfix)
{
int discharge_state = int(id(npw2500_discharge_slider).state);
if(id(npw2500_discharge_treshold).state != discharge_state) // check for difference between slider value and battery value
{
id(ble_command)->execute(0x0B,discharge_state); // send slidervalue to battery
ESP_LOGE("npw2500", "Watch Task - DOD corrected");
}
}
- id: watch_task
then:
lambda: |-
int batt_out_power_switch_power = 400; // set avarage power breakpoint for switching channels
int min_balancing_value = 50; // if one channel has less power start rebalancing
int max_timecount = 6; // defines the cycle time. One timecount is 10 seconds, 6*10 is one minute, 18*10 is three minutes
static int timecount = 0;
static int chn = 1;
static int batt_out_power = 0;
static bool rebalancing_flag = false;
static int last_channel_state = 0;
int batt_out_power_avg = 0;
int batt_out_power_act = 0;
ESP_LOGD("npw2500", "Watch Task started");
if(id(npw2500_enable_battery_control_switch).state && id(npw2500_communication_ready))
{
//ESP_LOGD("npw2500", "Watch Task - npw2500_enable_battery_control_switch");
batt_out_power_act = id(npw2500_output_power).state; // get actual battery output power
if(batt_out_power_act > 1000) batt_out_power_act = 0; // limit check in case of start up
//id(npw2500_battery_control_status).publish_state("Battery Control enabled");
ESP_LOGD("npw2500", "Watch Task - timecount = %d",timecount);
if(timecount == 0)
{
batt_out_power = 0; // reset values when starting new cycle
batt_out_power_avg = 0;
timecount ++;
}
else if (timecount < max_timecount)
{
batt_out_power += batt_out_power_act; // sum batt_out_power
batt_out_power_avg = batt_out_power / timecount;
ESP_LOGD("npw2500", "Watch Task - timecount avg. power = %d",timecount);
timecount ++;
}
else // we reached max_timecount
{
batt_out_power += batt_out_power_act; // calculate actual values
batt_out_power_avg = batt_out_power / timecount;
bool switch_ch1_on = id(npw2500_powerout_switch_ch1).state; // get state of channel1 switch
bool switch_ch2_on = id(npw2500_powerout_switch_ch2).state; // get state of channel2 switch
timecount = 0; // reset timecount
// Enable if only one output switch is set ON and the other one is set OFF and PT switch is OFF
if(((!switch_ch1_on && switch_ch2_on) || (switch_ch1_on && !switch_ch2_on)) && !id(npw2500_powerout_pv2_switch).state)
{
// check if we are not in pt transparent mode
if(!(id(npw2500_input_ch1_transparent).state || id(npw2500_input_ch2_transparent).state))
{
ESP_LOGD("npw2500", "Watch Task - check output power");
std::string power_str = "";
id(npw2500_command_sent_count).publish_state(0);
id(npw2500_enable_output_control) = true;
// check if the battery output power > output_higher_limit
if(batt_out_power_avg > batt_out_power_switch_power)
{
// check if rebalancing flag is set and rebalancing conditions are met
if( rebalancing_flag && id(npw2500_output_ch1_active).state && id(npw2500_output_ch2_active).state &&
(id(npw2500_output_power_ch1).state <= min_balancing_value || id(npw2500_output_power_ch2).state <= min_balancing_value))
{ // send restart inverter command
id(restart_inverter)->execute();
ESP_LOGD("npw2500", "Inverter restarted for rebalancing");
id(npw2500_command_sent_count).publish_state(4);
rebalancing_flag = false; // reset rebalancing flag
}
else
{
rebalancing_flag = false; // reset rebalancing flag
}
// check for channel switch 1->2
if((last_channel_state == 1) && id(npw2500_output_ch1_active).state && id(npw2500_output_ch2_active).state )
{
rebalancing_flag = true; // set rebalancing flag
last_channel_state = 2; // 2 channels active
id(npw2500_battery_control_status).publish_state("Checking for Rebalancing");
id(npw2500_command_sent_count).publish_state(3);
}
if(!rebalancing_flag) // if rebalancing flag is set, we are already in 2 channel mode
{
id(npw2500_set_output_state_ch1) = true; // turn on both outputs
id(npw2500_set_output_state_ch2) = true;
id(npw2500_update_output_state) = true;
id(npw2500_command_sent_count).publish_state(2);
if(id(npw2500_output_ch1_active).state && id(npw2500_output_ch2_active).state) // if both outputs are on, report 2 Channel mode
{
power_str = "2 Channel avg. power " + std::to_string(batt_out_power_avg) +" W";
id(npw2500_battery_control_status).publish_state(power_str);
ESP_LOGD("npw2500",power_str.c_str());
}
else // we are in switching mode
{
power_str = "Switching Channels avg. power " + std::to_string(batt_out_power_avg) +" W";
id(npw2500_battery_control_status).publish_state(power_str);
ESP_LOGD("npw2500",power_str.c_str());
}
}
}
else // batt_out_power_avg < batt_out_power_switch_power
{
if(!switch_ch1_on && switch_ch2_on) // switch channel 1 off
{
id(npw2500_set_output_state_ch1) = false;
id(npw2500_set_output_state_ch2) = true;
id(npw2500_update_output_state) = true;
}
else // switch channel 2 off
{
id(npw2500_set_output_state_ch1) = true;
id(npw2500_set_output_state_ch2) = false;
id(npw2500_update_output_state) = true;
}
id(npw2500_command_sent_count).publish_state(1);
if(id(npw2500_output_ch1_active).state && id(npw2500_output_ch2_active).state) // if both outputs are on, report switching mode
{
power_str = "Switching Channels avg. power " + std::to_string(batt_out_power_avg) +" W";
id(npw2500_battery_control_status).publish_state(power_str);
ESP_LOGD("npw2500",power_str.c_str());
}
else
{
power_str = "1 Channel avg. power " + std::to_string(batt_out_power_avg) +" W"; // report 1 Channel mode
id(npw2500_battery_control_status).publish_state(power_str);
ESP_LOGD("npw2500",power_str.c_str());
}
rebalancing_flag = false;
last_channel_state = 1; // set 1 channel state
}
}
else
{
id(npw2500_battery_control_status).publish_state("PTMode active");
id(npw2500_enable_output_control) = false;
}
}
else
{
id(npw2500_battery_control_status).publish_state("Both CH1/Ch2 are ON or OFF or PT ON");
id(npw2500_enable_output_control) = false;
}
}
}
else
{
if(!id(npw2500_enable_battery_control_switch).state)
{
id(npw2500_battery_control_status).publish_state("Battery Control disabled");
timecount = 0;
rebalancing_flag = false;
last_channel_state = 0;
id(npw2500_enable_output_control) = false;
}
}
### End of NPW2500.yaml ###
NPWDashboard Setup
Nachdem ihr den ESPNode NPW2500 in den HA integriert habt und unter
Settings->Device&Services->Integrations>ESPhome
das device "No Power Wasted 2500" vorhanden ist,
könnt ihr mit der Vorlage NPWDashboard V0.3 das entsprechende Dashboard erzeugen.
Ihr geht folgend vor:
HA-> Settings -> Dasboards
rechts unten auf das blaue Feld + ADD DASHBOARD drücken und
"New Dashboard" from Scratch" auswählen.
Als Name NPW2500 eingeben und "CREATE" drücken.
In der linken HA Dashboard Auswahlliste sollte dieses nun angezeigt werden.
In der Liste auswählen und öffnen.
Es sollte sich nun eine leeres Dashboard mit dem Namen NPW2500 öffnen.
Rechts oben in der blauen Leiste die 3 senkrechten Punkte clicken und "Edit Dashboard" auswählen .
Nun in der grauen Leiste oben wieder die 3 Punkte anklicken und "RAW CONFIGURATION EDITOR" auswählen.
Es öffnet sich nun ein Editierfenster in das ihr den Inhalt von NPWDashboard V0.3 kopiert. (Die ersten 2 vorgegebenen Zeilen überschreiben)
Wenn ihr fertig seid rechts oben "Save drücken" und den Editor mit dem x links oben verlassen.
Nun sollten die Panels im Dashboard angezeigt werden und oben rechts auf "Done" drücken.
views:
- title: No Power Wasted
badges: []
cards:
- type: entities
entities:
- entity: number.esphome_npw2500_set_discharge_threshold
name: Set Discharge threshold
- entity: sensor.esphome_npw2500_discharge_threshold
name: Discharge threshold
- entity: switch.esphome_npw2500_set_power_out_switch_ch1
name: Set Power Out Switch Ch1
- entity: binary_sensor.esphome_npw2500_output_ch1_active
name: Ouput Ch1 active
- entity: switch.esphome_npw2500_set_power_out_switch_ch2
name: Set Power Out Switch Ch2
- entity: binary_sensor.esphome_npw2500_output_ch2_active
name: Ouput Ch2 active
- entity: switch.esphome_npw2500_set_pv2_passtrough_switch
name: Set PV2 Passtrough Switch
- entity: binary_sensor.esphome_npw2500_passthrough_active
name: PassThrough active
- entity: number.esphome_npw2500_set_solar_charge_threshold
name: Set Solar Charge threshold
- entity: sensor.esphome_npw2500_solar_charge_threshold
name: Solar Charge threshold
- entity: switch.esphome_npw2500_enable_battery_control
name: Enable Battery Control
- entity: sensor.esphome_npw2500_powerzero_battery_control_status
name: Battery Control Status
title: No Power Wasted 2500 V0.322 (Test)
show_header_toggle: false
state_color: true
- type: entities
entities:
- entity: switch.esphome_npw2500_powerzero_enabled
name: PowerZero enabled
- entity: sensor.esphome_npw2500_powerzero_status
name: PowerZero Status
- entity: number.esphome_npw2500_set_power_limit_rel
name: Set Power Limit maximum
- entity: sensor.esphome_npw2500_opendtu_power_limit_rel_target_value
name: openDTU Power Limit target value
- entity: sensor.esphome_npw2500_opendtu_power_limit_rel_actual_value
name: openDTU Power Limit actual value
- entity: number.esphome_npw2500_set_max_cell_voltage
name: Set max Cell Voltage
- entity: sensor.esphome_npw2500_cell_voltage_max
name: Cell Voltage actual
- entity: number.esphome_npw2500_set_grid_power_offset
name: Set Grid Power Offset
- entity: sensor.esphome_npw2500_grid_power_offset
name: Grid Power Offset
- entity: sensor.esphome_npw2500_grid_power
name: Grid Power
- entity: binary_sensor.esphome_npw2500_powerzero_inverter_producing
name: Inverter producing
- entity: button.esphome_npw2500_restart_inverter
name: Inverter Restart
title: NPW PowerZero - Nulleinspeisung
show_header_toggle: false
state_color: true
- type: entities
entities:
- entity: sensor.esphome_npw2500_input_power
name: Battery Solar Input Power
- entity: sensor.esphome_npw2500_output_power
name: Battery DTU Output Power
- entity: sensor.esphome_npw2500_power_inout
name: Battery Power
- entity: sensor.esphome_npw2500_grid_power
name: Grid Power
- entity: sensor.esphome_npw2500_home_power_consumption
name: Home Power Consumption
title: NPW Solar
- type: entities
entities:
- entity: sensor.esphome_npw2500_input_energy_daily
name: Solar
- entity: sensor.esphome_npw2500_battery_inout_energy_daily
name: Battery
- entity: sensor.esphome_npw2500_output_energy_daily
name: Battery Output
- entity: sensor.esphome_npw2500_home_energy_consumption_daily
name: Home Consumption
- entity: sensor.esphome_npw2500_grid_energy_daily
name: Grid
- entity: sensor.esphome_npw2500_grid_export_energy_daily
name: Grid Export
- entity: sensor.esphome_npw2500_grid_import_energy_daily
name: Grid Import
- entity: sensor.esphome_npw2500_input_ch1_energy_daily
name: Solar Ch1
- entity: sensor.esphome_npw2500_input_ch2_energy_daily
name: Solar Ch2
- entity: sensor.esphome_npw2500_output_ch1_energy_daily
name: Battery Output Ch1
- entity: sensor.esphome_npw2500_output_ch2_energy_daily
name: Battery Output Ch2
- entity: button.esphome_npw2500_reset_daily_energy
name: Reset Daily Energy
title: NPW Energy Daily
show_header_toggle: false
- type: entities
entities:
- entity: sensor.esphome_npw2500_input_power
name: Input Power
- entity: sensor.esphome_npw2500_input_ch1_power
name: Input Ch1 Power
- entity: binary_sensor.esphome_npw2500_input_ch1_active
name: Input Ch1 active
- entity: binary_sensor.esphome_npw2500_input_ch1_transparent
name: Input Ch1 transparent
- entity: sensor.esphome_npw2500_input_ch2_power
name: Input Ch2 Power
- entity: binary_sensor.esphome_npw2500_input_ch2_active
name: Input Ch2 active
- entity: binary_sensor.esphome_npw2500_input_ch2_transparent
name: Input Ch2 transparent
title: NPW Inputs
show_header_toggle: false
state_color: true
- type: entities
entities:
- entity: sensor.esphome_npw2500_output_power
name: Output Power
- entity: sensor.esphome_npw2500_output_power_ch1
name: Output Power Ch1
- entity: binary_sensor.esphome_npw2500_output_ch1_active
name: Output Ch1 active
- entity: sensor.esphome_npw2500_output_power_ch2
name: Output Power Ch2
- entity: binary_sensor.esphome_npw2500_output_ch2_active
name: Output Ch2 active
title: NPW Outputs
show_header_toggle: false
state_color: true
- type: entities
entities:
- entity: binary_sensor.esphome_npw2500_battery_wifi_connected
name: Battery WiFi connected
- entity: sensor.esphome_npw2500_battery_wifi_disconnects
name: Battery WiFi disconnects
- entity: binary_sensor.esphome_npw2500_esp_ble_connected
name: ESP Ble connected
- entity: sensor.esphome_npw2500_esp_ble_disconnects
name: Battery Ble disconnects
- entity: binary_sensor.esphome_npw2500_esp_ha_connected
name: ESP HA connected
- entity: sensor.esphome_npw2500_esp_ha_disconnects
name: Battery HA disconnects
- entity: binary_sensor.esphome_npw2500_esp_wifi_connected
name: ESP Wifi connected
- entity: sensor.esphome_npw2500_esp_wifi_disconnects
name: ESP WiFi disconnects
- entity: button.esphome_npw2500_restart_esp
name: Restart ESP
- entity: switch.esphome_npw2500_enable_bluetooth
name: Enable Bluetooth
title: NPW Communication
show_header_toggle: false
state_color: true
- type: entities
entities:
- entity: sensor.esphome_npw2500_cell_voltage_avg
name: Cell Voltage avg
- entity: sensor.esphome_npw2500_cell_voltage_diff
name: Cell Voltage diff
- entity: sensor.esphome_npw2500_cell_voltage_max
name: Cell Voltage max
- entity: sensor.esphome_npw2500_cell_voltage_min
name: Cell Voltage min
- entity: sensor.esphome_npw2500_cell_voltage_sum
name: Cell Voltage sum
title: NPW Battery Cells
show_header_toggle: false
state_color: true
- type: entities
entities:
- entity: sensor.esphome_npw2500_battery_remaining_capacity
name: Battery remaining capacity
- entity: sensor.esphome_npw2500_battery_soc
name: Battery SOC
- entity: sensor.esphome_npw2500_battery_soc_dynamic
name: Battery SOC dynamic
- entity: sensor.esphome_npw2500_temperature_sensor_1
name: Temperature Sensor 1
- entity: sensor.esphome_npw2500_temperature_sensor_2
name: Temperature Sensor 2
- entity: sensor.esphome_npw2500_battery_version
name: Battery Version
- entity: button.esphome_npw2500_restart_battery
name: Restart Battery
title: NPW Battery
show_header_toggle: false
state_color: true
# Secrets V0.3
# sectrets.yaml
# Wi-Fi SSID and password
# use your ssid and password
wifi_ssid: "ssid"
wifi_password: "password"
# mac address of the batterie, you find it in in the App
battery_ble_mac: "e8:8d:a6:56:xx:xx"
# HA Sensor of your actual grid power
# sensor.grid_power is the id of my entity, enter your id
# "sensor.xyz..."
npw2500_grid_power: "sensor.grid_power"
# HA Sensor of your OpenDTU relativ power limit
# number.hm_800_limit_nonpersistent_relative is the id of my entity, enter your id
# '"number.xyz..."'
inverter_rel_power_limit: '"number.hm_800_limit_nonpersistent_relative"'
# "number.xyz..."
inverter_rel_power_limit_2: "number.hm_800_limit_nonpersistent_relative"
# HA Sensor of your OpenDTU inverter producing
# binary_sensor.hm_800_producing is the id of my entity, use your id
# "binary_sensor.xyz..."
inverter_producing: "binary_sensor.hm_800_producing"
# HA Sensor of your OpenDTU restart inverter
# "button.hm_800_restart_inverter" is the id of my entity, use your id
# "button..xyz..."
inverter_restart: "button.hm_800_restart_inverter"
@rschoell
Copy link

@neromatrix
Erstmal super Projekt, dass Du hier am Laufen hast. Ich habe lange mit mir gerungen, um endlich von der v1 auf die jetzige aktuelle Version zu wechseln. Läuft alles super. Eine Sache habe ich jedoch, die Du vllt noch einbauen könntest:
ich habe einen Marstek B2500, also einen v1.2.

In @noone2k's neuester Version ist eingebaut, die Timer zu aktivieren/deaktivieren und Timer3 entsprechend anzupassen. Das wäre bei dir der Discharge Threshold.
Hast Du geplant, etwas ähnliches bei Dir auch für Besitzer der neueren Akku's einzubauen?

@rschoell
Copy link

Ich brauche mal Euer Schwarmwissen:
Ich teste gerade welcher Mode bei mir der bessere ist. Im Modus "zuerst vollständig laden" sehe ich leider beim Erreichen von 100% dieses Verhalten:

image

Der Akku schaltet nicht wie er sollte in einen vollständigen Bypass, sondern alterniert zwischen 99% und 100%. Dabei schaltet er natürlich in/output immer wieder ein/aus, was durch die Wartezeit verm. etwas Energie kostet.

Weiters sehe ich im Passthrough Mode folgendes Verhalten: Ich habe eine Entladeschwelle von 240W eingetragen, was meinem untersten Energiebedarf entspricht und somit soll kein Strom ins Grid entweichen. Das funktioniert beim Entladen. Beim Laden, würde ich mir folgendes Verhalten erwarten: Er lädt, bis er sicher die gewünschten 240W liefern kann und verwendet den kompletten Überschuss für's Laden der Batterie. Bei Voll, pusht er allen Strom im Passthrough durch, also bis zu 800W.
Leider siehts aber so aus: er nutzt vom eingehenden Strom ca. 2/3 für den Passthrough beim Laden und nur 1/3 fürs Laden des Akku's. Wenn voll, drosselt er CH1 auf ca. 1/3 von CH2. Beide Module stehen nach Süden ausgerichtet und haben dabei keinen Schattenwurf, was für mich heißt, es müsste über CH1 und CH2 gleich viel Strom kommen.

Hat das Verhalten von Euch auch jemand? Über die App habe ich einen ersten request geschickt, der aber nur das gewünschte Verhalten bestätigte und nicht auf die Fehlerhafte Firmware einging. Interessanterweise habe ich aber gleich noch für meinen V 1.2 Akku die Firmware 2.10 bekommen.

Danke Euch für's lesen und beantworten.

@JulianBursee
Copy link

Grid Power Offset Regelung spinnt seit HA Update

Hallo in die Runde, nach dem heutigen Update von HA auf die V 2024.6.3 spinnt die Grid Power Offset Regelung.....kann das jemand bestätigen ?

Ich hatte sonst immer einen Minimalbezug aus dem Netz von 200 W eingestellt, damit bin ich dann mit den beiden Akkus teilweise durch die ganze Nacht gekommen. Also Schieberegler auf 200 W und dann als Respond auch dauerhaft die 200 W, jetzt springt dieser Wert aber immer hin und her und ich speise ein, anstatt die Batterien voll zu machen....

@Milchtrinker99
Copy link

Hallo,
Ich bin neu hier, und finde das Projekt sehr spannend. Ich habe auch 2 speicher einmal einen Becool V1. Und einen Bluepalm 1.2.
HA habe ich auch, aber bin da auch noch ziemlich Grün hinter den Ohren.
Gibt es vielleicht für Leute wie mich, irgendwo eine Anleitung wie man das als Laie zum laufen bekommt? Was ist ESP 32? Braucht man da noch eine zusätzliche Karte?
Ich bedanke mich schon einmal für die Infos.
Lg Helmut

@gine78
Copy link

gine78 commented Jun 20, 2024

Hallo, Ich bin neu hier, und finde das Projekt sehr spannend. Ich habe auch 2 speicher einmal einen Becool V1. Und einen Bluepalm 1.2. HA habe ich auch, aber bin da auch noch ziemlich Grün hinter den Ohren. Gibt es vielleicht für Leute wie mich, irgendwo eine Anleitung wie man das als Laie zum laufen bekommt? Was ist ESP 32? Braucht man da noch eine zusätzliche Karte? Ich bedanke mich schon einmal für die Infos. Lg Helmut

Ein ESP32 ist ein Minicomputer, welcher sich individuell anpassen lässt. Mit diesen günstigen und kleinen Platinen kannst du diverse Projekte realisieren.

Am gängigsten ist die implementierung über https://esphome.io/index.html (ESPHOME). Es gibt für Homeassitant auch eine Implementierung für ESPhome. Was das Ganze nochmal leichter macht.
Ein Tutorial wird hier keiner schreiben, weil die Voraussetzung schon ist, dass man etwas von dem hier versteht.

@7Netler
Copy link

7Netler commented Jun 30, 2024

Hat jemand das MQTT Protokoll des Herstellers in Verwendung (ohne ESP32) mit Homeassistant und kann mir einen Tipp geben wie ich Daten vom Speicher abfragen kann ? Verstehe die Doku in der Power Zero App nicht wirklich. Der Speicher ist aber mit mit meinem lokalen MQTT Broker verbunden. Jedoch muss man die Daten ja abfragen, da diese nicht automatisch gesendet werden und ich stehe da auf dem Schlauch. Mehr Knowhow oder Kompetenz zum Thema ist bei Google nicht zu finden als in diesem Forum

@SRc1221
Copy link

SRc1221 commented Jul 3, 2024

Benötige ich die Open DTU Werte vom WR dass eine Nulleinspeisung funktioniert?
Mein WR ist nicht damit kompatibel. ( Es ist ein NEP BDM- 800 ) Kann ich die Werte auch statisch setzen, außer dem power limit scheinen mir diese werte nicht notwendig zu sein wenn der Hausverbrauch und die Batterie Entladung bzw solarmodul Leistung gemessen wird.
Screenshot_6

@noone2k
Copy link

noone2k commented Jul 4, 2024

du müsste eigentlich jmd. antworten, der HA nutzt.

ABER: rein theor. kannst du da jeden Bezugspunkt eintragen, egal von wem,
die die Werte oder Schaltmöglichkeiten repräsentieren.
Gibt hier Leute, die das ganze ohne Hoymiles laufen lassen haben,
mit den Möglichkeiten, die Ihre Wechselrichter bieten.
Man muss nur irgendwie an die geforderten Werte kommen bzw. die Ausgabe steuern können.

wenn du statisch arbeiten willst, kannst du dem wechselrichter sagen, wieviel er ausgeben soll
( bei nem v1 und wenn der wr das ermöglicht ).

bei nem v2 kannst du ja die ausgabeleistung selbst festlegen.

@mastertape
Copy link

mastertape commented Jul 19, 2024

habs sry

@ruokxx
Copy link

ruokxx commented Jul 22, 2024

Hey Leute ,

Ich bin ziemlich frisch mit ESP Home und meinem Batterie Speicher Marstek B2500 habe ich erst seid kurzem .
Da Ich schon Jahrelang Homeassistant nutze , würde ich die Daten gerne in meinem EnergieDashboard , und allgemein in Homeassistant haben . Ich hab das Script in meinen ESP32 eingepflegt und geflasht . Der ESP erhält nun Daten . Aber leider immer nur kurz und es aktuallisiert sich alles nicht so wie es soll . Im Screenshot findet ihr die Fehler die mir angezeigt werden , Über hilfe wäre ich sehr dankbar .

PS Ich habe die daten direkt in der YAML geändert und nicht über die secret YAML spielt das eine Rolle ?

Viele Grüße

Screenshot 2024-07-22 201207

@ruokxx
Copy link

ruokxx commented Jul 22, 2024

Hier noch ein weiteres Bild

Screenshot 2024-07-22 201712

@tbretz65
Copy link

sieht aber nicht nach dem yaml hier aus.
ist wohl das von @noone2k

@ruokxx
Copy link

ruokxx commented Jul 23, 2024

Oh sorry ich hab im falschen tab kommentiert... ^^

@rschoell
Copy link

Servus, hat jemand eigentlich schon Mal probiert, 2 B2500 in Reihe zu schalten? Müsste ja eigentlich funktionieren, da auch der Ausgang noch DC ist. Spricht aus eurer Sicht war dagegen?

@helmi55
Copy link

helmi55 commented Jul 30, 2024

Guten Abend
mein HA ist aktuell und seit heute vormittag bekomme ich keine Daten mehr vom ESP32
Hat sich da was bei ESPHome geändert was an mir vorbeigezogen ist?

Danke für eure Hilfe
Gruß
Helmut

@azazul1980
Copy link

Guten Abend mein HA ist aktuell und seit heute vormittag bekomme ich keine Daten mehr vom ESP32 Hat sich da was bei ESPHome geändert was an mir vorbeigezogen ist?

Danke für eure Hilfe Gruß Helmut

Ich habe alles auf dem neuesten Stand und habe mit beiden Accus kein Problem. Nutze aber die Lösung von. Tomquist.

@kallejoken
Copy link

kallejoken commented Nov 12, 2024

ich habe beim kompilieren folgende fehlermeldung - kann wer helfen?

`INFO ESPHome 2024.10.3
INFO Reading configuration /config/esphome/akku-b2500.yaml...
INFO Generating C++ source...
INFO Compiling app...
Processing akku-b2500 (board: esp32dev; framework: espidf; platform: platformio/[email protected])

HARDWARE: ESP32 240MHz, 320KB RAM, 4MB Flash

  • framework-espidf @ 3.40408.0 (4.4.8)
  • tool-cmake @ 3.16.4
  • tool-ninja @ 1.7.1
  • toolchain-esp32ulp @ 2.35.0-20220830
  • toolchain-xtensa-esp32 @ 8.4.0+2021r2-patch5
    Reading CMake configuration...
    No dependencies
    Compiling .pioenvs/akku-b2500/src/main.o
    Compiling .pioenvs/akku-b2500/bt/host/bluedroid/btc/core/btc_sec.o
    Compiling .pioenvs/akku-b2500/bt/host/bluedroid/btc/core/btc_sm.o
    Compiling .pioenvs/akku-b2500/bt/host/bluedroid/btc/core/btc_storage.o
    Compiling .pioenvs/akku-b2500/bt/host/bluedroid/btc/core/btc_util.o
    Compiling .pioenvs/akku-b2500/bt/host/bluedroid/btc/profile/std/a2dp/bta_av_co.o
    Compiling .pioenvs/akku-b2500/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp.o
    Compiling .pioenvs/akku-b2500/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_control.o
    Compiling .pioenvs/akku-b2500/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.o
    /config/esphome/akku-b2500.yaml: In function 'void setup()':
    /config/esphome/akku-b2500.yaml:856:116: error: expected primary-expression before '.' token
    name: Set Grid Power Offset
    ^
    Compiling .pioenvs/akku-b2500/bt/host/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.o
    Compiling .pioenvs/akku-b2500/bt/host/bluedroid/btc/profile/std/a2dp/btc_av.o
    Compiling .pioenvs/akku-b2500/bt/host/bluedroid/btc/profile/std/avrc/btc_avrc.o
    Compiling .pioenvs/akku-b2500/bt/host/bluedroid/btc/profile/std/avrc/bta_avrc_co.o
    Compiling .pioenvs/akku-b2500/bt/host/bluedroid/btc/profile/std/hf_ag/bta_ag_co.o
    Compiling .pioenvs/akku-b2500/bt/host/bluedroid/btc/profile/std/hf_ag/btc_hf_ag.o
    Compiling .pioenvs/akku-b2500/bt/host/bluedroid/btc/profile/std/hf_client/btc_hf_client.o
    Compiling .pioenvs/akku-b2500/bt/host/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.o
    Compiling .pioenvs/akku-b2500/bt/host/bluedroid/btc/profile/std/hid/btc_hd.o
    Compiling .pioenvs/akku-b2500/bt/host/bluedroid/btc/profile/std/hid/btc_hh.o
    Compiling .pioenvs/akku-b2500/bt/host/bluedroid/btc/profile/std/hid/bta_hh_co.o
    Compiling .pioenvs/akku-b2500/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.o
    Compiling .pioenvs/akku-b2500/bt/host/bluedroid/btc/profile/std/gap/btc_gap_bt.o
    Compiling .pioenvs/akku-b2500/bt/host/bluedroid/btc/profile/std/gap/bta_gap_bt_co.o
    Compiling .pioenvs/akku-b2500/bt/host/bluedroid/btc/profile/std/gatt/btc_gatt_common.o
    Compiling .pioenvs/akku-b2500/bt/host/bluedroid/btc/profile/std/gatt/btc_gatt_util.o
    Compiling .pioenvs/akku-b2500/bt/host/bluedroid/btc/profile/std/gatt/btc_gattc.o
    Compiling .pioenvs/akku-b2500/bt/host/bluedroid/btc/profile/std/gatt/btc_gatts.o
    Compiling .pioenvs/akku-b2500/bt/host/bluedroid/btc/profile/std/spp/btc_spp.o
    *** [.pioenvs/akku-b2500/src/main.o] Error 1
    ========================= [FAILED] Took 25.30 seconds =========================`

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