Skip to content

Instantly share code, notes, and snippets.

@danielolsson100
Last active August 20, 2025 05:17
Show Gist options
  • Save danielolsson100/f20cb9a01c11b9ea5850ccc4bff8d0c5 to your computer and use it in GitHub Desktop.
Save danielolsson100/f20cb9a01c11b9ea5850ccc4bff8d0c5 to your computer and use it in GitHub Desktop.
Ferroamp Modbus TCP
Home Asssistant Ferroamp Modbus TCP
Ferroamp support needs to enable Modbus TCP for this to work
# Cred: Robin Östlund for the mapping
# Ref: https://ferroamp.com/wp-content/uploads/2023/04/Ferroamp-Modbus-TCP-Specification-RevD-2.pdf
configuration.yaml
-------------------------------------
modbus:
- name: ferroamp_modbus
type: tcp
host: 192.168.x.x
port: 502
delay: 5
message_wait_milliseconds: 30
timeout: 5
binary_sensors:
# Grid Power Data
- name: FMB Limit Import System Value
address: 8000
scan_interval: 30
slave: 1
input_type: input
- name: FMB Limit Export System Value
address: 8010
scan_interval: 30
slave: 1
input_type: input
sensors:
## Energy Hub - General Data
- name: FMB Modbus Major Version 1
address: 1004
data_type: uint16
scan_interval: 30
state_class: measurement
slave: 1
input_type: input
- name: FMB Modbus Major Version 2
address: 1008
data_type: uint16
scan_interval: 30
state_class: measurement
slave: 1
input_type: input
## Energy Hub Inverter Data
- name: FMB Inverter Status
address: 2000
data_type: uint16
scan_interval: 30
state_class: measurement
device_class: enum
slave: 1
input_type: input
- name: FMB Grid Frequency
address: 2016
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: Hz
state_class: measurement
device_class: frequency
slave: 1
input_type: input
- name: FMB Grid Voltage L1
address: 2032
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: V
state_class: measurement
device_class: voltage
slave: 1
input_type: input
- name: FMB Grid Voltage L2
address: 2036
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: V
state_class: measurement
device_class: voltage
slave: 1
input_type: input
- name: FMB Grid Voltage L3
address: 2040
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: V
state_class: measurement
device_class: voltage
slave: 1
input_type: input
- name: FMB Energy To DC-Nanogrid
address: 2064
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: kWh
state_class: total_increasing
device_class: energy
slave: 1
input_type: input
- name: FMB Energy From DC-Nanogrid
address: 2068
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: kWh
state_class: total_increasing
device_class: energy
slave: 1
input_type: input
- name: FMB Inverter Active Power
address: 2100
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: kW
state_class: measurement
device_class: power
slave: 1
input_type: input
- name: FMB Inverter Reactive Power
address: 2104
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: kvar
state_class: measurement
device_class: reactive_power
slave: 1
input_type: input
- name: FMB Inverter Apparent Power
address: 2108
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: kVa
state_class: measurement
device_class: apparent_power
slave: 1
input_type: input
- name: FMB Inverter Active Current L1
address: 2112
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: A
state_class: measurement
device_class: current
slave: 1
input_type: input
- name: FMB Inverter Active Current L2
address: 2116
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: A
state_class: measurement
device_class: current
slave: 1
input_type: input
- name: FMB Inverter Active Current L3
address: 2120
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: A
state_class: measurement
device_class: current
slave: 1
input_type: input
- name: FMB Inverter Reactive Current L1
address: 2124
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: A
state_class: measurement
device_class: current
slave: 1
input_type: input
- name: FMB Inverter Reactive Current L2
address: 2128
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: A
state_class: measurement
device_class: current
slave: 1
input_type: input
- name: FMB Inverter Reactive Current L3
address: 2132
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: A
state_class: measurement
device_class: current
slave: 1
input_type: input
- name: FMB Inverter RMS Current L1
address: 2136
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: A
state_class: measurement
device_class: current
slave: 1
input_type: input
- name: FMB Inverter RMS Current L2
address: 2140
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: A
state_class: measurement
device_class: current
slave: 1
input_type: input
- name: FMB Inverter RMS Current L3
address: 2144
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: A
state_class: measurement
device_class: current
slave: 1
input_type: input
## Energyhub facility Data
- name: FMB Energy Exported To Grid
address: 3064
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: kWh
# state_class: measurement
state_class: total_increasing
device_class: energy
slave: 1
input_type: input
- name: FMB Energy Imported To Grid
address: 3068
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: kWh
# state_class: measurement
state_class: total_increasing
device_class: energy
slave: 1
input_type: input
- name: FMB Grid Active Power
address: 3100
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: kW
state_class: measurement
device_class: power
slave: 1
input_type: input
- name: FMB Grid Reactive Power
address: 3104
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: kVAr
state_class: measurement
device_class: reactive_power
slave: 1
input_type: input
- name: FMB Grid Apparent Power
address: 3108
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: kVA
state_class: measurement
device_class: apparent_power
slave: 1
input_type: input
- name: FMB Grid Active Current L1
address: 3112
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: A
state_class: measurement
device_class: current
slave: 1
input_type: input
- name: FMB Grid Active Current L2
address: 3116
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: A
state_class: measurement
device_class: current
slave: 1
input_type: input
- name: FMB Grid Active Current L3
address: 3120
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: A
state_class: measurement
device_class: current
slave: 1
input_type: input
- name: FMB Grid Reactive Current L1
address: 3124
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: A
state_class: measurement
device_class: current
slave: 1
input_type: input
- name: FMB Grid Reactive Current L2
address: 3128
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: A
state_class: measurement
device_class: current
slave: 1
input_type: input
- name: FMB Grid Reactive Current L3
address: 3132
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: A
state_class: measurement
device_class: current
slave: 1
input_type: input
- name: FMB Grid RMS Current L1
address: 3136
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: A
state_class: measurement
device_class: current
slave: 1
input_type: input
- name: FMB Grid RMS Current L2
address: 3140
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: A
state_class: measurement
device_class: current
slave: 1
input_type: input
- name: FMB Grid RMS Current L3
address: 3144
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: A
state_class: measurement
device_class: current
slave: 1
input_type: input
## PV Data
- name: FMB Number Of Idle SSOs
address: 5000
data_type: uint16
scan_interval: 30
state_class: measurement
slave: 1
input_type: input
- name: FMB Number Of Running SSOs
address: 5002
data_type: uint16
scan_interval: 30
state_class: measurement
slave: 1
input_type: input
- name: FMB Number Of Faulty SSOs
address: 5004
data_type: uint16
scan_interval: 30
state_class: measurement
slave: 1
input_type: input
- name: FMB Energy Produced
address: 5064
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: kWh
# state_class: measurement
state_class: total_increasing
device_class: energy
slave: 1
input_type: input
- name: FMB Solar Power
address: 5100
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: kW
state_class: measurement
device_class: power
slave: 1
input_type: input
## Battery Control
- name: FMB Battery Mode
address: 6000
data_type: uint16
scan_interval: 60
state_class: measurement
device_class: enum
slave: 1
input_type: holding
- name: FMB Battery Power Reference
address: 6064
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: kW
state_class: measurement
device_class: power
slave: 1
input_type: holding
## Battery Data
- name: FMB Number Of Idle Batteries
address: 6000
data_type: uint16
scan_interval: 30
state_class: measurement
slave: 1
input_type: input
- name: FMB Number Of Running Batteries
address: 6002
data_type: uint16
scan_interval: 30
state_class: measurement
slave: 1
input_type: input
- name: FMB Number Of Faulty Batteries
#address: 6068
address: 6004
data_type: uint16
scan_interval: 30
state_class: measurement
slave: 1
input_type: input
- name: FMB Rated Capacity
address: 6008
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: kWh
state_class: measurement
device_class: energy_storage
slave: 1
input_type: input
- name: FMB State Of Health
address: 6012
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: "%"
state_class: measurement
slave: 1
input_type: input
- name: FMB State Of Charge
address: 6016
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: "%"
state_class: measurement
device_class: battery
slave: 1
input_type: input
- name: FMB Energy From Battery
address: 6064
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: kWh
# state_class: measurement
state_class: total_increasing
device_class: energy
slave: 1
input_type: input
- name: FMB Energy To Battery
address: 6068
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: kWh
# state_class: measurement
state_class: total_increasing
device_class: energy
slave: 1
input_type: input
- name: FMB Battery Power
address: 6100
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: kW
state_class: measurement
device_class: power
slave: 1
input_type: input
- name: FMB Battery Mode System Value
address: 6104
data_type: uint16
scan_interval: 30
state_class: measurement
device_class: enum
slave: 1
input_type: input
- name: FMB Battery Power Reference System Value
address: 6106
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: kW
state_class: measurement
# device_class: energy
device_class: power
slave: 1
input_type: input
## Grid Power Control
# TODO
## Grid Power Data
- name: FMB Import Threshold System Value
address: 8002
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: W
device_class: power
state_class: measurement
slave: 1
input_type: input
unique_id: fmb_import_threshold_system_value
- name: FMB Export Threshold System Value
address: 8012
data_type: float32
swap: word
scan_interval: 30
unit_of_measurement: W
device_class: power
state_class: measurement
slave: 1
input_type: input
unique_id: fmb_export_threshold_system_value
template:
- number:
- name: FMB Battery Control
state: "{{ float(states('sensor.fmb_battery_power_reference'), 0) * 1000 }}"
availability: "{{ is_number(states('sensor.fmb_battery_power_reference')) }}"
unique_id: fmb_battery_control
set_value:
# set battery power reference
- action: modbus.write_register
data_template:
hub: ferroamp_modbus
address: 6064
slave: 1
value: >
{% set value = (value | float(0) / 1000) %}
{% set packed_value = pack(value, ">f") %}
{% set high_word = unpack(packed_value, ">H", offset=2) | abs %}
{% set low_word = unpack(packed_value, ">H") | abs %}
[ {{ high_word }}, {{ low_word }} ]
# set battery to power mode
- action: modbus.write_register
data_template:
hub: ferroamp_modbus
address: 6000
slave: 1
value: >-
{% if value == 0 %} 0
{% else %} 1
{% endif %}
# value:
# - 1
step: 1
min: -30000
max: 30000
- name: FMB Import Threshold
state: "{{ states('sensor.fmb_import_threshold_system_value') }}"
availability: "{{ is_number(states('sensor.fmb_import_threshold_system_value')) }}"
unique_id: fmb_import_threshold
set_value:
# set import threshold
- action: modbus.write_register
data_template:
hub: ferroamp_modbus
address: 8002
slave: 1
value: >
{% set value = value | float(0) %}
{% set packed_value = pack(value, ">f") %}
{% set high_word = unpack(packed_value, ">H", offset=2) | abs %}
{% set low_word = unpack(packed_value, ">H") | abs %}
[ {{ high_word }}, {{ low_word }} ]
# apply import settings
- action: modbus.write_register
data_template:
hub: ferroamp_modbus
address: 8006
slave: 1
value:
- 1
step: 1
min: 0
max: 11000
- name: FMB Export Threshold
state: "{{ states('sensor.fmb_export_threshold_system_value') }}"
availability: "{{ is_number(states('sensor.fmb_export_threshold_system_value')) }}"
unique_id: fmb_export_threshold
set_value:
# set import threshold
- action: modbus.write_register
data_template:
hub: ferroamp_modbus
address: 8012
slave: 1
value: >
{% set value = value | float(0) %}
{% set packed_value = pack(value, ">f") %}
{% set high_word = unpack(packed_value, ">H", offset=2) | abs %}
{% set low_word = unpack(packed_value, ">H") | abs %}
[ {{ high_word }}, {{ low_word }} ]
# apply import settings
- action: modbus.write_register
data_template:
hub: ferroamp_modbus
address: 8016
slave: 1
value:
- 1
step: 1
min: -11000
max: 0
switch:
- platform: template
switches:
fmb_battery_mode_default:
friendly_name: FMB Battery Mode Default
value_template: "{{ is_state('sensor.fmb_battery_mode', '0') }}"
availability_template: >-
{%- if not is_state("sensor.fmb_battery_mode", "unavailable") %}
true
{%- endif %}
turn_on:
# set battery to default mode
- action: modbus.write_register
data_template:
hub: ferroamp_modbus
address: 6000
slave: 1
value: 0
turn_off:
# set battery to default mode
- action: modbus.write_register
data_template:
hub: ferroamp_modbus
address: 6000
slave: 1
value: 1
fmb_limit_import:
friendly_name: FMB Limit Import
value_template: "{{ is_state('binary_sensor.fmb_limit_import_system_value', 'on') }}"
availability_template: >-
{%- if not is_state("binary_sensor.fmb_limit_import_system_value", "unavailable") %}
true
{%- endif %}
turn_on:
# set limit import
- action: modbus.write_register
data:
hub: ferroamp_modbus
address: 8000
slave: 1
value:
- 1
# apply limit import
- action: modbus.write_register
data:
hub: ferroamp_modbus
address: 8006
slave: 1
value:
- 1
turn_off:
# set limit import
- action: modbus.write_register
data:
hub: ferroamp_modbus
address: 8000
slave: 1
value:
- 0
# apply limit import
- action: modbus.write_register
data:
hub: ferroamp_modbus
address: 8006
slave: 1
value:
- 1
fmb_limit_export:
friendly_name: FMB Limit Export
value_template: "{{ is_state('binary_sensor.fmb_limit_export_system_value', 'on') }}"
availability_template: >-
{%- if not is_state("binary_sensor.fmb_limit_export_system_value", "unavailable") %}
true
{%- endif %}
turn_on:
# set limit import
- action: modbus.write_register
data:
hub: ferroamp_modbus
address: 8010
slave: 1
value:
- 1
# apply limit import
- action: modbus.write_register
data:
hub: ferroamp_modbus
address: 8016
slave: 1
value:
- 1
turn_off:
# set limit import
- action: modbus.write_register
data:
hub: ferroamp_modbus
address: 8010
slave: 1
value:
- 0
# apply limit import
- action: modbus.write_register
data:
hub: ferroamp_modbus
address: 8016
slave: 1
value:
- 1
automation.yaml
--------------------------------------
- id: '1755326108092'
alias: FMB - Define Import Threshold
description: ''
triggers:
- entity_id:
- sensor.easee_status
trigger: state
- minutes: '0'
trigger: time_pattern
- trigger: state
entity_id:
- sensor.easee_power
conditions:
- condition: state
entity_id: sensor.ferroamp_control_status
state: auto
actions:
- if:
- condition: or
conditions:
- condition: state
entity_id: sensor.easee_status
state: charging
enabled: false
- condition: numeric_state
entity_id: sensor.easee_power
above: 1
then:
- action: input_number.set_value
metadata: {}
data:
value: 11000
target:
entity_id: input_number.import_threshold
else:
- action: input_number.set_value
metadata: {}
data:
value: 0
target:
entity_id: input_number.import_threshold
mode: single
- id: '1755327471564'
alias: FMB - Define Export Threshold
description: ''
triggers:
- entity_id:
- sensor.easee_status
trigger: state
- minutes: '0'
trigger: time_pattern
- trigger: state
entity_id:
- binary_sensor.solar_energy_low
- trigger: state
entity_id:
- binary_sensor.bs_ep_low
- trigger: state
entity_id:
- sensor.easee_power
conditions:
- condition: state
entity_id: sensor.ferroamp_control_status
state: auto
actions:
- if:
- condition: or
conditions:
- condition: state
entity_id: sensor.easee_status
state: charging
enabled: false
- condition: numeric_state
entity_id: sensor.easee_power
above: 1
then:
- action: input_number.set_value
metadata: {}
data:
value: -11000
target:
entity_id: input_number.export_threshold
else:
- if:
- condition: or
conditions:
- condition: state
entity_id: binary_sensor.solar_energy_low
state: 'on'
- condition: state
entity_id: binary_sensor.bs_ep_low
state: 'on'
then:
- action: input_number.set_value
metadata: {}
data:
value: 0
target:
entity_id: input_number.export_threshold
else:
- action: input_number.set_value
metadata: {}
data:
value: -11000
target:
entity_id: input_number.export_threshold
mode: single
- id: '1755328993471'
alias: FMB - Write register
description: ''
triggers:
- trigger: state
entity_id:
- input_number.export_threshold
- trigger: state
entity_id:
- input_number.import_threshold
for:
hours: 0
minutes: 0
seconds: 5
conditions: []
actions:
- action: modbus.write_register
metadata: {}
data:
hub: ferroamp_modbus
address: 8012
slave: 1
value: '{% set value = states(''input_number.export_threshold'') | float(0)
%} {% set packed_value = pack(value, ">f") %} {% set high_word = unpack(packed_value,
">H", offset=2) | abs %} {% set low_word = unpack(packed_value, ">H") | abs
%} [ {{ high_word }}, {{ low_word }} ]
'
- action: modbus.write_register
metadata: {}
data:
hub: ferroamp_modbus
address: 8002
slave: 1
value: '{% set value = states(''input_number.import_threshold'') | float(0)
%} {% set packed_value = pack(value, ">f") %} {% set high_word = unpack(packed_value,
">H", offset=2) | abs %} {% set low_word = unpack(packed_value, ">H") | abs
%} [ {{ high_word }}, {{ low_word }} ]
'
- action: modbus.write_register
metadata: {}
data:
hub: ferroamp_modbus
address: 8016
slave: 1
value: 1
- delay:
hours: 0
minutes: 0
seconds: 5
milliseconds: 0
- action: modbus.write_register
metadata: {}
data:
hub: ferroamp_modbus
address: 8006
slave: 1
value: 1
mode: single
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment