Skip to content

Commit a609bc5

Browse files
feat: validate temperature range and timer duration in CLI set commands (#56)
* feat: add input validation for heat-temp and timer CLI commands Co-authored-by: deviantintegral <255023+deviantintegral@users.noreply.github.com> * refactor: remove try/except from _set_heat_temp to match existing handler pattern Co-authored-by: deviantintegral <255023+deviantintegral@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: deviantintegral <255023+deviantintegral@users.noreply.github.com>
1 parent 0e96bd7 commit a609bc5

File tree

3 files changed

+67
-4
lines changed

3 files changed

+67
-4
lines changed

src/flameconnect/cli.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,13 @@
2020
DEFAULT_TARGET_TEMPERATURE,
2121
MAX_BOOST_DURATION,
2222
MAX_FLAME_SPEED,
23+
MAX_TEMP_CELSIUS,
24+
MAX_TEMP_FAHRENHEIT,
25+
MAX_TIMER_DURATION,
2326
MIN_BOOST_DURATION,
2427
MIN_FLAME_SPEED,
28+
MIN_TEMP_CELSIUS,
29+
MIN_TEMP_FAHRENHEIT,
2530
)
2631
from flameconnect.models import (
2732
NAMED_COLORS,
@@ -566,11 +571,24 @@ async def _set_heat_temp(client: FlameConnectClient, fire_id: str, value: str) -
566571
"""Set the heater setpoint temperature."""
567572
temp = float(value)
568573
overview = await client.get_fire_overview(fire_id)
574+
temp_unit_param = _find_param(overview.parameters, TempUnitParam)
575+
unit = temp_unit_param.unit if temp_unit_param else TempUnit.CELSIUS
576+
if unit == TempUnit.FAHRENHEIT:
577+
min_temp, max_temp = MIN_TEMP_FAHRENHEIT, MAX_TEMP_FAHRENHEIT
578+
else:
579+
min_temp, max_temp = MIN_TEMP_CELSIUS, MAX_TEMP_CELSIUS
580+
if not (min_temp <= temp <= max_temp):
581+
unit_suffix = temp_suffix(temp_unit_param)
582+
print(
583+
f"Error: heat-temp must be between"
584+
f" {min_temp} and {max_temp}\u00b0{unit_suffix}."
585+
)
586+
sys.exit(1)
569587
current = _find_param(overview.parameters, HeatParam)
570588
if current is None:
571589
print("Error: no HeatSettings parameter found.")
572590
sys.exit(1)
573-
unit_suffix = temp_suffix(_find_param(overview.parameters, TempUnitParam))
591+
unit_suffix = temp_suffix(temp_unit_param)
574592
new_param = replace(current, setpoint_temperature=temp)
575593
await client.write_parameters(fire_id, [new_param])
576594
print(f"Heat temperature set to {temp}\u00b0{unit_suffix}.")
@@ -582,6 +600,9 @@ async def _set_timer(client: FlameConnectClient, fire_id: str, value: str) -> No
582600
if minutes < 0:
583601
print("Error: timer must be non-negative (0 to disable).")
584602
sys.exit(1)
603+
if minutes > MAX_TIMER_DURATION:
604+
print(f"Error: timer must not exceed {MAX_TIMER_DURATION} minutes.")
605+
sys.exit(1)
585606
timer_status = TimerStatus.ENABLED if minutes > 0 else TimerStatus.DISABLED
586607
timer_param = TimerParam(timer_status=timer_status, duration=minutes)
587608
await client.write_parameters(fire_id, [timer_param])

tests/test_cli_commands.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,9 +1219,9 @@ async def test_heat_temp_with_fahrenheit_suffix(self, capsys):
12191219
],
12201220
)
12211221
client.get_fire_overview.return_value = overview
1222-
await cmd_set(client, FIRE_ID, "heat-temp", "25.0")
1222+
await cmd_set(client, FIRE_ID, "heat-temp", "72.0")
12231223
out = capsys.readouterr().out
1224-
assert "25.0\u00b0F" in out
1224+
assert "72.0\u00b0F" in out
12251225

12261226

12271227
# ===================================================================

tests/test_cli_set.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,12 @@
2323
cmd_set,
2424
)
2525
from flameconnect.client import FlameConnectClient
26-
from flameconnect.const import API_BASE
26+
from flameconnect.const import (
27+
API_BASE,
28+
MAX_TEMP_CELSIUS,
29+
MAX_TIMER_DURATION,
30+
MIN_TEMP_CELSIUS,
31+
)
2732
from flameconnect.models import RGBWColor
2833

2934
FIXTURES_DIR = Path(__file__).parent / "fixtures"
@@ -481,6 +486,35 @@ async def test_set_heat_temp(self, mock_api, token_auth, overview_payload):
481486
body = calls[0].kwargs["json"]
482487
assert body["Parameters"][0]["ParameterId"] == 323
483488

489+
async def test_set_heat_temp_too_low(
490+
self, mock_api, token_auth, overview_payload, capsys
491+
):
492+
mock_api.get(OVERVIEW_URL, payload=overview_payload)
493+
494+
async with FlameConnectClient(token_auth) as client:
495+
with pytest.raises(SystemExit):
496+
await _set_heat_temp(client, FIRE_ID, str(MIN_TEMP_CELSIUS - 1))
497+
captured = capsys.readouterr()
498+
assert "Error" in captured.out
499+
assert str(MIN_TEMP_CELSIUS) in captured.out
500+
501+
async def test_set_heat_temp_too_high(
502+
self, mock_api, token_auth, overview_payload, capsys
503+
):
504+
mock_api.get(OVERVIEW_URL, payload=overview_payload)
505+
506+
async with FlameConnectClient(token_auth) as client:
507+
with pytest.raises(SystemExit):
508+
await _set_heat_temp(client, FIRE_ID, str(MAX_TEMP_CELSIUS + 1))
509+
captured = capsys.readouterr()
510+
assert "Error" in captured.out
511+
assert str(MAX_TEMP_CELSIUS) in captured.out
512+
513+
async def test_set_heat_temp_not_a_number(self, mock_api, token_auth):
514+
async with FlameConnectClient(token_auth) as client:
515+
with pytest.raises(ValueError):
516+
await _set_heat_temp(client, FIRE_ID, "hot")
517+
484518

485519
# ---------------------------------------------------------------------------
486520
# _set_timer
@@ -518,6 +552,14 @@ async def test_set_timer_negative(self, mock_api, token_auth, capsys):
518552
captured = capsys.readouterr()
519553
assert "Error" in captured.out
520554

555+
async def test_set_timer_exceeds_max(self, mock_api, token_auth, capsys):
556+
async with FlameConnectClient(token_auth) as client:
557+
with pytest.raises(SystemExit):
558+
await _set_timer(client, FIRE_ID, str(MAX_TIMER_DURATION + 1))
559+
captured = capsys.readouterr()
560+
assert "Error" in captured.out
561+
assert str(MAX_TIMER_DURATION) in captured.out
562+
521563

522564
# ---------------------------------------------------------------------------
523565
# cmd_set dispatch

0 commit comments

Comments
 (0)