Custom Sensors
You can create custom sensors by defining them in a file called mysensors.py
in the /share/hass-addon-sunsynk/
directory. This allows you to add sensors that are not included in the default definitions.
In it's most basic form a sensor the RS486 register and a name. You can find the RS485 protocol document at various places online, search the Power Forum or Github issue #59
The /share/
folder can be accessed through the Samba addon in Home Assistant. You can create the hass-addon-sunsynk
folder & the mysensors.py
file
This is a Python file and follows the same logic as the definitions.py & definitions3p.py. It exposes a single SENSORS
global variable to which you can add the individual sensor definitions.
An example mysensors.py
file:
from sunsynk import AMPS, CELSIUS, KWH, VOLT, WATT, Sensor, SensorDefinitions
from sunsynk.rwsensors import NumberRWSensor, SelectRWSensor, TimeRWSensor
from sunsynk.sensors import MathSensor, TempSensor
# Initialize the sensor definitions
SENSORS = SensorDefinitions()
# Add your custom sensors
SENSORS += (
# Basic sensor example
Sensor(178, "My Custom Power Sensor", WATT, -1),
# Math sensor example (combining multiple registers)
MathSensor((175, 172), "Custom Combined Power", WATT, factors=(1, 1)),
# Read/Write sensor example
NumberRWSensor(130, "Custom Control Setting", "%", min=0, max=100),
)
The sensor definition parameters are:
- First parameter: Register number(s)
- Second parameter: Sensor name
- Third parameter: Unit (WATT, VOLT, AMPS, etc.)
- Last parameter: Scale factor (optional)
You can create different types of sensors:
Sensor
: Basic read-only sensorMathSensor
: Combines multiple registers with mathematical operationsNumberRWSensor
: Read/write sensor for configurable valuesSelectRWSensor
: Read/write sensor with predefined optionsSwitchRWSensor
: Read/write sensor for boolean values
An example of adding a custom selling load sensor, the takes the ct power off the inverter output is
MathSensor((175, 172), "Selling Load Power direct", WATT, factors=(1, 1)),
Once defined, your custom sensors will be loaded automatically when the addon starts, and you'll see them listed in the startup logs:
INFO Importing /share/hass-addon-sunsynk/mysensors.py...
INFO custom sensors: my_custom_power_sensor, custom_combined_power, custom_control_setting
Using the sensor
Once a sensor is loaded, you still have to add it to your configuration:
SENSORS:
- my_custom_sensor_1
- my_custom_sensor_2
You can also add all the custom sensors, using the special group called mysensors
.
SENSORS:
- mysensors
More examples
Python based sensor
This sensors divides 2 registers (reg 10/reg 20)
import attrs
from sunsynk import Sensor, SensorDefinitions, WATT
from sunsynk.helpers import unpack_value
@attrs.define(slots=True, eq=False)
class MyCustomSensor(Sensor):
"""Custom sensor, using multiple registers."""
def reg_to_value(self, regs: RegType) -> ValType:
"""Calculate the value."""
val1 = unpack_value((regs[0],), signed=True)
val2 = unpack_value((regs[1],), signed=True)
return val1 / val2
SENSORS = SensorDefinition()
# Use the class above with register 10 and 20
SENSORS += MyCustomSensor((10, 20), "Mysensor1", WATT)
Time sensor
INFO
Write is only partially implemented in the example below
Details
import attrs
import re
from sunsynk import RegType, ValType, SensorDefinitions
from sunsynk.rwsensors import RWSensor, ResolveType
SENSORS = SensorDefinitions()
@attrs.define(slots=True, eq=False)
class SystemTimeRWSensor(RWSensor):
"""Read & write time sensor."""
def value_to_reg(self, value: ValType, resolve: ResolveType) -> RegType:
"""Get the reg value from a display value."""
redt = re.compile(r"(2\d{3})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})")
match = redt.fullmatch(value)
if not match:
raise ValueError("Invalid datetime {value}")
y, m, d = int(match.group(1)) - 2000, int(match.group(2)), int(match.group(3))
h, mn, s = int(match.group(4)), int(match.group(5)), int(match.group(6))
regs = (
(y << 8) + m,
(d << 8) + h,
(mn << 8) + s,
)
raise ValueError(f"{y}-{m:02}-{d:02} {h}:{mn:02}:{s:02} ==> {regs}")
return regs
def reg_to_value(self, regs: RegType) -> ValType:
"""Decode the register."""
y = ((regs[0] & 0xFF00) >> 8) + 2000
m = regs[0] & 0xFF
d = (regs[1] & 0xFF00) >> 8
h = regs[1] & 0xFF
mn = (regs[2] & 0xFF00) >> 8
s = regs[2] & 0xFF
return f"{y}-{m:02}-{d:02} {h}:{mn:02}:{s:02}"
SENSORS += SystemTimeRWSensor((22, 23, 24), "Date", unit="")