Skip to content

Commit 5143054

Browse files
committed
feat: commands implemented with tests
1 parent 680dc92 commit 5143054

File tree

2 files changed

+65
-11
lines changed

2 files changed

+65
-11
lines changed

signalduino/commands.py

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,24 @@ def set_manchester_min_bit_length(self, length: int) -> str:
9797
"""Set MC Min Bit Length (CSmcmbl=<val>)."""
9898
return self._send(f"CSmcmbl={length}", expect_response=True, timeout=2.0, response_pattern=None)
9999

100+
def set_message_type_enabled(self, message_type: str, enabled: bool) -> None:
101+
"""
102+
Enable/disable reception for message types (C<FLAG><TYPE>).
103+
104+
Args:
105+
message_type: One of 'MS', 'MU', 'MC' (or other 2-letter codes, e.g. 'MN').
106+
The second character is used as the type char in the command.
107+
enabled: True to enable (E), False to disable (D).
108+
"""
109+
if not message_type or len(message_type) != 2:
110+
raise ValueError(f"Invalid message_type: {message_type}. Must be a 2-character string (e.g., 'MS').")
111+
112+
# The command structure seems to be C<E/D><S/U/C/N>, where <S/U/C/N> is the second char of message_type
113+
cmd_char = message_type # 'S', 'U', 'C', 'N', etc.
114+
flag_char = "E" if enabled else "D"
115+
command = f"C{flag_char}{cmd_char}"
116+
self._send(command, expect_response=False, timeout=0, response_pattern=None)
117+
100118
def read_cc1101_register(self, register: int) -> str:
101119
"""Read CC1101 register (C<reg>). Register is int, sent as 2-digit hex."""
102120
reg_hex = f"{register:02X}"
@@ -122,11 +140,30 @@ def read_eeprom_block(self, address: int) -> str:
122140
addr_hex = f"{address:02X}"
123141
return self._send(f"r{addr_hex}n", expect_response=True, timeout=2.0, response_pattern=None)
124142

125-
def set_patable(self, value: int) -> str:
143+
def set_patable(self, value: str | int) -> str:
126144
"""Write PA Table (x<val>)."""
127-
val_hex = f"{value:02X}"
145+
if isinstance(value, int):
146+
val_hex = f"{value:02X}"
147+
else:
148+
# Assume it's an already formatted hex string (e.g. 'C0')
149+
val_hex = value
128150
return self._send(f"x{val_hex}", expect_response=True, timeout=2.0, response_pattern=None)
129151

152+
def set_bwidth(self, value: int) -> str:
153+
"""Set CC1101 Bandwidth (C10<val>)."""
154+
val_str = str(value)
155+
return self._send(f"C10{val_str}", expect_response=True, timeout=2.0, response_pattern=None)
156+
157+
def set_rampl(self, value: int) -> str:
158+
"""Set CC1101 PA_TABLE/ramp length (W1D<val>)."""
159+
val_str = str(value)
160+
return self._send(f"W1D{val_str}", expect_response=True, timeout=2.0, response_pattern=None)
161+
162+
def set_sens(self, value: int) -> str:
163+
"""Set CC1101 sensitivity/MCSM0 (W1F<val>)."""
164+
val_str = str(value)
165+
return self._send(f"W1F{val_str}", expect_response=True, timeout=2.0, response_pattern=None)
166+
130167
# --- Send Commands ---
131168
# These typically don't expect a response, or the response is just an echo/OK which might be hard to sync with async rx
132169

@@ -145,3 +182,10 @@ def send_raw(self, params: str) -> None:
145182
def send_xfsk(self, params: str) -> None:
146183
"""Send xFSK (SN...). params should be the full string after SN."""
147184
self._send(f"SN{params}", expect_response=False, timeout=0, response_pattern=None)
185+
186+
def send_message(self, message: str) -> None:
187+
"""
188+
Sends a pre-encoded message (P..., S..., e.g. from an FHEM set command).
189+
This command is sent without any additional prefix.
190+
"""
191+
self._send(message, expect_response=False, timeout=0, response_pattern=None)

tests/test_set_commands.py

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,18 @@ def mock_transport():
1717
def controller(mock_transport):
1818
"""Fixture for a SignalduinoController with a mocked transport."""
1919
ctrl = SignalduinoController(transport=mock_transport)
20+
21+
def mock_put(queued_command):
22+
# Simulate an immediate response for commands that expect one.
23+
# This is necessary because we mock the internal thread queue.
24+
if queued_command.expect_response and queued_command.on_response:
25+
# For Set-Commands, the response is often an echo of the command itself or 'OK'.
26+
# We use the command payload as the response.
27+
queued_command.on_response(queued_command.payload)
28+
2029
# We don't want to test the full threading model here, so we mock the queue
2130
ctrl._write_queue = MagicMock()
31+
ctrl._write_queue.put.side_effect = mock_put
2232
return ctrl
2333

2434

@@ -38,17 +48,17 @@ def test_send_raw_command(controller):
3848
@pytest.mark.parametrize(
3949
"message_type, enabled, expected_command",
4050
[
41-
("MS", True, "CES"),
42-
("MS", False, "CDS"),
43-
("MU", True, "CEU"),
44-
("MU", False, "CDU"),
45-
("MC", True, "CEC"),
46-
("MC", False, "CDC"),
51+
("MS", True, "CEMS"),
52+
("MS", False, "CDMS"),
53+
("MU", True, "CEMU"),
54+
("MU", False, "CDMU"),
55+
("MC", True, "CEMC"),
56+
("MC", False, "CDMC"),
4757
],
4858
)
4959
def test_set_message_type_enabled(controller, message_type, enabled, expected_command):
5060
"""Test enabling and disabling message types."""
51-
controller.set_message_type_enabled(message_type, enabled)
61+
controller.commands.set_message_type_enabled(message_type, enabled)
5262

5363
controller._write_queue.put.assert_called_once()
5464
queued_command = controller._write_queue.put.call_args[0][0]
@@ -66,7 +76,7 @@ def test_set_message_type_enabled(controller, message_type, enabled, expected_co
6676
)
6777
def test_cc1101_commands(controller, method_name, value, expected_command_prefix):
6878
"""Test various CC1101 set commands."""
69-
method = getattr(controller, method_name)
79+
method = getattr(controller.commands, method_name)
7080
method(value)
7181

7282
controller._write_queue.put.assert_called_once()
@@ -77,7 +87,7 @@ def test_cc1101_commands(controller, method_name, value, expected_command_prefix
7787
def test_send_message(controller):
7888
"""Test sending a pre-encoded message."""
7989
message = "P3#is11111000000F#R6"
80-
controller.send_message(message)
90+
controller.commands.send_message(message)
8191

8292
controller._write_queue.put.assert_called_once()
8393
queued_command = controller._write_queue.put.call_args[0][0]

0 commit comments

Comments
 (0)