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
9 changes: 6 additions & 3 deletions packages/modules/devices/shelly/shelly/status_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,13 @@ def parse_temperatures(status: Dict, generation: int) -> Optional[List[float]]:
for index in range(3):
try:
if generation == 1:
value = status['ext_temperature'][str(index)]['tC']
entry = status['ext_temperature'][str(index)]
else:
value = status[f'temperature:{100 + index}']['tC']
temperatures.append(float(value))
entry = status[f'temperature:{100 + index}']
except (KeyError, TypeError):
continue
try:
temperatures.append(float(entry['tC']))
except (KeyError, TypeError, ValueError):
log.exception(f"Error parsing temperature for index {index} in status: {status}")
return temperatures if len(temperatures) > 0 else None
Expand Down
65 changes: 65 additions & 0 deletions packages/modules/devices/shelly/shelly/status_handler_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import logging

from modules.devices.shelly.shelly.status_handler import parse_temperatures

# real status dump from a Shelly Plug S without external temp probes attached (Discussion #3466,
# discussioncomment-19500699): ext_temperature is an empty dict, not missing/malformed data
GEN1_STATUS_WITHOUT_EXT_SENSORS = {
"temperature": 38.73,
"tmp": {"tC": 38.73, "tF": 101.71, "is_valid": True},
"ext_sensors": {},
"ext_temperature": {},
"ext_humidity": {},
}


def test_parse_temperatures_returns_none_without_logging_error_when_no_ext_sensors(caplog):
with caplog.at_level(logging.ERROR):
result = parse_temperatures(GEN1_STATUS_WITHOUT_EXT_SENSORS, generation=1)

assert result is None
assert caplog.records == []


def test_parse_temperatures_gen1_reads_available_ext_sensors():
status = {"ext_temperature": {"0": {"tC": 21.5}, "2": {"tC": 22.1}}}

result = parse_temperatures(status, generation=1)

assert result == [21.5, 22.1]


def test_parse_temperatures_still_logs_on_genuinely_malformed_value(caplog):
status = {"ext_temperature": {"0": {"tC": "not-a-number"}}}

with caplog.at_level(logging.ERROR):
result = parse_temperatures(status, generation=1)

assert result is None
assert len(caplog.records) == 1


def test_parse_temperatures_logs_when_entry_present_but_missing_tc(caplog):
status = {"ext_temperature": {"0": {"hwID": "28FF"}}}

with caplog.at_level(logging.ERROR):
result = parse_temperatures(status, generation=1)

assert result is None
assert len(caplog.records) == 1


def test_parse_temperatures_logs_instead_of_raising_when_entry_is_not_a_mapping():
status = {"ext_temperature": {"0": 21.5}}

result = parse_temperatures(status, generation=1)

assert result is None


def test_parse_temperatures_gen2_without_ext_sensors_does_not_log(caplog):
with caplog.at_level(logging.ERROR):
result = parse_temperatures({}, generation=2)

assert result is None
assert caplog.records == []