Integrating Smartfox energy manager EM2 in Home Assistant

The objective is to read and control the Smartfox energy manager with Home Assistant. I am using it in combination with a wall charger for surplus charging of an electric vehicle.

The communication with the device acts via Modbus TCP. You find a table of modbus registers on:
https://smartfox.at/wp-content/uploads/2022/12/Modbus-Register-SMARTFOX-Pro-SMARTFOX-Pro-2-v22e-00.01.03.10.xlsx

First assign a static IP address to the Smartfox device. Home Assistant must be in the same network/ LAN as the Smartfox device.

Maybe you need to add the modbus integration on Home Assistant.

Add the following lines to your configuration.yaml an replace the IP address host: with your IP of the smartfox device:

modbus:
  - name: "smartfox"
    type: tcp
    host: 192.168.0.4
    port: 502
    timeout: 5
    delay: 5
    sensors:
      - name: "Energy from grid"
        unique_id: smartfox.energy_from_grid
        unit_of_measurement: Wh
        data_type: uint64
        input_type: holding
        slave: 1
        address: 40999
        scan_interval: 100    
      - name: "Energy into grid"
        unique_id: smartfox.energy_into_grid
        unit_of_measurement: Wh
        data_type: uint64
        input_type: holding
        slave: 1
        address: 41003
        scan_interval: 100
      - name: "Energy smartfox"
        unique_id: smartfox.energy_smartfox
        unit_of_measurement: Wh
        data_type: uint64
        input_type: holding
        slave: 1
        address: 41007
        scan_interval: 100
      - name: "Day Energy from grid"
        unique_id: smartfox.day_energy_from_grid
        unit_of_measurement: Wh
        data_type: uint32
        input_type: holding
        slave: 1
        address: 41011
        scan_interval: 100
      - name: "Day Energy into grid"
        unique_id: smartfox.day_energy_into_grid
        unit_of_measurement: Wh
        data_type: uint32
        input_type: holding
        slave: 1
        address: 41013
        scan_interval: 100
      - name: "Day Energy Smartfox"
        unique_id: smartfox.day_energy_smartfox
        unit_of_measurement: Wh
        data_type: uint32
        input_type: holding
        slave: 1
        address: 41015
        scan_interval: 100
      - name: "Power total"
        unique_id: smartfox.power_total
        unit_of_measurement: W
        data_type: int32
        input_type: holding
        slave: 1
        address: 41017
        scan_interval: 100
      - name: "Car charge energy total"
        unique_id: smartfox.car_charge_1_energy_total
        unit_of_measurement: Wh
        data_type: uint64
        input_type: holding
        slave: 1
        address: 41599
        scan_interval: 100
      - name: "Car charge energy pres"
        unique_id: smartfox.car_charge_1_energy_pres
        unit_of_measurement: Wh
        data_type: uint32
        input_type: holding
        slave: 1
        address: 41603
        scan_interval: 100
      - name: "Car charge power"
        unique_id: smartfox.car_charge_1_power
        unit_of_measurement: W
        data_type: uint32
        input_type: holding
        slave: 1
        address: 41605
        scan_interval: 100
      - name: "Car charge man. charging value"
        unique_id: smartfox.car_charge_1_man_charging_value
        unit_of_measurement: "%"
        data_type: uint16
        input_type: holding
        slave: 1
        address: 41608
        scan_interval: 100
    switches:
      - name: "Car charge mode (Ein = Man.)"
        unique_id: smartfox.car_charge_1_charge_mode
        write_type: holdings
        slave: 1
        address: 41607
        command_on: 1
        command_off: 0
        verify:
            delay: 10

With the switch you can control the charging mode (OFF = surplus, ON = force charging).
Note that there is an offset of -1 to the modbus addresses.

I added a KNX switch in Home Assistant and added automations for updating the switch status (both the KNX switch and the modbus switch updating each other). Thus it is possible to set the charging mode with an external KNX switch or a KNX touch panel. I am using Busch-SmartTouch 10 therefore.

I hope this helps someone.

Hi,

first of all, thanks a lot for your great work and the detailed instructions! :pray:
I managed to get the integration working and can see the entities in Home Assistant.

However, I can’t assign them in the Energy Dashboard – they don’t show up as selectable sources there.
Were you able to feed your Smartfox data into the Energy Dashboard as well?

Best regards

You need to add ‘device_class: energy’ in the configuration.yaml for the relevant sensors. Only entities with this device_class can be selected in the energy dashboard.

For example:

    sensors:
      - name: "Energy from grid"
        unique_id: smartfox.energy_from_grid
        unit_of_measurement: Wh
        data_type: uint64
        input_type: holding
        slave: 1
        address: 40999
        scan_interval: 100
        device_class: energy
1 Like

Hello, thank you a lot for the hint about the divice_class, unfortuned it doesnt solve my problem to get the data from the smartfox to the energy dash board. Is there anybody out there who made it happen ?

Hi everyone,

After a few hours of tinkering, I managed to get my power dashboard working by reading the values.xml file from the Smartfox Pro 2 EM3, and I’d like to share the results with you. Maybe it’ll save some of you a bit of time :slight_smile:

smartfoxrest.yaml: Adjust the resource IP!

###############################################################
# SMARTFOX – REST SENSOR DATA
###############################################################
rest:
  - resource: "http://192.168.0.254/values.xml"
    scan_interval: 15
    timeout: 5
    headers:
      Accept: "application/xml"
    sensor:

      # Netz Gesamt (positiv = Bezug; negativ = Einspeisung)
      - name: "Smartfox Leistung Netz Gesamt"
        unique_id: smartfox_leistung_netz_gesamt
        unit_of_measurement: "W"
        device_class: power
        state_class: measurement
        value_template: >
          {% set v = value | regex_findall('"@id":"detailsPowerValue","#text":"([\-0-9\.]+) W"') %}
          {{ v[0] | float(0) if v else 0 }}

      # Netzbezug (nur positive Werte)
      - name: "Smartfox Leistung nur Netzbezug"
        unique_id: smartfox_leistung_nur_netzbezug
        unit_of_measurement: "W"
        device_class: power
        state_class: measurement
        value_template: >
          {% set v = value | regex_findall('"@id":"detailsPowerValue","#text":"([\-0-9\.]+) W"') %}
          {% set p = v[0] | float(0) if v else 0 %}
          {{ p if p > 0 else 0 }}

      # Einspeisung (negative Werte → positive Leistung)
      - name: "Smartfox Leistung nur Einspeisung"
        unique_id: smartfox_leistung_nur_einspeisung
        unit_of_measurement: "W"
        device_class: power
        state_class: measurement
        value_template: >
          {% set v = value | regex_findall('"@id":"detailsPowerValue","#text":"([\-0-9\.]+) W"') %}
          {% set p = v[0] | float(0) if v else 0 %}
          {{ (p * -1) if p < 0 else 0 }}

      # PV Produktion
      - name: "Smartfox Leistung PV"
        unique_id: smartfox_leistung_pv
        unit_of_measurement: "W"
        device_class: power
        state_class: measurement
        value_template: >
          {% set v = value | regex_findall('"@id":"wr1PowerValueinW","#text":"([\-0-9\.]+) W"') %}
          {% set p = v[0] | float(0) if v else 0 %}
          {{ p if p > 0 else 0 }}

      # PV Energie Gesamt (Smartfox liefert kWh)
      - name: "Smartfox Energie PV"
        unique_id: smartfox_energie_pv
        unit_of_measurement: "kWh"
        device_class: energy
        state_class: total_increasing
        value_template: >
          {% set v = value | regex_findall('"@id":"wr1EnergyValue","#text":"([\-0-9\.]+) kWh"') %}
          {{ v[0] | float(0) if v else 0 }}

      # Tagesbezug (Wh)
      - name: "Smartfox Energie Tagesbezug"
        unique_id: smartfox_energie_tagesbezug
        unit_of_measurement: "Wh"
        device_class: energy
        state_class: total_increasing
        value_template: >
          {% set v = value | regex_findall('"@id":"eDayValue","#text":"([\-0-9\.]+) Wh"') %}
          {{ v[0] | float(0) if v else 0 }}

      # Tageseinspeisung (Wh)
      - name: "Smartfox Energie Tageseinspeisung"
        unique_id: smartfox_energie_tageseinspeisung
        unit_of_measurement: "Wh"
        device_class: energy
        state_class: total_increasing
        value_template: >
          {% set v = value | regex_findall('"@id":"eDayToGridValue","#text":"([\-0-9\.]+) Wh"') %}
          {{ v[0] | float(0) if v else 0 }}

      # Tagesproduktion (Wh)
      - name: "Smartfox Energie Tagesproduktion"
        unique_id: smartfox_energie_tagesproduktion
        unit_of_measurement: "Wh"
        device_class: energy
        state_class: total_increasing
        value_template: >
          {% set v = value | regex_findall('"@id":"hidWr1EnergyDay","#text":"([\-0-9\.]+)"') %}
          {{ v[0] | float(0) if v else 0 }}


