From b7e532ca46f185852b1105bc7f0e0efd07947e6b Mon Sep 17 00:00:00 2001 From: ndrsnhs Date: Wed, 23 Jul 2025 11:49:21 +0200 Subject: [PATCH 1/7] add support for shelly pro em --- packages/modules/devices/shelly/shelly/bat.py | 4 +++- packages/modules/devices/shelly/shelly/inverter.py | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/modules/devices/shelly/shelly/bat.py b/packages/modules/devices/shelly/shelly/bat.py index 994f7a7208..8ecb2f10ff 100644 --- a/packages/modules/devices/shelly/shelly/bat.py +++ b/packages/modules/devices/shelly/shelly/bat.py @@ -51,8 +51,10 @@ def total_power_from_shelly(self) -> int: for meter in meters: total = total + meter['power'] else: - if 'switch:0' in status: + if 'switch:0' in status and 'apower' in status['switch:0']: total = status['switch:0']['apower'] + elif 'em1:0' in status: + total = status['em1:0']['act_power'] # shelly Pro EM Gen 2 elif 'pm1:0' in status: total = status['pm1:0']['apower'] # shelly PM Mini Gen 3 else: diff --git a/packages/modules/devices/shelly/shelly/inverter.py b/packages/modules/devices/shelly/shelly/inverter.py index d8a1285d38..173c68e327 100644 --- a/packages/modules/devices/shelly/shelly/inverter.py +++ b/packages/modules/devices/shelly/shelly/inverter.py @@ -51,8 +51,10 @@ def total_power_from_shelly(self) -> int: for meter in meters: total = total + meter['power'] else: - if 'switch:0' in status: + if 'switch:0' in status and 'apower' in status['switch:0']: total = status['switch:0']['apower'] + elif 'em1:0' in status: + total = status['em1:0']['act_power'] # shelly Pro EM Gen 2 elif 'pm1:0' in status: total = status['pm1:0']['apower'] # shelly PM Mini Gen 3 else: From dab6e08205fe2d52252cf7b77279468c7d3723fb Mon Sep 17 00:00:00 2001 From: ndrsnhs Date: Wed, 23 Jul 2025 15:44:53 +0200 Subject: [PATCH 2/7] add single phase shellys as counter --- .../modules/devices/shelly/shelly/counter.py | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/modules/devices/shelly/shelly/counter.py b/packages/modules/devices/shelly/shelly/counter.py index 995bda7df0..3c4ebadf41 100644 --- a/packages/modules/devices/shelly/shelly/counter.py +++ b/packages/modules/devices/shelly/shelly/counter.py @@ -63,13 +63,32 @@ def update(self) -> None: power_factors = [meter[f'{i}_pf'] for i in 'abc'] power = meter['total_act_power'] * self.factor # Shelly MiniPM G3 - else: - meter = status['pm1:0'] + elif "pm1:0" in status: log.debug("single phase shelly") + meter = status['pm1:0'] voltages = [meter['voltage'], 0, 0] currents = [meter['current'], 0, 0] power = meter['apower'] frequency = meter['freq'] + powers = [meter['apower'], 0, 0] + elif 'switch:0' in status and 'apower' in status['switch:0']: + log.debug("single phase shelly") + meter = status['switch:0'] + power = meter['apower'] + voltages = [meter['voltage'], 0, 0] + currents = [meter['current'], 0, 0] + frequency = meter['freq'] + power_factors = [meter['pf'], 0, 0] + powers = [meter['apower'], 0, 0] + else: + log.debug("single phase shelly") + meter = status['em1:0'] + power = meter['act_power'] # shelly Pro EM Gen 2 + voltages = [meter['voltage'], 0, 0] + currents = [meter['current'], 0, 0] + frequency = meter['freq'] + power_factors = [meter['pf'], 0, 0] + powers = [meter['act_power'], 0, 0] imported, exported = self.sim_counter.sim_count(power) From c19f730f7473d618607d236db3c9b98a615d7ce8 Mon Sep 17 00:00:00 2001 From: ndrsnhs Date: Thu, 24 Jul 2025 12:11:18 +0200 Subject: [PATCH 3/7] add bat and inverter currents; add powers to test --- packages/modules/devices/shelly/shelly/bat.py | 44 ++++++++++--------- .../modules/devices/shelly/shelly/inverter.py | 40 +++++++++-------- .../devices/shelly/shelly/shelly_test.py | 2 +- 3 files changed, 46 insertions(+), 40 deletions(-) diff --git a/packages/modules/devices/shelly/shelly/bat.py b/packages/modules/devices/shelly/shelly/bat.py index 8ecb2f10ff..c340d0a370 100644 --- a/packages/modules/devices/shelly/shelly/bat.py +++ b/packages/modules/devices/shelly/shelly/bat.py @@ -34,13 +34,14 @@ def initialize(self) -> None: self.store = get_bat_value_store(self.component_config.id) self.fault_state = FaultState(ComponentInfo.from_component_config(self.component_config)) - def total_power_from_shelly(self) -> int: - total = 0 + def update(self) -> None: + power = 0 if self.generation == 1: status_url = "http://" + self.address + "/status" else: status_url = "http://" + self.address + "/rpc/Shelly.GetStatus" status = req.get_http_session().get(status_url, timeout=3).json() + try: if self.generation == 1: if 'meters' in status: @@ -49,30 +50,33 @@ def total_power_from_shelly(self) -> int: meters = status['emeters'] # shellyEM & shelly3EM # shellyEM has one meter, shelly3EM has three meters: for meter in meters: - total = total + meter['power'] + power = power + meter['power'] + currents = [0, 0, 0] else: if 'switch:0' in status and 'apower' in status['switch:0']: - total = status['switch:0']['apower'] + power = status['switch:0']['apower'] + currents = [status['switch:0']['current'], 0, 0] elif 'em1:0' in status: - total = status['em1:0']['act_power'] # shelly Pro EM Gen 2 + power = status['em1:0']['act_power'] # shelly Pro EM Gen 2 + currents = [status['em1:0']['current'], 0, 0] elif 'pm1:0' in status: - total = status['pm1:0']['apower'] # shelly PM Mini Gen 3 + power = status['pm1:0']['apower'] # shelly PM Mini Gen 3 + currents = [status['pm1:0']['current'], 0, 0] else: - total = status['em:0']['total_act_power'] # shelly Pro3EM - except KeyError: - log.exception("unsupported shelly device?") - finally: - return int(total) + power = status['em:0']['total_act_power'] # shelly Pro3EM + currents = [meter[f'{i}_current'] for i in 'abc'] - def update(self) -> None: - bat = self.total_power_from_shelly() * self.factor - imported, exported = self.sim_counter.sim_count(bat) - bat_state = BatState( - power=bat, - imported=imported, - exported=exported - ) - self.store.set(bat_state) + power = power * self.factor + imported, exported = self.sim_counter.sim_count(power) + bat_state = BatState( + power=power, + imported=imported, + exported=exported, + currents=currents + ) + self.store.set(bat_state) + except KeyError: + log.exception("unsupported shelly device.") component_descriptor = ComponentDescriptor(configuration_factory=ShellyBatSetup) diff --git a/packages/modules/devices/shelly/shelly/inverter.py b/packages/modules/devices/shelly/shelly/inverter.py index 173c68e327..7ef7818914 100644 --- a/packages/modules/devices/shelly/shelly/inverter.py +++ b/packages/modules/devices/shelly/shelly/inverter.py @@ -34,8 +34,8 @@ def initialize(self) -> None: self.store = get_inverter_value_store(self.component_config.id) self.fault_state = FaultState(ComponentInfo.from_component_config(self.component_config)) - def total_power_from_shelly(self) -> int: - total = 0 + def update(self) -> None: + power = 0 if self.generation == 1: status_url = "http://" + self.address + "/status" else: @@ -49,29 +49,31 @@ def total_power_from_shelly(self) -> int: meters = status['emeters'] # shellyEM & shelly3EM # shellyEM has one meter, shelly3EM has three meters: for meter in meters: - total = total + meter['power'] + power = power + meter['power'] else: if 'switch:0' in status and 'apower' in status['switch:0']: - total = status['switch:0']['apower'] + power = status['switch:0']['apower'] + currents = [status['switch:0']['current'], 0, 0] elif 'em1:0' in status: - total = status['em1:0']['act_power'] # shelly Pro EM Gen 2 + power = status['em1:0']['act_power'] # shelly Pro EM Gen 2 + currents = [status['em1:0']['current'], 0, 0] elif 'pm1:0' in status: - total = status['pm1:0']['apower'] # shelly PM Mini Gen 3 + power = status['pm1:0']['apower'] # shelly PM Mini Gen 3 + currents = [status['pm1:0']['current'], 0, 0] else: - total = status['em:0']['total_act_power'] # shelly Pro3EM - except KeyError: - log.exception("unsupported shelly device?") - finally: - return int(total) + power = status['em:0']['total_act_power'] # shelly Pro3EM + currents = [meter[f'{i}_current'] for i in 'abc'] - def update(self) -> None: - pv = self.total_power_from_shelly() * self.factor - _, pv_exported = self.sim_counter.sim_count(pv) - inverter_state = InverterState( - power=pv, - exported=pv_exported - ) - self.store.set(inverter_state) + pv = self.total_power_from_shelly() * self.factor + _, exported = self.sim_counter.sim_count(pv) + inverter_state = InverterState( + power=pv, + exported=exported, + currents=currents + ) + self.store.set(inverter_state) + except KeyError: + log.exception("unsupported shelly device.") component_descriptor = ComponentDescriptor(configuration_factory=ShellyInverterSetup) diff --git a/packages/modules/devices/shelly/shelly/shelly_test.py b/packages/modules/devices/shelly/shelly/shelly_test.py index 7825623a5f..8be2aa50e5 100644 --- a/packages/modules/devices/shelly/shelly/shelly_test.py +++ b/packages/modules/devices/shelly/shelly/shelly_test.py @@ -56,4 +56,4 @@ def test_counter_shelly_minipm_g3(monkeypatch, requests_mock: requests_mock.mock SAMPLE_COUNTER_STATE = CounterState(voltages=[230.9, 0, 0], power=230, currents=[ - 1, 0, 0], frequency=51, imported=100, exported=200) + 1, 0, 0], frequency=51, imported=100, exported=200, powers=[230, 0, 0]) From 444335b014cd94cac6371b20c7a4e6b5ba064479 Mon Sep 17 00:00:00 2001 From: ndrsnhs Date: Tue, 29 Jul 2025 08:54:05 +0200 Subject: [PATCH 4/7] fix shelly inverter --- packages/modules/devices/shelly/shelly/inverter.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/modules/devices/shelly/shelly/inverter.py b/packages/modules/devices/shelly/shelly/inverter.py index 7ef7818914..d59443652e 100644 --- a/packages/modules/devices/shelly/shelly/inverter.py +++ b/packages/modules/devices/shelly/shelly/inverter.py @@ -64,10 +64,10 @@ def update(self) -> None: power = status['em:0']['total_act_power'] # shelly Pro3EM currents = [meter[f'{i}_current'] for i in 'abc'] - pv = self.total_power_from_shelly() * self.factor - _, exported = self.sim_counter.sim_count(pv) + power = power * self.factor + _, exported = self.sim_counter.sim_count(power) inverter_state = InverterState( - power=pv, + power=power, exported=exported, currents=currents ) From aef1a86f54823139f1bbe0a7bd93b410a66d745d Mon Sep 17 00:00:00 2001 From: LKuemmel <76958050+LKuemmel@users.noreply.github.com> Date: Tue, 29 Jul 2025 10:29:10 +0200 Subject: [PATCH 5/7] Remove duplicate lines --- packages/modules/devices/shelly/shelly/inverter.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/packages/modules/devices/shelly/shelly/inverter.py b/packages/modules/devices/shelly/shelly/inverter.py index 269d557db1..d59443652e 100644 --- a/packages/modules/devices/shelly/shelly/inverter.py +++ b/packages/modules/devices/shelly/shelly/inverter.py @@ -50,14 +50,7 @@ def update(self) -> None: # shellyEM has one meter, shelly3EM has three meters: for meter in meters: power = power + meter['power'] - power = power + meter['power'] else: - if 'switch:0' in status and 'apower' in status['switch:0']: - power = status['switch:0']['apower'] - currents = [status['switch:0']['current'], 0, 0] - elif 'em1:0' in status: - power = status['em1:0']['act_power'] # shelly Pro EM Gen 2 - currents = [status['em1:0']['current'], 0, 0] if 'switch:0' in status and 'apower' in status['switch:0']: power = status['switch:0']['apower'] currents = [status['switch:0']['current'], 0, 0] @@ -67,8 +60,6 @@ def update(self) -> None: elif 'pm1:0' in status: power = status['pm1:0']['apower'] # shelly PM Mini Gen 3 currents = [status['pm1:0']['current'], 0, 0] - power = status['pm1:0']['apower'] # shelly PM Mini Gen 3 - currents = [status['pm1:0']['current'], 0, 0] else: power = status['em:0']['total_act_power'] # shelly Pro3EM currents = [meter[f'{i}_current'] for i in 'abc'] From 15b76f662184bd812d3d72d723645b7c63718f35 Mon Sep 17 00:00:00 2001 From: ndrsnhs Date: Fri, 1 Aug 2025 14:23:39 +0200 Subject: [PATCH 6/7] remove redundant code --- packages/modules/devices/shelly/shelly/inverter.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/packages/modules/devices/shelly/shelly/inverter.py b/packages/modules/devices/shelly/shelly/inverter.py index 269d557db1..d59443652e 100644 --- a/packages/modules/devices/shelly/shelly/inverter.py +++ b/packages/modules/devices/shelly/shelly/inverter.py @@ -50,14 +50,7 @@ def update(self) -> None: # shellyEM has one meter, shelly3EM has three meters: for meter in meters: power = power + meter['power'] - power = power + meter['power'] else: - if 'switch:0' in status and 'apower' in status['switch:0']: - power = status['switch:0']['apower'] - currents = [status['switch:0']['current'], 0, 0] - elif 'em1:0' in status: - power = status['em1:0']['act_power'] # shelly Pro EM Gen 2 - currents = [status['em1:0']['current'], 0, 0] if 'switch:0' in status and 'apower' in status['switch:0']: power = status['switch:0']['apower'] currents = [status['switch:0']['current'], 0, 0] @@ -67,8 +60,6 @@ def update(self) -> None: elif 'pm1:0' in status: power = status['pm1:0']['apower'] # shelly PM Mini Gen 3 currents = [status['pm1:0']['current'], 0, 0] - power = status['pm1:0']['apower'] # shelly PM Mini Gen 3 - currents = [status['pm1:0']['current'], 0, 0] else: power = status['em:0']['total_act_power'] # shelly Pro3EM currents = [meter[f'{i}_current'] for i in 'abc'] From 4f2cc9f7974f9e83879ad9b211facdfe8d77d9f0 Mon Sep 17 00:00:00 2001 From: ndrsnhs Date: Fri, 1 Aug 2025 14:35:35 +0200 Subject: [PATCH 7/7] =?UTF-8?q?add=20currents=20only=20f=C3=BCr=20gen2+?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/modules/devices/shelly/shelly/bat.py | 5 +++-- packages/modules/devices/shelly/shelly/inverter.py | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/modules/devices/shelly/shelly/bat.py b/packages/modules/devices/shelly/shelly/bat.py index c340d0a370..abbcb15ab3 100644 --- a/packages/modules/devices/shelly/shelly/bat.py +++ b/packages/modules/devices/shelly/shelly/bat.py @@ -71,9 +71,10 @@ def update(self) -> None: bat_state = BatState( power=power, imported=imported, - exported=exported, - currents=currents + exported=exported ) + if 'currents' in locals(): + bat_state.currents = currents self.store.set(bat_state) except KeyError: log.exception("unsupported shelly device.") diff --git a/packages/modules/devices/shelly/shelly/inverter.py b/packages/modules/devices/shelly/shelly/inverter.py index d59443652e..cc57a0959f 100644 --- a/packages/modules/devices/shelly/shelly/inverter.py +++ b/packages/modules/devices/shelly/shelly/inverter.py @@ -68,9 +68,10 @@ def update(self) -> None: _, exported = self.sim_counter.sim_count(power) inverter_state = InverterState( power=power, - exported=exported, - currents=currents + exported=exported ) + if 'currents' in locals(): + inverter_state.currents = currents self.store.set(inverter_state) except KeyError: log.exception("unsupported shelly device.")