I just wanted to put this modbus yaml config somewhere, in hope it will save some time and frustration.
This is tested on a EFOY 2800 methanol fuel cell, but I guess it will work with any of the 900/1800/2800 series cells.
The config is based on sensors I found interesting in these manuals: EFOY MODBUS TCP - Pro 900/1800/2800 : Support Centre but it’s only a fraction of the information you can get from the system.
- name: efoy
type: tcp
host: aaa.bbb.ccc.ddd #Replace with the IP address of your cell
port: 502
delay: 5
message_wait_milliseconds: 100
timeout: 5
binary_sensors:
- name: "CurrentErrorActive"
unique_id: "efoy.CurrentErrorActive"
address: 2
scan_interval: 10
input_type: discrete_input
device_class: problem
- name: "CurrentWarningActive"
unique_id: "efoy.CurrentWarningActive"
address: 3
scan_interval: 10
input_type: discrete_input
device_class: problem
- name: "FuelBelow25"
unique_id: "efoy.fuelBelow25"
address: 12
scan_interval: 30
input_type: discrete_input
device_class: battery
- name: "FMport1active"
unique_id: "efoy.FMport1active"
address: 28
scan_interval: 30
input_type: discrete_input
- name: "FMport2active"
unique_id: "efoy.FMport2active"
address: 29
scan_interval: 30
input_type: discrete_input
sensors:
# Take note of this really important piece of information from the EFOY manuals:
# "The byte ordering for a 16-bit word is Big-endian.
# The word order is Little-endian for all 32bit/64bit values."
# That is the reason all 'float32' sensors have the line 'swap: byte' in them.
# It took me a while to figure that out :)
- name: "LogPOut"
unique_id: "efoy.LogPOut"
data_type: float32
swap: word
device_class: power
scan_interval: 10
address: 20
input_type: input
unit_of_measurement: "W"
- name: "LogUBat"
unique_id: "efoy.LogUBat"
data_type: float32
swap: word
device_class: voltage
scan_interval: 10
address: 22
input_type: input
unit_of_measurement: "V"
- name: "LogTAmb"
unique_id: "efoy.LogTAmb"
data_type: float32
swap: word
device_class: temperature
scan_interval: 10
address: 24
input_type: input
unit_of_measurement: "°C"
- name: "CurrentErrorCode"
unique_id: "efoy.CurrentErrorCode"
data_type: int16
scan_interval: 10
address: 31
input_type: input
- name: "CurrentErrorCodeMinor"
unique_id: "efoy.CurrentErrorCodeMinor"
data_type: int16
scan_interval: 10
address: 32
input_type: input
- name: "LastErrorCode"
unique_id: "efoy.LastErrorCode"
data_type: int16
scan_interval: 10
address: 33
input_type: input
- name: "LastErrorCodeMinor"
unique_id: "efoy.LastErrorCodeMinor"
data_type: int16
scan_interval: 10
address: 34
input_type: input
- name: "CurrentWarningCode"
unique_id: "efoy.CurrentWarningCode"
data_type: int16
scan_interval: 10
address: 35
input_type: input
- name: "CurrentWarningCodeMinor"
unique_id: "efoy.CurrentWarningCodeMinor"
data_type: int16
scan_interval: 10
address: 36
input_type: input
- name: "SystemStateEnum"
unique_id: "efoy.SystemStateEnum"
device_class: enum
data_type: int16
scan_interval: 10
address: 39
input_type: input
- name: "OperatingModeEnum"
unique_id: "efoy.OperatingModeEnum"
device_class: enum
data_type: int16
scan_interval: 10
address: 40
input_type: input
- name: "LogStackOpTime"
unique_id: "efoy.LogStackOpTime"
data_type: float32
swap: word
device_class: duration
scan_interval: 600
address: 270
input_type: input
- name: "LogpAmb"
unique_id: "efoy.LogpAmb"
data_type: float32
swap: word
device_class: atmospheric_pressure
scan_interval: 10
address: 295
input_type: input
unit_of_measurement: "hPa"
- name: "LogRH"
unique_id: "efoy.LogRH"
data_type: float32
swap: word
device_class: humidity
scan_interval: 10
address: 297
input_type: input
unit_of_measurement: "%"
- name: "LogTStack"
unique_id: "efoy.LogTStack"
data_type: float32
swap: word
device_class: temperature
scan_interval: 10
address: 287
input_type: input
unit_of_measurement: "°C"
- name: "LogTHE"
unique_id: "efoy.LogTHE"
data_type: float32
swap: word
device_class: temperature
scan_interval: 10
address: 289
input_type: input
unit_of_measurement: "°C"
- name: "LogTMeOH"
unique_id: "efoy.LogTMeOH"
data_type: float32
swap: word
device_class: temperature
scan_interval: 10
address: 291
input_type: input
unit_of_measurement: "°C"
- name: "CartCapStatus"
unique_id: "efoy.CartCapStatus"
data_type: float32
swap: word
device_class: volume
scan_interval: 10
address: 202
input_type: input
unit_of_measurement: "L"
- name: "CartRlVolStatus"
unique_id: "efoy.CartRlVolStatus"
data_type: float32
swap: word
device_class: battery
min_value: 0
max_value: 100
scan_interval: 10
address: 204
input_type: input
unit_of_measurement: "%"
- name: "CartAbVolStatus"
unique_id: "efoy.CartAbVolStatus"
data_type: float32
swap: word
device_class: volume_storage
scan_interval: 10
address: 206
input_type: input
unit_of_measurement: "L"
switches:
- name: "SystemOn"
unique_id: "efoy.SystemOn"
address: 0
write_type: coil
verify:
- name: "SystemOff"
unique_id: "efoy.SystemOff"
address: 1
write_type: coil
verify:
- name: "SystemAuto"
unique_id: "efoy.SystemAuto"
address: 2
write_type: coil
verify:
Optionally, you can also add these template sensors to your Configuration.yaml, to get human readable output for the Operational mode and System state
template:
- sensor:
- name: "SystemState"
unique_id: "efoy.SystemState"
device_class: enum
state: >
{% set mapper = {
'0' : 'Off',
'1' : 'Standby',
'2' : 'Operational',
'3' : 'Shut down',
'4' : 'Frost protection',
'5' : 'Deep discharge protection',
'6' : 'Transport locking',
'7' : 'Transport locked',
'8' : 'Reset',
'9' : 'Factory default',
'10' : 'Error',
'11' : 'Frost protection',
'12' : 'pending',
'13' : 'pending',
'14' : 'Update accessories'} %}
{% set state = states('sensor.SystemStateEnum') %}
{{ mapper[state] if state in mapper else 'Unknown' }}
- name: "OperatingMode"
unique_id: "efoy.OperatingMode"
device_class: enum
state: >
{% set mapper = {
'0' : 'Auto',
'1' : 'Off'} %}
{% set state = states('sensor.OperatingModeEnum') %}
{{ mapper[state] if state in mapper else 'Unknown' }}