###############################################################
# TEMPLATE-SENSOREN (ALLE IN EINEM BLOCK!)
###############################################################
template:
  - sensor:

      # Hausverbrauch = PV + Netz-Gesamt
      - name: "Smartfox Leistung Hausverbrauch"
        unique_id: smartfox_leistung_hausverbrauch
        unit_of_measurement: "W"
        device_class: power
        state_class: measurement
        state: >
          {% set pv = states('sensor.smartfox_leistung_pv') | float(0) %}
          {% set grid_total = states('sensor.smartfox_leistung_netz_gesamt') | float(0) %}
          {{ pv + grid_total }}

      # Eigenverbrauch = PV - Einspeisung
      - name: "Smartfox Leistung Eigenverbrauch"
        unique_id: smartfox_leistung_eigenverbrauch
        unit_of_measurement: "W"
        device_class: power
        state_class: measurement
        state: >
          {% set pv = states('sensor.smartfox_leistung_pv') | float(0) %}
          {% set grid_out = states('sensor.smartfox_leistung_nur_einspeisung') | float(0) %}
          {{ pv - grid_out }}

      # Autarkiegrad = Eigenverbrauch / Hausverbrauch * 100
      - name: "Smartfox Autarkiegrad"
        unique_id: smartfox_autarkiegrad
        unit_of_measurement: "%"
        state: >
          {% set haus = states('sensor.smartfox_leistung_hausverbrauch') | float(0) %}
          {% set eigen = states('sensor.smartfox_leistung_eigenverbrauch') | float(0) %}
          {% if haus > 0 %}
            {{ (eigen / haus * 100) | round(1) }}
          {% else %}
            0
          {% endif %}

      # Hausverbrauchsquote = Hausverbrauch / PV * 100 oder 100% wenn Hausverbrauch >= PV
      - name: "Smartfox Hausverbrauchsquote"
        unique_id: smartfox_hausverbrauchsquote
        unit_of_measurement: "%"
        state: >
          {% set pv = states('sensor.smartfox_leistung_pv') | float(0) %}
          {% set haus = states('sensor.smartfox_leistung_hausverbrauch') | float(0) %}

          {% if pv <= 0 %}
            0
          {% elif haus >= pv %}
            100
          {% else %}
            {{ (haus / pv * 100) | round(1) }}
          {% endif %}

      # Eigenverbrauchsquote = Eigenverbrauch / PV * 100
      - name: "Smartfox Eigenverbrauchsquote"
        unique_id: smartfox_eigenverbrauchsquote
        unit_of_measurement: "%"
        state: >
          {% set pv = states('sensor.smartfox_leistung_pv') | float(0) %}
          {% set eigen = states('sensor.smartfox_leistung_eigenverbrauch') | float(0) %}
          {% if pv > 0 %}
            {{ (eigen / pv * 100) | round(1) }}
          {% else %}
            0
          {% endif %}
 

Dashboard YAML

title: Smartfox Energie
views:
  - title: Übersicht
    icon: mdi:solar-power
    cards:
      - type: gauge
        name: PV Produktion
        entity: sensor.smartfox_leistung_pv
        min: 0
        max: 6500
        needle: true
        severity:
          green: 0
          yellow: 6000
          red: 6300
      - type: gauge
        entity: sensor.smartfox_hausverbrauchsquote
        needle: true
        max: 100
        min: 0
        severity:
          green: 10
          yellow: 5
          red: 0
        name: Hausverbrauchsquote
      - type: gauge
        name: Einspeisung
        entity: sensor.smartfox_leistung_nur_einspeisung_2
        min: 0
        max: 6500
        needle: false
      - type: gauge
        entity: sensor.smartfox_leistung_hausverbrauch
        min: 0
        needle: false
        max: 8000
        name: Hausverbrauch
      - type: gauge
        entity: sensor.smartfox_autarkiegrad
        min: 0
        needle: true
        max: 100
        name: Autarkiegrad
        severity:
          green: 66
          yellow: 33
          red: 0
      - type: gauge
        name: Netzbezug
        entity: sensor.smartfox_leistung_nur_netzbezug_2
        min: 0
        max: 8000
        needle: false
        severity:
          green: 0
          yellow: 250
          red: 500
      - type: history-graph
        title: Leistungen (24h)
        hours_to_show: 24
        entities:
          - entity: sensor.smartfox_leistung_netz_gesamt
          - entity: sensor.smartfox_leistung_pv
        logarithmic_scale: false
    type: masonry

EDIT: I extended the sensors for daily energy statistics. Use smartfox_energie_tagesbezug and smartfox_energie_tageseinspeisung to configure the energy dashboard. With smartfox_energie_tagesproduktion the solar production can be also added.

XML reading generally works very reliably. Via Modbus, I was only able to read the total power data:

smartfox.yaml

modbus:
  - name: "smartfox"
    type: tcp
    host: 192.168.0.254
    port: 502

    sensors:
      - name: "Gesamtleistung"
        unique_id: smartfox_total_power
        unit_of_measurement: "W"
        slave: 1
        address: 41017
        data_type: int32
        input_type: holding
        device_class: power
        state_class: measurement
        scan_interval: 5

Hi everyone,

I found a way to control the SMARTFOX EV charger from Home Assistant without Modbus writes (which don’t work reliably on the EM3, and possibly EM2).

The SMARTFOX web UI uses an undocumented local HTTP CGI endpoint to switch charger modes:

GET http://<SMARTFOX-IP>/setswcc.cgi?num=0&mode=<mode>&value=<percent>

Modes:

mode Name
0 A (Surplus/Automatic)
1 M (Forced charging)
2 A+ (Automatic+)
3 OFF
4 M+

value = charging power in % (0–100), relevant for modes 1 and 4.

No authentication required — just a plain GET request.

Home Assistant Setup

configuration.yaml:

rest_command:
  smartfox_charger_mode:
    url: "http://<SMARTFOX-IP>/setswcc.cgi?num=0&mode={{ mode }}&value={{ value }}"
    method: GET

Note: requires HA restart (rest_command doesn’t support YAML reload).

Example automation — force charge at night if SoC < 70%:

- id: smartfox_ev_force_charge
  alias: "SMARTFOX: Force charge when below 70%"
  triggers:
    - trigger: time
      at: "00:00:00"
    - trigger: time
      at: "01:00:00"
    - trigger: time
      at: "02:00:00"
    - trigger: time
      at: "03:00:00"
    - trigger: time
      at: "04:00:00"
    - trigger: time
      at: "05:00:00"
  conditions:
    - condition: numeric_state
      entity_id: sensor.audi_e_tron_state_of_charge
      below: 70
  actions:
    - action: rest_command.smartfox_charger_mode
      data:
        mode: "1"
        value: "100"

Switch back to surplus charging when SoC >= 70%:

- id: smartfox_ev_surplus_charge
  alias: "SMARTFOX: Surplus charging above 70%"
  triggers:
    - trigger: numeric_state
      entity_id: sensor.audi_e_tron_state_of_charge
      above: 69
  actions:
    - action: rest_command.smartfox_charger_mode
      data:
        mode: "3"
        value: "0"
    - delay:
        seconds: 5
    - action: rest_command.smartfox_charger_mode
      data:
        mode: "0"
        value: "100"

Tip: When switching from forced charging (M) to automatic (A), stop charging first (mode=3/OFF), wait a few seconds, then switch to automatic — otherwise charging may continue from the grid.

How I found this

I analyzed the minified JavaScript of the SMARTFOX web UI. The hideDeviceModal() function calls sendCommand(deviceModalCommand), which sends a GET XMLHttpRequest. The charger mode buttons set deviceModalCommand = 'setswcc.cgi?num=...'.

Why Modbus writes don’t work

On the EM3 (firmware 00.01.13.10):

  • Function Code 6 (Write Single Register) is rejected entirely
  • Function Code 16 (Write Multiple Registers) is accepted but values are immediately reset by the internal controller (~200ms)
  • The official Modbus register table is for Pro/Pro 2, not EM3

Other CGI endpoints (not tested for write)

  • setswaout.cgi — analog output (boiler) control
  • setswrel.cgi — relay control
  • setvb.cgi — consumption controller

Tested on: SMARTFOX EM3, firmware 00.01.13.10, with SMARTFOX Pro Charger (RS485).

Hope this helps others!