Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 12 additions & 15 deletions packages/modules/devices/shelly/shelly/bat.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from modules.common.store import get_bat_value_store
from modules.common.simcount._simcounter import SimCounter
from modules.devices.shelly.shelly.config import ShellyBatSetup
from modules.devices.shelly.shelly.constants import ALPHABETICAL_INDEX

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -37,40 +38,36 @@ def initialize(self) -> None:
self.fault_state = FaultState(ComponentInfo.from_component_config(self.component_config))

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:
alphabetical_index = ['a', 'b', 'c']
power = 0
currents = [0.0, 0.0, 0.0]
# GEN 1
if "meters" in status:
meters = status['meters'] # einphasiger shelly?
for i in range(len(meters)):
currents[(i+self.phase-1) % 3] = ((float(meters[i]['power']) * self.factor) / 230
if meters[i].get('power') else 0)
power = power + (float(meters[i]['power'] * self.factor))
for i in range(0, min(3, len(meters))):
currents[(i+self.phase-1) % 3] = (float(meters[i].get('power', 0)) * self.factor) / 230
power = power + (float(meters[i].get('power', 0)) * self.factor)
elif "emeters" in status:
meters = status['emeters'] # shellyEM & shelly3EM
# shellyEM has one meter, shelly3EM has three meters
for i in range(len(meters)):
currents[(i+self.phase-1) % 3] = (float(meters[i]['current']) * self.factor
if meters[i].get('current') else 0)
power = power + (float(meters[i]['power'] * self.factor))
for i in range(0, min(3, len(meters))):
currents[(i+self.phase-1) % 3] = float(meters[i].get('current', 0)) * self.factor
power = power + float(meters[i].get('power', 0)) * self.factor
# GEN 2+
# shelly Pro3EM
elif "em:0" in status:
meters = status['em:0']
for i in range(0, 3):
if meters.get(f'{alphabetical_index[i]}_current') is None:
for i, alphabetical_index in enumerate(ALPHABETICAL_INDEX):
if meters.get(f'{alphabetical_index}_current') is None:
continue
currents[(i+self.phase-1) % 3] = (float(meters[f'{alphabetical_index[i]}_current']) * self.factor
if meters.get(f'{alphabetical_index[i]}_current') else 0)
power = float(meters['total_act_power']) * self.factor
currents[(i+self.phase-1) % 3] = float(meters.get(f'{alphabetical_index}_current', 0)) * self.factor
power = float(meters.get('total_act_power', 0)) * self.factor
# Shelly MiniPM G3
elif "pm1:0" in status:
log.debug("single phase shelly")
Expand Down
1 change: 1 addition & 0 deletions packages/modules/devices/shelly/shelly/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALPHABETICAL_INDEX = ['a', 'b', 'c']
41 changes: 16 additions & 25 deletions packages/modules/devices/shelly/shelly/counter.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from modules.common.store import get_counter_value_store
from modules.common.simcount._simcounter import SimCounter
from modules.devices.shelly.shelly.config import ShellyCounterSetup
from modules.devices.shelly.shelly.constants import ALPHABETICAL_INDEX

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -45,14 +46,12 @@ def update(self) -> None:
status = req.get_http_session().get(status_url, timeout=3).json()
try:
# GEN 1
alphabetical_index = ['a', 'b', 'c']
if "meters" in status:
powers = [0.0, 0.0, 0.0]
voltages = [0.0, 0.0, 0.0]
meters = status['meters'] # einphasiger shelly?
for i in range(len(meters)):
powers[(i+self.phase-1) % 3] = (float(meters[i]['power']) * self.factor
if meters[i].get('power') else 0)
for i in range(0, min(3, len(meters))):
powers[(i+self.phase-1) % 3] = float(meters[i].get('power', 0)) * self.factor
Comment on lines +53 to +54

Copilot AI Mar 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description and referenced issue state that the bug occurs with devices that have more than 3 entries in their meters or emeters array (e.g., Shelly 3EM-63 Gen3 which may include extra non-phase entries). The core fix — capping iteration at 3 with min(3, len(meters)) — is not covered by any new test case. Given that the test file (shelly_test.py) has comprehensive parametrized test cases for all existing device types and scenarios, a test case using a meters/emeters list with more than 3 items would be needed to verify the fix and prevent regressions.

Copilot uses AI. Check for mistakes.
voltages[(i+self.phase-1) % 3] = 230
power = sum(powers)
elif "emeters" in status:
Expand All @@ -62,15 +61,11 @@ def update(self) -> None:
power_factors = [0.0, 0.0, 0.0]
meters = status['emeters'] # shellyEM & shelly3EM
# shellyEM has one meter, shelly3EM has three meters
for i in range(len(meters)):
powers[(i+self.phase-1) % 3] = (float(meters[i]['power']) * self.factor
if meters[i].get('power') else 0)
currents[(i+self.phase-1) % 3] = (float(meters[i]['current']) * self.factor
if meters[i].get('current') else 0)
voltages[(i+self.phase-1) % 3] = (float(meters[i]['voltage'])
if meters[i].get('voltage') else 0)
power_factors[(i+self.phase-1) % 3] = (float(meters[i]['pf'])
if meters[i].get('pf') else 0)
for i in range(0, min(3, len(meters))):
powers[(i+self.phase-1) % 3] = float(meters[i].get('power', 0)) * self.factor
currents[(i+self.phase-1) % 3] = float(meters[i].get('current', 0)) * self.factor
voltages[(i+self.phase-1) % 3] = float(meters[i].get('voltage', 0))
power_factors[(i+self.phase-1) % 3] = float(meters[i].get('pf', 0))
power = sum(powers)

# GEN 2+
Expand All @@ -81,18 +76,14 @@ def update(self) -> None:
voltages = [0.0, 0.0, 0.0]
power_factors = [0.0, 0.0, 0.0]
meters = status['em:0']
for i in range(0, 3):
if meters.get(f'{alphabetical_index[i]}_act_power') is None:
for i, alphabetical_index in enumerate(ALPHABETICAL_INDEX):
if meters.get(f'{alphabetical_index}_act_power') is None:
continue
powers[(i+self.phase-1) % 3] = (float(meters[f'{alphabetical_index[i]}_act_power']) * self.factor
if meters.get(f'{alphabetical_index[i]}_act_power') else 0)
voltages[(i+self.phase-1) % 3] = (float(meters[f'{alphabetical_index[i]}_voltage'])
if meters.get(f'{alphabetical_index[i]}_voltage') else 0)
currents[(i+self.phase-1) % 3] = (float(meters[f'{alphabetical_index[i]}_current']) * self.factor
if meters.get(f'{alphabetical_index[i]}_current') else 0)
power_factors[(i+self.phase-1) % 3] = (float(meters[f'{alphabetical_index[i]}_pf'])
if meters.get(f'{alphabetical_index[i]}_pf') else 0)
power = float(meters['total_act_power']) * self.factor
powers[(i+self.phase-1) % 3] = float(meters.get(f'{alphabetical_index}_act_power', 0)) * self.factor
voltages[(i+self.phase-1) % 3] = float(meters.get(f'{alphabetical_index}_voltage', 0))
currents[(i+self.phase-1) % 3] = float(meters.get(f'{alphabetical_index}_current', 0)) * self.factor
power_factors[(i+self.phase-1) % 3] = float(meters.get(f'{alphabetical_index}_pf', 0))
power = float(meters.get('total_act_power', 0)) * self.factor
# Shelly MiniPM G3
elif "pm1:0" in status:
log.debug("single phase shelly")
Expand All @@ -104,7 +95,7 @@ def update(self) -> None:
powers[self.phase-1] = meters['apower'] * self.factor
voltages[self.phase-1] = meters['voltage']
currents[self.phase-1] = meters['current'] * self.factor
power_factors[self.phase-1] = meters['pf'] if meters.get('pf') else 0
power_factors[self.phase-1] = meters.get('pf', 0)
power = meters['apower'] * self.factor
frequency = meters['freq']
elif 'switch:0' in status and 'apower' in status['switch:0']:
Expand Down
25 changes: 11 additions & 14 deletions packages/modules/devices/shelly/shelly/inverter.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from modules.common.store import get_inverter_value_store
from modules.common.simcount._simcounter import SimCounter
from modules.devices.shelly.shelly.config import ShellyInverterSetup
from modules.devices.shelly.shelly.constants import ALPHABETICAL_INDEX

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -44,32 +45,28 @@ def update(self) -> None:
status_url = "http://" + self.address + "/rpc/Shelly.GetStatus"
status = req.get_http_session().get(status_url, timeout=3).json()
try:
alphabetical_index = ['a', 'b', 'c']
currents = [0.0, 0.0, 0.0]
# GEN 1
if "meters" in status:
meters = status['meters'] # einphasiger shelly?
for i in range(len(meters)):
currents[(i+self.phase-1) % 3] += ((float(meters[i]['power']) * self.factor) / 230
if meters[i].get('power') else 0)
power = power + (float(meters[i]['power'] * self.factor))
for i in range(0, min(3, len(meters))):
currents[(i+self.phase-1) % 3] += (float(meters[i].get('power', 0)) * self.factor) / 230
power = power + float(meters[i].get('power', 0)) * self.factor
elif "emeters" in status:
meters = status['emeters'] # shellyEM & shelly3EM
# shellyEM has one meter, shelly3EM has three meters
for i in range(len(meters)):
currents[(i+self.phase-1) % 3] = (float(meters[i]['current']) * self.factor
if meters[i].get('current') else 0)
power = power + (float(meters[i]['power'] * self.factor))
for i in range(0, min(3, len(meters))):
currents[(i+self.phase-1) % 3] = float(meters[i].get('current', 0)) * self.factor
power = power + float(meters[i].get('power', 0)) * self.factor
# GEN 2+
# shelly Pro3EM
elif "em:0" in status:
meters = status['em:0']
for i in range(len(meters)):
if meters.get(f'{alphabetical_index[i]}_current') is None:
for i, alphabetical_index in enumerate(ALPHABETICAL_INDEX):
if meters.get(f'{alphabetical_index}_current') is None:
continue
currents[(i+self.phase-1) % 3] = (float(meters[f'{alphabetical_index[i]}_current']) * self.factor
if meters.get(f'{alphabetical_index[i]}_current') else 0)
power = float(meters['total_act_power']) * self.factor
currents[(i+self.phase-1) % 3] = float(meters.get(f'{alphabetical_index}_current', 0)) * self.factor
power = float(meters.get('total_act_power', 0)) * self.factor
# Shelly MiniPM G3
elif "pm1:0" in status:
log.debug("single phase shelly")
Expand Down