-
-
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" |
Hi zusammen,
erst mal ein ganz dickes DANKE an den/die Coder von dem Projekt, MEGA!
Ich habe den B2500 von Marstek mit der SW 1.63 am laufen und habe folgendes Problem. Der ESP pollt nur einmalig die Werte danach nicht mehr, anbei mal ein Screenshot vom LOG
Habt ihr sowas auch schon gehabt oder wisst ihr woran das liegen könnte?
EDIT: Problem gelöst, liegt anscheinend daran, wenn's mit framework: -> type: arduino gebaut wird...
Gruß Christian
Auch hier wieder EDITA EDIT: mein copy paste hatte offenbar gestern etwas falsches drin, weswegen der Sensor komplett falsch eingerichtet war. Funktioniert wieder :D
Hallo,
bin relativ neu hier und Neuling in ESPHome.
Ich besitze ein B2500 seit einer Woche und ich möchte die Werte über ESP auslesen, aber ich benötige nicht die Null Einspeisung,
die ich hier im Code gelesen habe. Ich weiss nicht ob man nur die Codzeilen rauslöschen kann oder ob es noch Anpassungen benötigt.
In Yaml bin ich auch noch Anfänger, vielleicht könnt ihr mir helfen?
Ich setze eine ESP32 D1 mini ein und Home Assistent ESP Home.
Vielen Dank für in voraus
Tom-48
@Tom-48
Du kannst das yaml ohne Änderung verwenden; die Null-Einspeisung kann im Dashboard ein/ausgeschaltet werden.
Ich verwende NPW auch ohne Null-Einspeisung.
@Tom-48
Du kannst die sensor in der seecret.yaml einfach ignorieren. Nur wifi und MAC Adresse anpassen.
@JoeBue1 @fefi-byte
Danke euch beiden! Es läuft, nun kann ich es in Nod-Red nutzen
Hallo,
ich habe NPW2500 nach dem Studieren der ganzen Kommentare nun auch zum Laufen gebracht. Vielen Dank für das tolle Projekt.
Ich wollte nur meine Beobachtungen mit euch teilen, da ich anscheinend eine andere Version der Batterie habe, als die meisten hier…
In der App gibt es bei mir eine zeitgesteuerte Entladeeinstellung. Dieser in der App eingestellte Wert legt den “Solar Charge Threshold” fest und über HA kann ich den Wert nicht ändern. Da die App maximal 800Watt erlaubt, kann ich auch nicht auf die “empfohlenen” 990 Watt einstellen.
Es gibt auch noch eine Entladeeinstellung, welche sich selber anpassen soll. Da ich jedoch nicht den “Sensor” (was auch immer das sein mag) habe, kann ich das nicht testen.
das ist ein v1.2/v2 ...
wenn du die möglichkeit hast, guck nach dem geräte type ( dürfte HMA-X sein )
selbstanpassung ist für die verbindung mit einem smartmeter ...
einige befehle der v1 funktionieren nicht oder anders bei der v2 ... ( and vice versa )
war gerade dabei mir die neuste beta der esphome anzusehen in verbindung einer neueren esp-idf.
sntp wurde endlich portiert ... und was für dich interessant sein könnte: der http_request befehl wurde portiert.
ich weiss nicht mehr genau für was, aber du wolltest mal einen http-request versenden ...
in der nächsten offiziellen version könnte das also möglich sein ( habe gerade die beta drauf, aber den befehl noch nicht getestet )
@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?
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:
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.
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....
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
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.
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
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.
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.
habs sry
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
sieht aber nicht nach dem yaml hier aus.
ist wohl das von @noone2k
Oh sorry ich hab im falschen tab kommentiert... ^^
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?
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
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.
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/espressif32@5.4.0)
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 =========================`
schönes Projekt. Danke. Läuft auf Anhieb.
Allerdings habe ich zwei Akkus, Würde auch zwei ESPs benutzen, aber was muss ich anpassen? An der Yaml und an dem Dashboard, damit die sich nicht in die quere kommen?
Danke in vorraus
Joewest
PS:
kann der Ansatz von ChatGPT funktionieren?
`esphome:
name: esphome-npw2500
friendly_name: No Power Wasted 2500
on_boot:
priority: 600
then:
- lambda: |-
id(npw2500_ble_disconnects_1).publish_state(0);
id(npw2500_ble_disconnects_2).publish_state(0);
id(npw2500_wifi_disconnects).publish_state(0);
id(npw2500_api_disconnects).publish_state(0);
id(npw2500_battery_wifi_disconnects_1).publish_state(0);
id(npw2500_battery_wifi_disconnects_2).publish_state(0);
id(npw2500_battery_control_status_1).publish_state("");
id(npw2500_battery_control_status_2).publish_state("");
id(npw2500_command_sent_count_1).publish_state(0);
id(npw2500_command_sent_count_2).publish_state(0);
esp32:
board: esp32dev
framework:
type: esp-idf
OTA
#ota:
wifi:
id: npw2500_wifi
ssid: !secret wifi_ssid
password: !secret wifi_password
reboot_timeout: 0s
fast_connect: True
api:
id: api_server
logger:
esp32_ble_tracker:
ble_client:
Akku 1
- mac_address: !secret battery_ble_mac_1
id: npw2500_ble_1
Akku 2
- mac_address: !secret battery_ble_mac_2
id: npw2500_ble_2
globals:
Akku 1
- id: npw2500_communication_ready_1
type: bool
restore_value: no
initial_value: '0'
Akku 2
- id: npw2500_communication_ready_2
type: bool
restore_value: no
initial_value: '0'
text_sensor:
Akku 1: Status
- platform: template
id: npw2500_battery_control_status_1
name: Akku 1 Status
Akku 2: Status
- platform: template
id: npw2500_battery_control_status_2
name: Akku 2 Status
sensor:
Akku 1: SOC
- platform: template
name: Akku 1 SOC
id: npw2500_battery_soc_1
unit_of_measurement: '%'
device_class: battery
accuracy_decimals: 0
Akku 2: SOC
- platform: template
name: Akku 2 SOC
id: npw2500_battery_soc_2
unit_of_measurement: '%'
device_class: battery
accuracy_decimals: 0
Akku 1: Zellspannung
- platform: template
name: Akku 1 Zellspannung Max
id: npw2500_cell_vmax_1
unit_of_measurement: V
device_class: voltage
accuracy_decimals: 3
Akku 2: Zellspannung
- platform: template
name: Akku 2 Zellspannung Max
id: npw2500_cell_vmax_2
unit_of_measurement: V
device_class: voltage
accuracy_decimals: 3
switch:
Akku 1: Batteriekontrolle
- platform: template
name: Akku 1 Batterie-Kontrolle
id: npw2500_enable_battery_control_switch_1
Akku 2: Batteriekontrolle
- platform: template
name: Akku 2 Batterie-Kontrolle
id: npw2500_enable_battery_control_switch_2
interval:
Akku 1
- interval: 5 sec
then:- logger.log: "Akku 1 wird abgefragt..."
- script.execute:
id: ble_parse_response_1
Akku 2
- interval: 5 sec
then:- logger.log: "Akku 2 wird abgefragt..."
- script.execute:
id: ble_parse_response_2
script:
Akku 1: BLE-Daten verarbeiten
- id: ble_parse_response_1
parameters:
x: char[]
then:
lambda: |-
// BLE-Daten von Akku 1 verarbeiten
ESP_LOGD("npw2500", "Akku 1 BLE-Daten verarbeitet.");
Akku 2: BLE-Daten verarbeiten
- id: ble_parse_response_2
parameters:
x: char[]
then:
lambda: |-
// BLE-Daten von Akku 2 verarbeiten
ESP_LOGD("npw2500", "Akku 2 BLE-Daten verarbeitet.");
PowerZero für beide Akkus
- id: power_zero
then:-
lambda: |-
if (id(npw2500_communication_ready_1)) {
// PowerZero-Logik für Akku 1
ESP_LOGD("npw2500", "PowerZero für Akku 1 aktiv.");
}if (id(npw2500_communication_ready_2)) {
// PowerZero-Logik für Akku 2
ESP_LOGD("npw2500", "PowerZero für Akku 2 aktiv.");
}
`
-
Hallo in die Runde. Ich habe mich bisher mit ESP Home nicht beschäftigt. Allerdings habe ich mir jetzt einen bestellt. Marstek habe ich ebenfalls und diesen würde ich gerne über ESP dann integrieren.
Homeassistent läuft über einen Windows Mini Pc. Kann mir jemand kurz erklären wie das instaliert wird? Muss ich denn ESP Home erstmal hinzufügen wie in Simons Video und anschließend diesenYAML Code einfach in Yaml hinzufügen? Sorry für die Anfönger Frage;)
Hi,
EDIT: mittlerweile ist der ESP per MQTT verbunden, jedoch erstellt mir der HA keine Entitäten dafür. Ist das so gewollt?