From da96506101a248f0803e95e8ac1220c4ba94bb91 Mon Sep 17 00:00:00 2001 From: ndrsnhs Date: Wed, 14 Feb 2024 12:26:40 +0100 Subject: [PATCH 1/2] add Shelly Pro3EM as inverter to shelly module --- packages/modules/devices/shelly/config.py | 4 ++-- packages/modules/devices/shelly/device.py | 18 ++++++++++++------ packages/modules/devices/shelly/inverter.py | 12 +++++++----- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/packages/modules/devices/shelly/config.py b/packages/modules/devices/shelly/config.py index a831ee9403..0f5ce8055f 100644 --- a/packages/modules/devices/shelly/config.py +++ b/packages/modules/devices/shelly/config.py @@ -5,9 +5,9 @@ @auto_str class ShellyConfiguration: - def __init__(self, ip_address: Optional[str] = None, generation: Optional[int] = None): + def __init__(self, ip_address: Optional[str] = None, type: Optional[int] = None): self.ip_address = ip_address - self.generation = generation + self.type = type @auto_str diff --git a/packages/modules/devices/shelly/device.py b/packages/modules/devices/shelly/device.py index 04be22c494..281e67e26e 100644 --- a/packages/modules/devices/shelly/device.py +++ b/packages/modules/devices/shelly/device.py @@ -15,22 +15,28 @@ log = logging.getLogger(__name__) -def get_device_generation(address: str) -> int: +def get_device_type(address: str) -> int: url = "http://" + address + "/shelly" + app = None generation = 1 device_info = req.get_http_session().get(url, timeout=3).json() + if 'app' in device_info: + app = int(device_info['app']) if 'gen' in device_info: generation = int(device_info['gen']) - return generation + if generation == 2 and app == "Pro3EM": + return 3 + else: + return generation def create_device(device_config: Shelly) -> ConfigurableDevice: def create_inverter_component(component_config: ShellyInverterSetup) -> ShellyInverter: return ShellyInverter(device_config.id, component_config, device_config.configuration.ip_address, - device_config.configuration.generation) + device_config.configuration.type) - if device_config.configuration.generation is None and device_config.configuration.ip_address is not None: - device_config.configuration.generation = get_device_generation(device_config.configuration.ip_address) + if device_config.configuration.type is None and device_config.configuration.ip_address is not None: + device_config.configuration.type = get_device_type(device_config.configuration.ip_address) return ConfigurableDevice( device_config=device_config, @@ -66,7 +72,7 @@ def read_legacy_inverter(address: str, num: int) -> None: with open(generation_file_name, 'r') as file: generation = int(file.read()) else: - generation = get_device_generation(address) + generation = get_device_type(address) with open(generation_file_name, 'w') as file: file.write(str(generation)) run_device_legacy(create_legacy_device_config(address, generation, diff --git a/packages/modules/devices/shelly/inverter.py b/packages/modules/devices/shelly/inverter.py index b700b778d5..467c38c7d2 100644 --- a/packages/modules/devices/shelly/inverter.py +++ b/packages/modules/devices/shelly/inverter.py @@ -18,23 +18,23 @@ def __init__(self, device_id: int, component_config: ShellyInverterSetup, address: str, - generation: Optional[int]) -> None: + type: Optional[int]) -> None: self.component_config = component_config self.sim_counter = SimCounter(device_id, self.component_config.id, prefix="pv") self.store = get_inverter_value_store(self.component_config.id) self.fault_state = FaultState(ComponentInfo.from_component_config(self.component_config)) self.address = address - self.generation = generation + self.type = type def total_power_from_shelly(self) -> int: total = 0 - if self.generation == 1: + if self.type == 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 self.type == 1: if 'meters' in status: meters = status['meters'] # shelly else: @@ -42,8 +42,10 @@ def total_power_from_shelly(self) -> int: # shellyEM has one meter, shelly3EM has three meters: for meter in meters: total = total + meter['power'] - else: + elif self.type == 2: total = status['switch:0']['apower'] + else: + total = status['em:0']['total_act_power'] except KeyError: log.exception("unsupported shelly device?") finally: From 8eb67e5e4a2de4b0c99bc0f272d6d082f082ce34 Mon Sep 17 00:00:00 2001 From: ndrsnhs Date: Wed, 21 Feb 2024 10:28:44 +0100 Subject: [PATCH 2/2] distinguish between shellys just based on generation --- packages/modules/devices/shelly/config.py | 4 ++-- packages/modules/devices/shelly/device.py | 18 ++++++------------ packages/modules/devices/shelly/inverter.py | 15 ++++++++------- 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/packages/modules/devices/shelly/config.py b/packages/modules/devices/shelly/config.py index 0f5ce8055f..a831ee9403 100644 --- a/packages/modules/devices/shelly/config.py +++ b/packages/modules/devices/shelly/config.py @@ -5,9 +5,9 @@ @auto_str class ShellyConfiguration: - def __init__(self, ip_address: Optional[str] = None, type: Optional[int] = None): + def __init__(self, ip_address: Optional[str] = None, generation: Optional[int] = None): self.ip_address = ip_address - self.type = type + self.generation = generation @auto_str diff --git a/packages/modules/devices/shelly/device.py b/packages/modules/devices/shelly/device.py index 281e67e26e..04be22c494 100644 --- a/packages/modules/devices/shelly/device.py +++ b/packages/modules/devices/shelly/device.py @@ -15,28 +15,22 @@ log = logging.getLogger(__name__) -def get_device_type(address: str) -> int: +def get_device_generation(address: str) -> int: url = "http://" + address + "/shelly" - app = None generation = 1 device_info = req.get_http_session().get(url, timeout=3).json() - if 'app' in device_info: - app = int(device_info['app']) if 'gen' in device_info: generation = int(device_info['gen']) - if generation == 2 and app == "Pro3EM": - return 3 - else: - return generation + return generation def create_device(device_config: Shelly) -> ConfigurableDevice: def create_inverter_component(component_config: ShellyInverterSetup) -> ShellyInverter: return ShellyInverter(device_config.id, component_config, device_config.configuration.ip_address, - device_config.configuration.type) + device_config.configuration.generation) - if device_config.configuration.type is None and device_config.configuration.ip_address is not None: - device_config.configuration.type = get_device_type(device_config.configuration.ip_address) + if device_config.configuration.generation is None and device_config.configuration.ip_address is not None: + device_config.configuration.generation = get_device_generation(device_config.configuration.ip_address) return ConfigurableDevice( device_config=device_config, @@ -72,7 +66,7 @@ def read_legacy_inverter(address: str, num: int) -> None: with open(generation_file_name, 'r') as file: generation = int(file.read()) else: - generation = get_device_type(address) + generation = get_device_generation(address) with open(generation_file_name, 'w') as file: file.write(str(generation)) run_device_legacy(create_legacy_device_config(address, generation, diff --git a/packages/modules/devices/shelly/inverter.py b/packages/modules/devices/shelly/inverter.py index 467c38c7d2..e2131cf325 100644 --- a/packages/modules/devices/shelly/inverter.py +++ b/packages/modules/devices/shelly/inverter.py @@ -18,23 +18,23 @@ def __init__(self, device_id: int, component_config: ShellyInverterSetup, address: str, - type: Optional[int]) -> None: + generation: Optional[int]) -> None: self.component_config = component_config self.sim_counter = SimCounter(device_id, self.component_config.id, prefix="pv") self.store = get_inverter_value_store(self.component_config.id) self.fault_state = FaultState(ComponentInfo.from_component_config(self.component_config)) self.address = address - self.type = type + self.generation = generation def total_power_from_shelly(self) -> int: total = 0 - if self.type == 1: + 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.type == 1: + if self.generation == 1: if 'meters' in status: meters = status['meters'] # shelly else: @@ -42,10 +42,11 @@ def total_power_from_shelly(self) -> int: # shellyEM has one meter, shelly3EM has three meters: for meter in meters: total = total + meter['power'] - elif self.type == 2: - total = status['switch:0']['apower'] else: - total = status['em:0']['total_act_power'] + if 'switch:0' in status: + total = status['switch:0']['apower'] + else: + total = status['em:0']['total_act_power'] # shelly Pro3EM except KeyError: log.exception("unsupported shelly device?") finally: