Skip to content

Commit 380024a

Browse files
feat: display fire feature flags in CLI status output
Add _display_features() to cli.py that shows all 24 feature flags with Yes/No values in the status command output. The Supported Features section appears after connection state and before the parameter list. Add tests for the display function and its integration into cmd_status. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 8ed0c38 commit 380024a

2 files changed

Lines changed: 116 additions & 0 deletions

File tree

src/flameconnect/cli.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from flameconnect.models import (
1616
NAMED_COLORS,
1717
ErrorParam,
18+
FireFeatures,
1819
FireMode,
1920
FlameColor,
2021
FlameEffect,
@@ -345,6 +346,43 @@ def _display_log_effect(param: LogEffectParam) -> None:
345346
print(f" Pattern: {param.pattern}")
346347

347348

349+
_FEATURE_LABELS: list[tuple[str, str]] = [
350+
("sound", "Sound"),
351+
("simple_heat", "Simple Heat"),
352+
("advanced_heat", "Advanced Heat"),
353+
("seven_day_timer", "7-Day Timer"),
354+
("count_down_timer", "Countdown Timer"),
355+
("moods", "Moods"),
356+
("flame_height", "Flame Height"),
357+
("rgb_flame_accent", "RGB Flame Accent"),
358+
("flame_dimming", "Flame Dimming"),
359+
("rgb_fuel_bed", "RGB Fuel Bed"),
360+
("fuel_bed_dimming", "Fuel Bed Dimming"),
361+
("flame_fan_speed", "Flame Fan Speed"),
362+
("rgb_back_light", "RGB Back Light"),
363+
("front_light_amber", "Front Light Amber"),
364+
("pir_toggle_smart_sense", "PIR Smart Sense"),
365+
("lgt1_to_5", "LGT 1-5"),
366+
("requires_warm_up", "Requires Warm Up"),
367+
("apply_flame_only_first", "Apply Flame Only First"),
368+
("flame_amber", "Flame Amber"),
369+
("check_if_remote_was_used", "Check If Remote Was Used"),
370+
("media_accent", "Media Accent"),
371+
("power_boost", "Power Boost"),
372+
("fan_only", "Fan Only"),
373+
("rgb_log_effect", "RGB Log Effect"),
374+
]
375+
376+
377+
def _display_features(features: FireFeatures) -> None:
378+
"""Display supported feature flags."""
379+
print("\n Supported Features")
380+
print(f" {'─' * 40}")
381+
for field_name, label in _FEATURE_LABELS:
382+
value = "Yes" if getattr(features, field_name) else "No"
383+
print(f" {label + ':':<28s}{value}")
384+
385+
348386
def _display_parameter(
349387
param: Parameter,
350388
temp_unit: TempUnitParam | None = None,
@@ -401,6 +439,7 @@ async def cmd_status(client: FlameConnectClient, fire_id: str) -> None:
401439
print(f"Fireplace: {fire.friendly_name} ({fire.fire_id})")
402440
state = _enum_name(_CONNECTION_STATE_NAMES, fire.connection_state)
403441
print(f"Connection: {state}")
442+
_display_features(fire.features)
404443

405444
if not overview.parameters:
406445
print("\nNo parameters returned (fireplace may be offline).")

tests/test_cli_commands.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from flameconnect.cli import (
1212
_convert_temp,
1313
_display_error,
14+
_display_features,
1415
_display_flame_effect,
1516
_display_heat,
1617
_display_heat_mode,
@@ -40,6 +41,7 @@
4041
ConnectionState,
4142
ErrorParam,
4243
Fire,
44+
FireFeatures,
4345
FireMode,
4446
FireOverview,
4547
FlameColor,
@@ -673,6 +675,81 @@ async def test_connection_state_displayed(self, capsys):
673675
out = capsys.readouterr().out
674676
assert "Updating Firmware" in out
675677

678+
async def test_features_displayed(self, capsys):
679+
client = AsyncMock()
680+
features = FireFeatures(sound=True, advanced_heat=True)
681+
fire = _make_fire(features=features)
682+
overview = FireOverview(fire=fire, parameters=[_make_mode_param()])
683+
client.get_fire_overview.return_value = overview
684+
await cmd_status(client, FIRE_ID)
685+
out = capsys.readouterr().out
686+
assert "Supported Features" in out
687+
assert "Sound:" in out
688+
assert "Advanced Heat:" in out
689+
690+
async def test_features_displayed_when_offline(self, capsys):
691+
"""Features section appears even when no parameters returned."""
692+
client = AsyncMock()
693+
features = FireFeatures(flame_height=True)
694+
fire = _make_fire(features=features)
695+
overview = FireOverview(fire=fire, parameters=[])
696+
client.get_fire_overview.return_value = overview
697+
await cmd_status(client, FIRE_ID)
698+
out = capsys.readouterr().out
699+
assert "Supported Features" in out
700+
assert "Flame Height:" in out
701+
702+
703+
class TestDisplayFeatures:
704+
"""Tests for _display_features()."""
705+
706+
def test_all_false(self, capsys):
707+
_display_features(FireFeatures())
708+
out = capsys.readouterr().out
709+
assert "Supported Features" in out
710+
# All should show No
711+
assert "Yes" not in out
712+
assert out.count("No") == 24
713+
714+
def test_some_true(self, capsys):
715+
features = FireFeatures(sound=True, simple_heat=True, rgb_log_effect=True)
716+
_display_features(features)
717+
out = capsys.readouterr().out
718+
assert out.count("Yes") == 3
719+
assert out.count("No") == 21
720+
721+
def test_all_labels_present(self, capsys):
722+
_display_features(FireFeatures())
723+
out = capsys.readouterr().out
724+
expected_labels = [
725+
"Sound:",
726+
"Simple Heat:",
727+
"Advanced Heat:",
728+
"7-Day Timer:",
729+
"Countdown Timer:",
730+
"Moods:",
731+
"Flame Height:",
732+
"RGB Flame Accent:",
733+
"Flame Dimming:",
734+
"RGB Fuel Bed:",
735+
"Fuel Bed Dimming:",
736+
"Flame Fan Speed:",
737+
"RGB Back Light:",
738+
"Front Light Amber:",
739+
"PIR Smart Sense:",
740+
"LGT 1-5:",
741+
"Requires Warm Up:",
742+
"Apply Flame Only First:",
743+
"Flame Amber:",
744+
"Check If Remote Was Used:",
745+
"Media Accent:",
746+
"Power Boost:",
747+
"Fan Only:",
748+
"RGB Log Effect:",
749+
]
750+
for label in expected_labels:
751+
assert label in out, f"Missing label: {label}"
752+
676753

677754
class TestCmdOn:
678755
"""Tests for cmd_on()."""

0 commit comments

Comments
 (0)