Iâm started to collect my Homevolt battery sensors from the local webserver in a package to access all data in Home-Assistant.
Please use if want, and post comments or improvements.
Invite: https://invite.tibber.com/zg5s6hew
- Enable local webserver on Homevolt
- Enabled at start or 3s press on left button under the hood
- Navigate to Homevolt local webserver by http://ip-address
- Force local webserver to enabled in Params
- Turn on password, if desired
- Turn on secure http, if desired
- Store Params to flash
Guide in swedish
Wi-Fi-guide
Om ditt batteri har dÄlig LTE-anslutning som orsakar lÄngsamma eller misslyckade uppdateringar, kan du manuellt stÀlla in Wi-Fi via batteriets portal:
Aktivera servicelÀge
- HÄll in knappen pÄ vÀnstra sidan av vÀxelriktaren i 3 sekunder.
- Anslut till batteriets Wi-Fi
- Ăppna Wi-Fi-instĂ€llningarna pĂ„ din telefon.
- Anslut till nÀtverket som heter HVSM-<QR-kod pÄ batteriet>.
- Konfigurera Wi-Fi via portalen
- NÀr du Àr ansluten bör en portal öppnas automatiskt.
- Klicka âKonfigurera Wi-Fiâ.
- VÀlj och anslut till kundens Wi-Fi-nÀtverk.
Om portalen inte öppnas automatiskt:
- Ăppna en webblĂ€sare och navigera till: http://10.133.70.1/ eller http://homevolt-.local
- Hitta serienumret pÄ vÀxelriktarens förpackning:
- Det börjar med 68b och ser ut som 68b6b34dcbac
Using custom components in package to calculate income:
to include packages folder to config.
homeassistant:
packages: !include_dir_named packages
Secrets file
- Change to http without s if not using local cert
- Change ip-address in the file.
homevolt_pass: "password_in_local_webserver"
homevolt_pris: 60000
homevolt_montage: "2025-01-01"
homevolt_status: "https://192.168.1.100/status.json"
homevolt_ems: "https://192.168.1.100/ems.json"
homevolt_error: "https://192.168.1.100/error_report.json"
homevolt_error_curl: >
echo {\"errors\": $(curl -sk -u 'admin:password' https://192.168.1.100/error_report.json) }
homevolt_schedule: "https://192.168.1.100/schedule.json"
homevolt_params: "https://192.168.1.100/params.json"
homevolt_params_curl: >
echo {\"params\": $(curl -sk -u 'admin:password' https://192.168.1.100/params.json) }
homevolt_logs: "https://192.168.1.100/logs.json"
homevolt_logs_curl: >
echo {\"logs\": $(curl -sk -u 'admin:password' https://192.168.1.100/logs.json) }
# whitelist check for commands before sending them
homevolt_console_curl: >
echo "{\"result\": \"$( curl -sk -u 'admin:password' -X POST --form cmd='{{
states('input_text.homevolt_cmd') if
states('input_text.homevolt_cmd') in [
'time uptime' ,'help' ,'lte_info' ,'tasks', 'power i',
'param_list', 'mqtt',
'lte_restart', 'lte_power 1','lte_power 0',
'ems_schedule_get',
'sched_list'
] or states('input_text.homevolt_cmd').startswith('echo ')
or states('input_text.homevolt_cmd').startswith('ping ')
or states('input_text.homevolt_cmd').startswith('lte_at ')
or states('input_text.homevolt_cmd').startswith('sched_del ')
or states('input_text.homevolt_cmd').startswith('sched_add ')
or states('input_text.homevolt_cmd').startswith('sched_set ')
or states('input_text.homevolt_cmd').startswith('ems_schedule_force ')
else
'echo command not accepted to send by HA'
}}' https://192.168.1.100/console.json | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/\\n/g' )\"}"
packages\homevolt.yaml
### Homevolt package
# 2025-04-23
#
# Custom changes
# Uses nordpool integration (https://www.home-assistant.io/integrations/nordpool/) for the sensor:
# sensor.nord_pool_se3_aktuellt_pris
# price for battery and purchased day
# ------------------------------------------------ #
# REST integration
rest:
- resource: !secret homevolt_status
username: "admin"
password: !secret homevolt_pass
verify_ssl: false
scan_interval: 300
timeout: 30
sensor:
- name: "Homevolt status"
unique_id: "homevolt_status"
value_template: "{{ value_json.uptime if 'uptime' in value_json }}"
icon: "mdi:battery-clock"
json_attributes:
- uptime
- wifi_status
- lte_status
- mqtt_status
- w868_status
- ems_status
- name: "Homevolt LTE cellid"
unique_id: "homevolt_lte_cellid"
value_template: >-
{{ ((value_json.lte_status.cell_id) | replace('"','')) if 'cell_id' in value_json.lte_status }}
icon: "mdi:sim"
- resource: !secret homevolt_ems
username: "admin"
password: !secret homevolt_pass
verify_ssl: false
scan_interval: 30
timeout: 30
sensor:
- name: "Homevolt EMS"
unique_id: "homevolt_ems"
value_template: "{{ value_json.ems[0].ems_data.state_str }}"
icon: >-
mdi:battery-{{ int((float(value_json.ems[0].ems_data.soc_avg)/100) | round(-1), 0)
if not float(value_json.ems[0].ems_data.soc_avg) < 5 else 'outline' }}
json_attributes:
- ems
- aggregated
- sensors
- name: "Homevolt EMS error"
unique_id: "homevolt_ems_error"
value_template: "{{ (value_json.ems[0].error_str)[:255] }}"
icon: "mdi:battery-unknown"
json_attributes_path: "$.ems[0]"
json_attributes:
- error_str
- name: "Homevolt EMS varning"
unique_id: "homevolt_ems_warning"
value_template: "{{ (value_json.ems[0].ems_data.warning_str | join(', ') | replace('_', ' ') | replace('ems', 'EMS'))[:255] }}"
icon: "mdi:battery-unknown"
json_attributes_path: "$.ems[0].ems_data"
json_attributes:
- warning_str
- name: "Homevolt EMS info"
unique_id: "homevolt_ems_info"
value_template: "{{ (value_json.ems[0].ems_data.info_str | join(', ') | replace('_', ' ') | replace('ems', 'EMS'))[:255] }}"
icon: "mdi:battery-unknown"
json_attributes_path: "$.ems[0].ems_data"
json_attributes:
- info_str
- name: "Homevolt temperatur"
unique_id: "homevolt_ems_temperature"
value_template: "{{ float(value_json.ems[0].ems_data.sys_temp,0)/10 }}"
icon: "mdi:battery-heart-variant"
unit_of_measurement: '°C'
device_class: temperature
- name: "Homevolt spÀnning L1"
unique_id: "homevolt_ems_l1"
value_template: "{{ value_json.ems[0].ems_voltage.l1 /10 }}"
unit_of_measurement: 'V'
icon: "mdi:meter-electric-outline"
device_class: voltage
- name: "Homevolt spÀnning L2"
unique_id: "homevolt_ems_l2"
value_template: "{{ value_json.ems[0].ems_voltage.l2 /10 }}"
unit_of_measurement: 'V'
icon: "mdi:meter-electric-outline"
device_class: voltage
- name: "Homevolt spÀnning L3"
unique_id: "homevolt_ems_l3"
value_template: "{{ value_json.ems[0].ems_voltage.l3 /10 }}"
unit_of_measurement: 'V'
icon: "mdi:meter-electric-outline"
device_class: voltage
- name: "Homevolt frekvens"
unique_id: "homevolt_ems_freq"
value_template: "{{ value_json.ems[0].ems_data.frequency /1000 }}"
unit_of_measurement: 'Hz'
icon: "mdi:meter-electric-outline"
device_class: frequency
- name: "Homevolt effekt"
unique_id: "homevolt_ems_power"
value_template: "{{ value_json.ems[0].ems_data.power }}"
unit_of_measurement: 'W'
icon: "mdi:battery-sync-outline"
device_class: power
- name: "Homevolt energi producerat"
unique_id: "homevolt_ems_prod"
value_template: "{{ value_json.ems[0].ems_data.energy_produced /1000 }}"
unit_of_measurement: 'kW'
icon: "mdi:battery-positive"
device_class: power
- name: "Homevolt energi konsumerat"
unique_id: "homevolt_ems_consumed"
value_template: "{{ value_json.ems[0].ems_data.energy_consumed /1000 }}"
unit_of_measurement: 'kW'
icon: "mdi:battery-negative"
device_class: power
- name: "Homevolt effekt tillgÀnglig"
unique_id: "homevolt_power_avail"
value_template: >-
{{
float(value_json.ems[0].ems_prediction.avail_ch_pwr,0) -
float(value_json.ems[0].ems_prediction.avail_di_pwr,0)
}}
unit_of_measurement: 'kW'
icon: "mdi:battery-negative"
device_class: power
json_attributes_path: "$.ems[0].ems_prediction"
json_attributes:
- avail_ch_pwr
- avail_di_pwr
- name: "Homevolt konsumerat"
unique_id: "homevolt_consumed"
value_template: "{{ value_json.ems[0].ems_aggregate.exported_kwh }}"
unit_of_measurement: 'kWh'
icon: "mdi:battery-positive"
device_class: energy
state_class: total
- name: "Homevolt producerat"
unique_id: "homevolt_produced"
value_template: "{{ value_json.ems[0].ems_aggregate.imported_kwh }}"
unit_of_measurement: 'kWh'
icon: "mdi:battery-negative"
device_class: energy
state_class: total
- name: "Homevolt bat0"
unique_id: "homevolt_bat0"
value_template: "{{ float(value_json.ems[0].bms_data[0].soc)/100 }}"
unit_of_measurement: '%'
icon: >-
mdi:battery{{
'-'~(float(value_json.ems[0].bms_data[0].soc)/100) | round(-1) | int
if (float(value_json.ems[0].bms_data[0].soc)/100) >= 10 and (float(value_json.ems[0].bms_data[0].soc)/100) <= 90
else '-outline' if (float(value_json.ems[0].bms_data[0].soc)/100) <= 10 }}
- name: "Homevolt bat1"
unique_id: "homevolt_bat1"
value_template: "{{ float(value_json.ems[0].bms_data[1].soc)/100 }}"
unit_of_measurement: '%'
icon: >-
mdi:battery{{
'-'~(float(value_json.ems[0].bms_data[1].soc)/100) | round(-1) | int
if (float(value_json.ems[0].bms_data[1].soc)/100) >= 10 and (float(value_json.ems[0].bms_data[1].soc)/100) <= 90
else '-outline' if (float(value_json.ems[0].bms_data[1].soc)/100) <= 10 }}
- name: "Homevolt bat0 laddningar"
unique_id: "homevolt_bat0_cycle"
value_template: "{{ value_json.ems[0].bms_data[0].cycle_count }}"
icon: "mdi:battery"
- name: "Homevolt bat1 laddningar"
unique_id: "homevolt_bat1_cycle"
value_template: "{{ value_json.ems[0].bms_data[1].cycle_count }}"
icon: "mdi:battery"
# Pulse CT
- name: "Homevolt nÀteffekt"
unique_id: "homevolt_grid_power"
value_template: "{{ value_json.sensors[0].total_power }}"
unit_of_measurement: 'W'
icon: "mdi:battery-negative"
device_class: power
state_class: measurement
json_attributes_path: "$.sensors[0]"
json_attributes:
- phase
- name: "Homevolt nÀt konsumerat"
unique_id: "homevolt_grid_consumed"
value_template: "{{ value_json.sensors[0].energy_imported }}"
unit_of_measurement: 'kWh'
icon: "mdi:battery-negative"
device_class: energy
state_class: total
- name: "Homevolt nÀt producerat"
unique_id: "homevolt_grid_produced"
value_template: "{{ value_json.sensors[0].energy_exported }}"
unit_of_measurement: 'kWh'
icon: "mdi:battery-positive"
device_class: energy
state_class: total
- name: "Homevolt solcell effekt"
unique_id: "homevolt_solar_power"
value_template: "{{ value_json.sensors[1].total_power }}"
unit_of_measurement: 'W'
icon: "mdi:battery-positive"
device_class: power
state_class: measurement
json_attributes_path: "$.sensors[1]"
json_attributes:
- phase
- name: "Homevolt solcell konsumerat"
unique_id: "homevolt_solar_consumed"
value_template: "{{ value_json.sensors[1].energy_imported }}"
unit_of_measurement: 'kWh'
icon: "mdi:battery-negative"
device_class: energy
state_class: total
- name: "Homevolt solcell producerat"
unique_id: "homevolt_solar_produced"
value_template: "{{ value_json.sensors[1].energy_exported }}"
unit_of_measurement: 'kWh'
icon: "mdi:battery-positive"
device_class: energy
state_class: total
- name: "Homevolt hushÄlleffekt"
unique_id: "homevolt_load_power"
value_template: "{{ value_json.sensors[2].total_power }}"
unit_of_measurement: 'W'
icon: "mdi:battery-negative"
device_class: power
state_class: measurement
json_attributes_path: "$.sensors.[2]"
json_attributes:
- phase
- name: "Homevolt batteri konsumerat"
unique_id: "homevolt_bat_consumed"
value_template: "{{ value_json.sensors[2].energy_imported }}"
unit_of_measurement: 'kWh'
icon: "mdi:battery-negative"
device_class: energy
state_class: total
- name: "Homevolt batteri producerat"
unique_id: "homevolt_bat_produced"
value_template: "{{ value_json.sensors[2].energy_exported }}"
unit_of_measurement: 'kWh'
icon: "mdi:battery-positive"
device_class: energy
state_class: total
- resource: !secret homevolt_schedule
username: "admin"
password: !secret homevolt_pass
verify_ssl: false
scan_interval: 1800
sensor:
- name: "Homevolt schema"
unique_id: "homevolt_schem"
value_template: >-
{{ (value_json.schedule | rejectattr('from', '>', (now().timestamp())) | rejectattr('to', '<', (now().timestamp())) | map(attribute='type') |
first |
replace('1', 'Ladda, uttag:') | replace('3', 'VĂ€nta') | replace('4', 'NĂ€t urladdning ') | replace('2', 'Urladdning ') | replace('5', 'NĂ€t Laddning/urladdning ')) if 'schedule' in value_json
}} {{ (value_json.schedule | rejectattr('from', '>', (now().timestamp())) | rejectattr('to', '<', (now().timestamp())) | map(attribute='params.setpoint') | first) ~'W' if 'schedule' in value_json and
(value_json.schedule | rejectattr('from', '>', (now().timestamp())) | rejectattr('to', '<', (now().timestamp())) | map(attribute='params.setpoint') | first) > 0
}}
icon: >-
{% set type = (value_json.schedule | rejectattr('from', '>', (now().timestamp())) | rejectattr('to', '<', (now().timestamp())) | map(attribute='type') | first) %}
{{ 'mdi:battery-positive' if type == 1 }}
{{ 'mdi:battery-negative' if type == 2 or type == 4 }}
{{ 'mdi:battery-clock-outline' if type == 3 }}
json_attributes:
- local_mode
- schedule
- schedule_id
- name: "Homevolt schema nÀsta"
unique_id: "homevolt_schem_next"
value_template: >-
{{ as_datetime(float(value_json.schedule[1].from,0)).strftime('%H:%M') if 'schedule' in value_json
}} {{ (value_json.schedule[1].type |
replace('1', 'Ladda, uttag:') | replace('3', 'VĂ€nta') | replace('4', 'NĂ€t urladdning ') | replace('2', 'Urladdning ') | replace('5', 'NĂ€t Laddning/urladdning ')) if 'schedule' in value_json
}}{{ (value_json.schedule[1].params.setpoint ) ~'W' if 'schedule' in value_json and 'setpoint' in value_json.schedule[1].params
}}
icon: "mdi:calendar-clock-outline"
# ------------------------------------------------ #
# Command line integration
# used to fetch json array
command_line:
- sensor:
name: "Homevolt logs"
unique_id: "homevolt_logs"
scan_interval: 600
icon: "mdi:text"
# password in curl
command: !secret homevolt_logs_curl
value_template: >-
Error: {{ value_json.logs | selectattr('level','eq', 'error') | list | count }},
Warning: {{ value_json.logs | selectattr('level','eq', 'warning') | list | count }},
Info: {{ value_json.logs| selectattr('level','eq', 'info') | list | count }},
Total: {{ value_json.logs | length if value_json is defined }}
json_attributes:
- logs
- sensor:
name: "Homevolt parametrar"
unique_id: "homevolt_param"
scan_interval: 7200
icon: "mdi:console-line"
# password in curl
command: !secret homevolt_params_curl
value_template: >-
{{ value_json.params | length if value_json is defined }}
json_attributes:
- params
- sensor:
name: "Homevolt errors"
unique_id: "homevolt_errors"
scan_interval: 600
icon: "mdi:battery-alert-variant-outline"
command: !secret homevolt_error_curl
value_template: >-
{{ (value_json.errors |
rejectattr('message','in',
['','Throttled','idle','up2date','Rev:1 (435 mV)','Protocol version: 5']) |
rejectattr('message','contains', 'OK') |
rejectattr('message','contains', 'online') |
rejectattr('message','contains', 'No ') |
rejectattr('message','contains', ' 100.00%') |
rejectattr('message','contains', 'RSSI ') |
rejectattr('message','contains', ' valid') |
rejectattr('message','contains', ' available') |
map(attribute='message') | list | join(', '))[:255]
if value_json is defined }}
json_attributes:
- errors
- sensor:
name: "Homevolt console"
unique_id: "homevolt_console"
scan_interval: 2592000
icon: "mdi:console"
command: !secret homevolt_console_curl
value_template: >-
{{ value_json.result[:255] }}
json_attributes:
- result
# ------------------------------------------------ #
# Template integration
template:
- sensor:
- name: "Homevolt intÀkt momentant"
unique_id: "homevolt_income"
unit_of_measurement: "SEK"
state: >-
{{ float(states('sensor.nord_pool_se3_aktuellt_pris'), 0) * (float(states('sensor.homevolt_effekt'), 0)/1000) | round(2) }}
device_class: monetary
icon: "mdi:cash"
- name: "Homevolt nÀt L1"
unique_id: "homevolt_grid_l1"
unit_of_measurement: "A"
state: "{{ float(state_attr('sensor.homevolt_nateffekt', 'phase')[0].amp, 0) }}"
device_class: current
state_class: measurement
icon: "mdi:current-ac"
attributes:
power: "{{ float(state_attr('sensor.homevolt_nateffekt', 'phase')[0].power,0) }}"
volt: "{{ float(state_attr('sensor.homevolt_nateffekt', 'phase')[0].voltage,0) }}"
- name: "Homevolt nÀt L2"
unique_id: "homevolt_grid_l2"
unit_of_measurement: "A"
state: "{{ float(state_attr('sensor.homevolt_nateffekt', 'phase')[1].amp, 0) }}"
device_class: current
state_class: measurement
icon: "mdi:current-ac"
attributes:
power: "{{ float(state_attr('sensor.homevolt_nateffekt', 'phase')[1].power,0) }}"
volt: "{{ float(state_attr('sensor.homevolt_nateffekt', 'phase')[1].voltage,0) }}"
- name: "Homevolt nÀt L3"
unique_id: "homevolt_grid_l3"
unit_of_measurement: "A"
state: "{{ float(state_attr('sensor.homevolt_nateffekt', 'phase')[2].amp, 0) }}"
device_class: current
state_class: measurement
icon: "mdi:current-ac"
attributes:
power: "{{ float(state_attr('sensor.homevolt_nateffekt', 'phase')[2].power,0) }}"
volt: "{{ float(state_attr('sensor.homevolt_nateffekt', 'phase')[2].voltage,0) }}"
- trigger:
- platform: time_pattern
hours: "/1"
sensor:
name: "Homevolt Äterbetalning"
unique_id: "homevolt_refund_automation"
unit_of_measurement: "SEK"
state: >-
{{ float(states('sensor.homevolt_intakt'),0) +
float(state_attr(this.entity_id, 'gridrewards_per_dygn') if 'gridrewards_per_dygn' in this.attributes else 0 ,0) *
int((as_timestamp(now()) - as_timestamp(state_attr(this.entity_id, 'montage_datum') if 'montage_datum' in this.attributes else now()) )/60/60/24, 0) |
round(0) }}
device_class: monetary
icon: "mdi:cash"
attributes:
kostnad_batteri: !secret homevolt_pris
montage_datum: !secret homevolt_montage
gridrewards_per_dygn: 18
sparat_nyttjande: "{{ float(states('sensor.homevolt_intakt'),0) }}"
gridrewards_total: "{{ float(this.attributes.gridrewards_per_dygn if 'gridrewards_per_dygn' in this.attributes else 0,0)* int((as_timestamp(now()) - as_timestamp(this.attributes.montage_datum if 'montage_datum' in this.attributes else now()))/60/60/24,0) }}"
beraknad_ater_days: >-
{% set per_day = (int(this.state, 0) / int((as_timestamp(now()) - int(as_timestamp(this.attributes.montage_datum if 'montage_datum' in this.attributes else now())))/60/60/24, 0)) %}
{{ int((int(this.attributes.kostnad_batteri if 'kostnad_batteri' in this.attributes else 0,0) - (int(this.state,0))) / per_day, 0) }}
beraknad_ater: "{{ (int(this.attributes.beraknad_ater_days if 'beraknad_ater_days' in this.attributes else 0,0) * (24*60*60) + as_timestamp(now())) | timestamp_custom('%Y-%m-%d', True) }}"
# ------------------------------------------------ #
# Sensor integration
sensor:
- platform: integration
unique_id: "homevolt_income_moment"
source: sensor.homevolt_intakt_momentant
name: Homevolt intÀkt
unit_time: h
method: left
round: 2
utility_meter:
yearly_earning:
source: sensor.homevolt_intakt
name: "Homevolt intÀkt Är"
unique_id: "homevolt_income_yearly"
cycle: yearly
net_consumption: true
monthly_earning:
source: sensor.homevolt_intakt
name: "Homevolt intÀkt mÄnad"
unique_id: "homevolt_income_monthley"
cycle: monthly
net_consumption: true
# Input for cmd
input_text:
homevolt_cmd:
name: Homevolt cmd input
initial: time uptime
# ------------------------------------------------ #
# Automation integration
automation:
- alias: Homevolt uppdatera schema varje timme
id: "homevolt_update"
description: "Uppdaterar schema sensor varje timme för att fÄ senaste schema | homevolt.yaml"
trigger:
- platform: time_pattern
minutes: 1
action:
- action: homeassistant.update_entity
data:
entity_id:
- sensor.homevolt_schema
- alias: Homevolt uppdatera console
id: "homevolt_update_console"
description: "Uppdaterar console-frÄga | homevolt.yaml"
trigger:
- platform: state
entity_id: input_text.homevolt_cmd
for: "00:00:06"
action:
- action: homeassistant.update_entity
data:
entity_id:
- sensor.homevolt_console