-
-
Save tbretz65/4b42570635edffd310a887b270adcd86 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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 | |
- platform: esphome | |
password: !secret ota_password | |
# 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 = 1500; | |
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 = 30; | |
int send_every_number_of_cycles = 6; | |
bool use_slewrate_limiter = 1; | |
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 ### |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment