Skip to content

Commit

Permalink
Merge pull request #159 from kbialek/feature/settings-micro
Browse files Browse the repository at this point in the history
Add settings_micro metric group
  • Loading branch information
kbialek authored Mar 25, 2024
2 parents 0b42403 + 84bdaea commit 4d747e2
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 19 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ METRIC_GROUPS = \
deye_hybrid_battery \
deye_hybrid_timeofuse \
settings \
settings_micro \
deye_sg01hp3 \
deye_sg01hp3_battery \
deye_sg01hp3_ups \
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ When your inverter turns out to work well with an already exiting metrics group,
| Inverter model | Metric groups |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Deye SUN-4/5/6/7/8/10/12K-G05-P](https://www.deyeinverter.com/product/three-phase-string-inverter/sun4-5-6-7-8-10-12kg05p-412kw-three-phase-2-mppt.html) | [string](docs/metric_group_string.md), [settings](docs/metric_group_settings.md) |
| [Deye SUN300/500G3-US-220/EU-230](https://www.deyeinverter.com/product/microinverter-1/sun300-500g3eu230.html) | [micro](docs/metric_group_micro.md), [settings](docs/metric_group_settings.md) |
| [Deye SUN600/800/1000G3-US-220/EU-230](https://www.deyeinverter.com/product/microinverter-1/sun600-800-1000g3eu230-single-phase-4-mppt-microinverter-rapid-shutdown.html) | [micro](docs/metric_group_micro.md), [settings](docs/metric_group_settings.md) |
| [Deye SUN300/500G3-US-220/EU-230](https://www.deyeinverter.com/product/microinverter-1/sun300-500g3eu230.html) | [micro](docs/metric_group_micro.md), [settings_micro](docs/metric_group_settings_micro.md) |
| [Deye SUN600/800/1000G3-US-220/EU-230](https://www.deyeinverter.com/product/microinverter-1/sun600-800-1000g3eu230-single-phase-4-mppt-microinverter-rapid-shutdown.html) | [micro](docs/metric_group_micro.md), [settings_micro](docs/metric_group_settings_micro.md) |
| [Deye SUN-M60/80/100G3-EU-Q0](https://www.deyeinverter.com/product/microinverter-1/SUN600-800-1000G3US220-EU230-6001000W-Einphasig-2-MPPT-MikroWechselrichter-Schnelles-Herunterfahren.html) | [micro](docs/metric_group_micro.md), [settings](docs/metric_group_settings.md) |
| [Deye SUN1300-2000G3-US-220/EU-230](https://www.deyeinverter.com/product/microinverter-1/sun13002000g3eu230.html) | [micro](docs/metric_group_micro.md), [settings](docs/metric_group_settings.md) |
| [Deye SUN-5/6/8/10/12K-SG04LP3](https://deye.com/product/sun-5-6-8-10-12k-sg04lp3-5-12kw-three-phase-2-mppt-hybrid-inverter-low-voltage-battery/) | [deye_sg04lp3](docs/metric_group_deye_sg04lp3.md), [deye_sg04lp3_battery](docs/metric_group_deye_sg04lp3_battery.md), [deye_sg04lp3_ups](docs/metric_group_deye_sg04lp3_ups.md), [deye_sg04lp3_timeofuse](docs/metric_group_deye_sg04lp3_timeofuse.md), [settings](docs/metric_group_settings.md) |
Expand Down Expand Up @@ -228,7 +228,8 @@ All configuration options are controlled through environment variables.
* `deye_sg01hp3_bms` - sg01hp3 bms
* `deye_sg01hp3_ups` - sg01hp3 ups
* `igen_dtsd422`- dtsd422 smart meter
* `settings` - inverter settings
* `settings` - inverter settings, all types except micro
* `settings_micro` - inverter settings for micro inverters
* `DEYE_LOGGER_COUNT` - declares the number of inverters, and therefore loggers to connect, optional, defaults to `0`, which means, that multi-inverter support is disabled
* `DEYE_LOGGER_SERIAL_NUMBER` - inverter data logger serial number
* `DEYE_LOGGER_IP_ADDRESS` - inverter data logger IP address
Expand Down
3 changes: 3 additions & 0 deletions docs/metric_group_settings_micro.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
|Metric|Modbus address|MQTT topic suffix|Unit|
|---|:-:|---|:-:|
|Active power regulation|40|`settings/active_power_regulation`|%|
21 changes: 18 additions & 3 deletions src/deye_active_power_regulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,29 @@
from deye_modbus import DeyeModbus
from deye_config import DeyeLoggerConfig
from deye_events import DeyeEventProcessor
from deye_sensor import Sensor
from paho.mqtt.client import Client, MQTTMessage


class DeyeActivePowerRegulationEventProcessor(DeyeEventProcessor):
def __init__(self, logger_config: DeyeLoggerConfig, mqtt_client: DeyeMqttClient, modbus: DeyeModbus):
def __init__(
self, logger_config: DeyeLoggerConfig, mqtt_client: DeyeMqttClient, sensors: [Sensor], modbus: DeyeModbus
):
self.__log = logger_config.logger_adapter(logging.getLogger(DeyeActivePowerRegulationEventProcessor.__name__))
self.__logger_config = logger_config
self.__mqtt_client = mqtt_client
self.__modbus = modbus
self.__active_power_regulation_topic_suffix = "settings/active_power_regulation"
matching_sensors = [s for s in sensors if s.mqtt_topic_suffix == self.__active_power_regulation_topic_suffix]
if len(matching_sensors) == 0:
self.__log.error("Active power regulation sensor not found. Enable appropriate settings metric group.")
return
elif len(matching_sensors) > 1:
self.__log.error(
"Too many active power regulation sensors not found. Check your metric groups configuration."
)
return
self.__active_power_reg_sensor = matching_sensors[0]

def get_id(self):
return "active_power_regulation"
Expand All @@ -39,7 +53,7 @@ def get_description(self):

def initialize(self):
self.__mqtt_client.subscribe_command_handler(
self.__logger_config.index, "settings/active_power_regulation", self.handle_command
self.__logger_config.index, self.__active_power_regulation_topic_suffix, self.handle_command
)

def handle_command(self, client: Client, userdata, msg: MQTTMessage):
Expand All @@ -58,4 +72,5 @@ def handle_command(self, client: Client, userdata, msg: MQTTMessage):
return

self.__log.info("Setting active power regulation to %f", active_power_regulation_factor)
self.__modbus.write_register_uint(40, int(active_power_regulation_factor * 10))
reg_addr, reg_value = self.__active_power_reg_sensor.write_value(msg.payload).popitem()
self.__modbus.write_register(reg_addr, reg_value)
18 changes: 13 additions & 5 deletions src/deye_sensors_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

from deye_sensor import SingleRegisterSensor, SensorRegisterRange

deye_settings_active_power_regulation = SingleRegisterSensor(
deye_settings_active_power_regulation_default = SingleRegisterSensor(
"Active power regulation",
40,
0.1,
Expand All @@ -27,10 +27,18 @@
groups=["settings"],
)

deye_settings_sensors = [
deye_settings_active_power_regulation,
]
deye_settings_active_power_regulation_micro = SingleRegisterSensor(
"Active power regulation",
40,
1,
mqtt_topic_suffix="settings/active_power_regulation",
unit="%",
signed=False,
groups=["settings_micro"],
)

deye_settings_sensors = [deye_settings_active_power_regulation_default, deye_settings_active_power_regulation_micro]

deye_settings_register_ranges = [
SensorRegisterRange(group="settings", first_reg_address=40, last_reg_address=40),
SensorRegisterRange(group={"settings", "settings_micro"}, first_reg_address=40, last_reg_address=40),
]
37 changes: 29 additions & 8 deletions tests/deye_active_power_regulation_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@
from deye_modbus import DeyeModbus
from deye_mqtt import DeyeMqttClient
from deye_config import DeyeConfig, DeyeMqttConfig, DeyeLoggerConfig
from deye_sensor import Sensor
from paho.mqtt.client import Client, MQTTMessage


class TestDeyeActivePowerRegulationCommandHandler:
class TestDeyeActivePowerRegulationEventProcessor:
@staticmethod
@pytest.fixture
def modbus_mock(mocker) -> DeyeModbus:
Expand All @@ -45,11 +46,23 @@ def mqtt_config_mock(mocker) -> DeyeMqttConfig:
def config_mock(mocker) -> DeyeLoggerConfig:
return mocker.Mock(spec=DeyeLoggerConfig)

@staticmethod
@pytest.fixture
def sensors(mocker) -> [Sensor]:
sensor = mocker.Mock(spec=Sensor)
sensor.mqtt_topic_suffix = "settings/active_power_regulation"
sensor.write_value.return_value = {40: bytearray.fromhex("0102")}
return [sensor]

def test_handle_valid_value(
self, config_mock: DeyeLoggerConfig, mqtt_client_mock: DeyeMqttClient, modbus_mock: DeyeModbus
self,
config_mock: DeyeLoggerConfig,
mqtt_client_mock: DeyeMqttClient,
modbus_mock: DeyeModbus,
sensors: [Sensor],
):
# given
sut = DeyeActivePowerRegulationEventProcessor(config_mock, mqtt_client_mock, modbus_mock)
sut = DeyeActivePowerRegulationEventProcessor(config_mock, mqtt_client_mock, sensors, modbus_mock)

# and
msg = MQTTMessage()
Expand All @@ -59,13 +72,17 @@ def test_handle_valid_value(
sut.handle_command(None, None, msg)

# then
modbus_mock.write_register_uint.assert_called_with(40, 1000)
modbus_mock.write_register.assert_called_with(40, bytearray.fromhex("0102"))

def test_reject_too_high_value(
self, config_mock: DeyeLoggerConfig, mqtt_client_mock: DeyeMqttClient, modbus_mock: DeyeModbus
self,
config_mock: DeyeLoggerConfig,
mqtt_client_mock: DeyeMqttClient,
modbus_mock: DeyeModbus,
sensors: [Sensor],
):
# given
sut = DeyeActivePowerRegulationEventProcessor(config_mock, mqtt_client_mock, modbus_mock)
sut = DeyeActivePowerRegulationEventProcessor(config_mock, mqtt_client_mock, sensors, modbus_mock)

# and
msg = MQTTMessage()
Expand All @@ -78,10 +95,14 @@ def test_reject_too_high_value(
assert not modbus_mock.write_register_uint.called

def test_reject_too_low_value(
self, config_mock: DeyeLoggerConfig, mqtt_client_mock: DeyeMqttClient, modbus_mock: DeyeModbus
self,
config_mock: DeyeLoggerConfig,
mqtt_client_mock: DeyeMqttClient,
modbus_mock: DeyeModbus,
sensors: [Sensor],
):
# given
sut = DeyeActivePowerRegulationEventProcessor(config_mock, mqtt_client_mock, modbus_mock)
sut = DeyeActivePowerRegulationEventProcessor(config_mock, mqtt_client_mock, sensors, modbus_mock)

# and
msg = MQTTMessage()
Expand Down

0 comments on commit 4d747e2

Please sign in to comment.