Skip to content

Commit 4fc12ea

Browse files
author
sidey79
committed
feat: fhem container in devcontainer environment with basic configuration
1 parent 188de18 commit 4fc12ea

9 files changed

Lines changed: 312 additions & 24 deletions

File tree

.devcontainer/devcontainer.json

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
23
// README at: https://github.com/devcontainers/templates/tree/main/src/python
34
{
@@ -9,17 +10,9 @@
910
// Features to add to the dev container. More info: https://containers.dev/features.
1011
// "features": {},
1112
"features": {
12-
"ghcr.io/devcontainers/features/node:1": {
13-
"nodeGypDependencies": true,
14-
"installYarnUsingApt": true,
15-
"version": "lts",
16-
"pnpmVersion": "latest",
17-
"nvmVersion": "latest"
18-
},
19-
"ghcr.io/devcontainer-community/devcontainer-features/astral.sh-uv:1": {
20-
"shellautocompletion": true,
21-
"version": "latest"
22-
}
13+
"ghcr.io/devcontainers/features/node:1": {},
14+
"ghcr.io/devcontainer-community/devcontainer-features/astral.sh-uv:1": {},
15+
"ghcr.io/braun-daniel/devcontainer-features/asciidoc:1": {}
2316
//"ghcr.io/hspaans/devcontainer-features/pytest:2": {}
2417
},
2518
// Use 'forwardPorts' to make a list of ports inside the container available locally.

.devcontainer/docker-compose.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,18 @@ services:
2929
- ./mosquitto/log:/mosquitto/log
3030
command: mosquitto -c /mosquitto/config/mosquitto.conf
3131
restart: unless-stopped
32+
33+
fhem:
34+
image: ghcr.io/fhem/fhem-minimal-docker:5-bookworm
35+
container_name: fhem-dev-server
36+
ports:
37+
- '38083:8083' # Expose FHEM web interface on port 38083
38+
environment:
39+
- CONFIGTYPE=fhem_signalduino_example.cfg
40+
- FHEM_PERM_DIR=0777
41+
- FHEM_PERM_FILES=0777
42+
volumes:
43+
- ./fhem-data:/opt/fhem
44+
depends_on:
45+
- mqtt
46+
restart: unless-stopped
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
attr global userattr cmdIcon devStateIcon:textField-long devStateStyle icon sortby webCmd webCmdLabel:textField-long widgetOverride
2+
attr global autosave 0
3+
attr global logfile log/fhem-%Y-%m-%d.log
4+
attr global modpath .
5+
attr global nofork 0
6+
attr global pidfilename log/fhem.pid
7+
attr global statefile ./log/fhem.save
8+
attr global updateInBackground 1
9+
attr global verbose 3
10+
# FHEM Configuration for PySignalduino Dev Environment
11+
#
12+
# This file is loaded by the FHEM container via CONFIGTYPE environment variable.
13+
14+
15+
# 1. Define FHEMWEB instance to access FHEM via Browser (Port 8083)
16+
define WEB FHEMWEB 8083 global
17+
setuuid WEB 695e9c21-f33f-c986-956a-7e26fc9adfc69728
18+
attr WEB editConfig 1
19+
attr WEB stylesheetPrefix dark
20+
21+
# 2. Define Telnet for command line access (Optional)
22+
#define telnetPort telnet 7072 global
23+
24+
# 3. Basic Event Handling
25+
define eventTypes eventTypes ./log/eventTypes.txt
26+
setuuid eventTypes 695e9c21-f33f-c986-9ac3-190c47641a98acb9
27+
28+
# 4. Define the MQTT Client (Broker Connection)
29+
# 'mqtt' is the hostname of the broker service in docker-compose.yml
30+
define mqtt_broker MQTT2_CLIENT mqtt:1883
31+
setuuid mqtt_broker 695e9c21-f33f-c986-e617-d7301881c4685bc6
32+
attr mqtt_broker autocreate simple
33+
34+
# 5. Define the SignalDuino MQTT Device
35+
define PySignalDuino MQTT2_DEVICE
36+
setuuid PySignalDuino 695e9c21-f33f-c986-4f81-a9f0ab37b6bcedf8
37+
attr PySignalDuino IODev mqtt_broker
38+
attr PySignalDuino readingList signalduino/v1/state/messages:.* { json2nameValue($EVENT, 'MSG_',$JSONMAP) }\
39+
signalduino/v1/responses:.* { json2nameValue($EVENT, 'RESP_') }\
40+
signalduino/v1/errors:.* { json2nameValue($EVENT, 'ERR_') }
41+
attr PySignalDuino setList raw:textField signalduino/v1/commands/set/raw $EVTPART1 \
42+
cc1101_reg:textField signalduino/v1/commands/set/cc1101_reg $EVTPART1 \
43+
# System GET commands (noArg) \
44+
version:noArg signalduino/v1/commands/get/system/version \
45+
freeram:noArg signalduino/v1/commands/get/system/freeram \
46+
uptime:noArg signalduino/v1/commands/get/system/uptime \
47+
# Decoder state commands \
48+
decoder_state:noArg signalduino/v1/commands/get/config/decoder \
49+
decoder_ms_enable:noArg signalduino/v1/commands/set/config/decoder_ms_enable \
50+
decoder_ms_disable:noArg signalduino/v1/commands/set/config/decoder_ms_disable \
51+
decoder_mu_enable:noArg signalduino/v1/commands/set/config/decoder_mu_enable \
52+
decoder_mu_disable:noArg signalduino/v1/commands/set/config/decoder_mu_disable \
53+
decoder_mc_enable:noArg signalduino/v1/commands/set/config/decoder_mc_enable \
54+
decoder_mc_disable:noArg signalduino/v1/commands/set/config/decoder_mc_disable \
55+
# CC1101 GET commands (noArg) \
56+
cc_config:noArg signalduino/v1/commands/get/cc1101/config \
57+
cc_patable_get:noArg signalduino/v1/commands/get/cc1101/patable \
58+
cc_register:noArg signalduino/v1/commands/get/cc1101/register \
59+
cc_freq_get:noArg signalduino/v1/commands/get/cc1101/frequency \
60+
cc_bandwidth_get:noArg signalduino/v1/commands/get/cc1101/bandwidth \
61+
cc_rampl_get:noArg signalduino/v1/commands/get/cc1101/rampl \
62+
cc_sensitivity_get:noArg signalduino/v1/commands/get/cc1101/sensitivity \
63+
cc_datarate_get:noArg signalduino/v1/commands/get/cc1101/datarate \
64+
cc_settings_get:noArg signalduino/v1/commands/get/cc1101/settings \
65+
cc_deviation_get:noArg signalduino/v1/commands/get/cc1101/deviation\
66+
# CC1101 SET commands \
67+
cc_frequency_set:textField signalduino/v1/commands/set/cc1101/frequency $EVTPART1 \
68+
cc_rampl_set:select,24,27,30,33,36,38,40,42 signalduino/v1/commands/set/cc1101/rampl $EVTPART1 \
69+
cc_sensitivity_set:select,4,8,12,16 signalduino/v1/commands/set/cc1101/sensitivity $EVTPART1 \
70+
cc_patable_set:select,-30_dBm,-20_dBm,-15_dBm,-10_dBm,-5_dBm,0_dBm,5_dBm,7_dBm,10_dBm signalduino/v1/commands/set/cc1101/patable $EVTPART1 \
71+
cc_bandwidth_set:textField signalduino/v1/commands/set/cc1101/bandwidth $EVTPART1 \
72+
cc_datarate_set:textField signalduino/v1/commands/set/cc1101/datarate $EVTPART1 \
73+
cc_deviation_set:textField signalduino/v1/commands/set/cc1101/deviation $EVTPART1 \
74+
\
75+
# Maintenance commands \
76+
factory_reset:noArg signalduino/v1/commands/set/factory_reset
77+
attr PySignalDuino stateFormat state
78+
# Map JSON payload to readings
79+
# Define setter commands
80+
81+
# Logfile for SignalDuino
82+
define FileLog_PySignalDuino FileLog ./log/PySignalDuino-%Y.log PySignalDuino
83+
setuuid FileLog_PySignalDuino 695e9c21-f33f-c986-1981-abe9a5a366b3c989
84+
attr FileLog_PySignalDuino logtype text
85+
define Logfile FileLog /opt/fhem/log/fhem-%Y-%m-%d.log Logfile
86+
setuuid Logfile 695e9c21-f33f-c986-cfda-4915c3e60c145721

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,7 @@ SIGNALDuino-Firmware/
88
.devcontainer/.devcontainer.env
99
.devcontainer/mosquitto/data/
1010
.devcontainer/mosquitto/log/
11+
.devcontainer/fhem-data/*
12+
!.devcontainer/fhem-data/fhem_signalduino_example.cfg
13+
1114
.roo/mcp.json

docs/01_user_guide/mqtt_api.adoc

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,8 @@ GET-Befehle benötigen eine leere Payload (`{}`) oder nur eine `req_id`.
140140
| CC1101 PA-Tabelle.
141141

142142
| `get/cc1101/register`
143-
| `{"register_value": "C00 = 29"}`
144-
| Liest den Wert eines einzelnen CC1101-Registers (Adresse 0x00). Der Befehl nimmt keinen Wert in der Payload entgegen und liest standardmäßig Register 0x00.
143+
| `{"register_name": "IOCFG2", "address_hex": "00", "register_value": "C00 = 29"}`
144+
| Liest den Wert eines einzelnen CC1101-Registers. *Erfordert den Registernamen* im `value`-Feld der Payload (z.B. `{"value": "IOCFG2"}`).
145145

146146
| `get/cc1101/frequency`
147147
| `{"frequency": 868.3500}`
@@ -303,3 +303,37 @@ Dieser Befehl sendet eine vorab encodierte Nachricht an das Signalduino-Gerät,
303303
| Nein
304304
| Optionale Frequenz in MHz (`F<val>`).
305305
|===
306+
307+
[[_fhem_integration]]
308+
== FHEM Integration
309+
310+
PySignalduino lässt sich nahtlos in FHEM integrieren, indem ein MQTT-Broker als Vermittler genutzt wird. Die empfohlene Methode ist die Verwendung des FHEM-Moduls `MQTT2_CLIENT` zur Verbindung mit dem Broker und `MQTT2_DEVICE` zur Repräsentation des Signalduino.
311+
312+
=== Beispielkonfiguration
313+
314+
Eine vollständige Beispielkonfiguration finden Sie in der Datei `.devcontainer/fhem-data/fhem_signalduino_example.cfg`. Im DevContainer wird diese Datei automatisch als FHEM-Konfiguration geladen, sodass `PySignalDuino` sofort verfügbar ist.
315+
316+
[source,fhem]
317+
----
318+
# 1. Verbindung zum Broker herstellen (falls noch nicht vorhanden)
319+
define mqtt_broker MQTT2_CLIENT mqtt:1883
320+
attr mqtt_broker autocreate simple
321+
322+
# 2. PySignalduino Device definieren
323+
define PySignalDuino MQTT2_DEVICE
324+
attr PySignalDuino IODev mqtt_broker
325+
326+
# 3. Readings für empfangene Nachrichten extrahieren
327+
# Wandelt JSON-Payload automatisch in Readings um
328+
attr PySignalDuino readingList signalduino/v1/state/messages:.* { json2nameValue($EVENT, '', $JSONMAP) }
329+
330+
# 4. Senden von Befehlen ermöglichen
331+
attr PySignalDuino setList raw:textField signalduino/v1/commands/set/raw $EVTPART1 \
332+
cc1101_reg:textField signalduino/v1/commands/set/cc1101_reg $EVTPART1 \
333+
version:noArg signalduino/v1/commands/get/system/version
334+
----
335+
336+
=== Wichtige Hinweise
337+
338+
* **Topics:** Stellen Sie sicher, dass das `readingList` Attribut dem in PySignalduino konfigurierten `MQTT_TOPIC` entspricht (Standard: `signalduino/v1/state/messages`).
339+
* **JSON Parsing:** Die Funktion `json2nameValue` in FHEM ist ideal, um die flachen JSON-Objekte von PySignalduino direkt in FHEM Readings umzuwandeln.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Architekturproposal: FHEM-Integration über MQTT
2+
3+
## Zusammenfassung
4+
Die empfohlene Architektur für die Anbindung von PySignalduino an FHEM basiert auf der Nutzung eines zentralen MQTT-Brokers. PySignalduino agiert als MQTT-Publisher und Subscriber, während FHEM über das `MQTT_DEVICE` Modul die Daten von PySignalduino konsumiert und Steuerbefehle zurücksendet.
5+
6+
## Datenfluss-Diagramm
7+
8+
```mermaid
9+
flowchart TD
10+
A[SignalDuino Hardware] -->|Seriell/TCP| B(PySignalduino Anwendung);
11+
12+
subgraph MQTT Broker (z.B. Mosquitto)
13+
M(MQTT Broker);
14+
end
15+
16+
B -->|Publish (signalduino/messages/decoded/...)| M;
17+
B <--|Subscribe (signalduino/commands/#)| M;
18+
19+
C(FHEM Server) -->|Verbindet sich mit| M;
20+
C <--|Abonniert Topics| M;
21+
C -->|Sendet Steuerbefehle| M;
22+
23+
M -->|Topic: signalduino/messages/#| D[FHEM MQTT_DEVICE Modul];
24+
D -->|Internal FHEM Logic| C;
25+
C -->|Befehle publizieren| M;
26+
M -->|Topic: signalduino/commands/#| B;
27+
28+
style B fill:#f9f,stroke:#333
29+
style C fill:#ccf,stroke:#333
30+
style M fill:#ffa,stroke:#333
31+
32+
%% Datenfluss
33+
subgraph Datenfluss
34+
direction LR
35+
S1[PySignalduino publiziert] --> S2{MQTT Broker} --> S3[FHEM abonniert];
36+
end
37+
38+
%% Befehlsfluss
39+
subgraph Befehlsfluss
40+
direction LR
41+
S4[FHEM Steuerbefehl] --> S5{MQTT Broker} --> S6[PySignalduino Subscriber];
42+
end
43+
44+
B --> Datenfluss;
45+
B <-- Befehlsfluss;
46+
C --> Datenfluss;
47+
C <-- Befehlsfluss;
48+
```
49+
50+
## Implementierungsplan (TODO-Liste)
51+
Da die PySignalduino-Implementierung bereits vorhanden ist, konzentriert sich der Implementierungsplan auf die Erstellung von Dokumentation und Beispielen.
52+
53+
[x] Architektur-Entscheidung dokumentiert: Verwendung eines externen MQTT-Brokers für FHEM-Integration
54+
[x] Devcontainer-Konfiguration geprüft und als ausreichend befunden.
55+
[-] Mermaid-Diagramm zur Visualisierung des Datenflusses (PySignalduino <-> MQTT Broker <-> FHEM) erstellt.
56+
[ ] FHEM-spezifische Konfigurationsbeispiele in `docs/01_user_guide/mqtt.adoc` ergänzen.
57+
[ ] Plan dem Benutzer zur Genehmigung vorlegen und Moduswechsel zu 'code' vorschlagen.

signalduino/commands.py

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,21 @@
1616

1717
logger = logging.getLogger(__name__)
1818

19+
CC1101_REGISTER_MAP: Dict[str, int] = {
20+
# Configuration Registers
21+
"IOCFG2": 0x00, "IOCFG1": 0x01, "IOCFG0": 0x02, "FIFOTHR": 0x03,
22+
"PKTLEN": 0x06, "PKTCTRL1": 0x07, "PKTCTRL0": 0x08, "ADDR": 0x09,
23+
"CHANNR": 0x0A, "FSCTRL1": 0x0B, "FSCTRL0": 0x0C, "FREQ2": 0x0D,
24+
"FREQ1": 0x0E, "FREQ0": 0x0F, "MDMCFG4": 0x10, "MDMCFG3": 0x11,
25+
"MDMCFG2": 0x12, "MDMCFG1": 0x13, "MDMCFG0": 0x14, "DEVIATN": 0x15,
26+
"MCSM1": 0x16, "MCSM0": 0x17, "FOCCFG": 0x19, "BSCFG": 0x1A,
27+
"AGCCTRL2": 0x1B, "AGCCTRL1": 0x1C, "AGCCTRL0": 0x1D, "FSCAL3": 0x1F,
28+
"FSCAL2": 0x20, "FSCAL1": 0x21, "FSCAL0": 0x22, "FSTEST": 0x23,
29+
"PTEST": 0x25, "LTEST": 0x26, "PATABLE": 0x3E,
30+
# Status Registers
31+
"PARTNUM": 0x30, "VERSION": 0x31, "MARCSTATE": 0x35, "LQI": 0x38, "RSSI": 0x39
32+
}
33+
1934
# --- BEREICH 1: SignalduinoCommands (Implementierung der seriellen Befehle) ---
2035

2136
class SignalduinoCommands:
@@ -132,7 +147,7 @@ async def get_cc1101_settings(self, payload: Optional[Dict[str, Any]] = None) ->
132147

133148
async def _read_register_value(self, register_address: int) -> int:
134149
"""Liest einen CC1101-Registerwert und gibt ihn als Integer zurück."""
135-
response_dict = await self.read_cc1101_register(register_address)
150+
response_dict = await self._read_cc1101_register_by_address(register_address)
136151
response = response_dict["register_value"]
137152

138153
# Stellt sicher, dass wir nur den Wert nach 'C[A-Fa-f0-9]{2}\s*=\s*([0-9A-Fa-f]+)' extrahieren
@@ -266,18 +281,41 @@ def _calculate_datarate_registers(self, datarate_kbaud: float) -> tuple[int, int
266281

267282
return best_drate_e, best_drate_m
268283

269-
async def read_cc1101_register(self, register_address: int, timeout: float = SDUINO_CMD_TIMEOUT) -> Dict[str, str]:
270-
"""Read CC1101 register (C<reg>)"""
284+
async def _read_cc1101_register_by_address(self, register_address: int, timeout: float = SDUINO_CMD_TIMEOUT) -> Dict[str, str]:
285+
"""Liest CC1101-Register über die numerische Adresse (C<reg>) und gibt die rohe Antwort zurück."""
271286
hex_addr = f"{register_address:02X}"
272287
# Response-Pattern: ccreg 00: oder Cxx = yy (aus 00_SIGNALduino.pm, Zeile 87)
273-
# Die Regex muss an den Anfang und das Ende der Zeile gebunden werden (re.match wird verwendet)
274-
# ^(C[a-f0-9]{2}\s*=\s*[a-f0-9]+|ccreg 00:.*)\s*$
275-
# Hinweis: *Der Controller verwendet re.match*, was implizit ^ bindet.
276-
# Wir müssen den Regex also an das Ende binden, um Leerzeichen zu erlauben.
277288
response_pattern = re.compile(r'^\s*(C[a-f0-9]{2}\s*=\s*[a-f0-9]+|ccreg [a-f0-9]{2}:.*)\s*$', re.IGNORECASE)
278289
response = await self._send_command(command=f"C{hex_addr}", expect_response=True, timeout=timeout, response_pattern=response_pattern)
279290
return {"register_value": response}
280291

292+
async def _read_cc1101_register_by_name(self, register_name: str, timeout: float = SDUINO_CMD_TIMEOUT) -> Dict[str, Any]:
293+
"""Internal: Read CC1101 register by name (e.g., 'IOCFG2')."""
294+
register_name = register_name.upper()
295+
register_address = CC1101_REGISTER_MAP.get(register_name)
296+
if register_address is None:
297+
raise CommandValidationError(f"Unknown CC1101 register name: {register_name}")
298+
299+
response_dict = await self._read_cc1101_register_by_address(register_address, timeout)
300+
301+
# Füge den Registernamen und die Adresse zur Antwort hinzu
302+
response_dict["register_name"] = register_name
303+
response_dict["address_hex"] = f"{register_address:02X}"
304+
305+
return response_dict
306+
307+
async def read_cc1101_register(self, payload: Dict[str, Any], timeout: float = SDUINO_CMD_TIMEOUT) -> Dict[str, Any]:
308+
"""
309+
MqttCommand: Reads a CC1101 register by name provided in the MQTT payload's 'value' field.
310+
The name must be a key from CC1101_REGISTER_MAP.
311+
"""
312+
register_name = payload.get("value")
313+
if not register_name:
314+
raise CommandValidationError("Payload for read_cc1101_register must contain 'value' with the register name.")
315+
316+
# Ruft die interne Methode auf
317+
return await self._read_cc1101_register_by_name(str(register_name), timeout=timeout)
318+
281319
async def _get_frequency_registers(self) -> int:
282320
"""Liest die CC1101 Frequenzregister (FREQ2, FREQ1, FREQ0) und kombiniert sie zu einem 24-Bit-Wert (F_REG)."""
283321

@@ -296,15 +334,15 @@ def extract_hex_value(response: str) -> int:
296334
raise ValueError(f"Unexpected response format for CC1101 register read: {response}")
297335

298336
# FREQ2 (0D)
299-
response2 = await self.read_cc1101_register(FREQ2)
337+
response2 = await self._read_cc1101_register_by_address(FREQ2)
300338
freq2 = extract_hex_value(response2["register_value"])
301339

302340
# FREQ1 (0E)
303-
response1 = await self.read_cc1101_register(FREQ1)
341+
response1 = await self._read_cc1101_register_by_address(FREQ1)
304342
freq1 = extract_hex_value(response1["register_value"])
305343

306344
# FREQ0 (0F)
307-
response0 = await self.read_cc1101_register(FREQ0)
345+
response0 = await self._read_cc1101_register_by_address(FREQ0)
308346
freq0 = extract_hex_value(response0["register_value"])
309347

310348
# Die Register bilden eine 24-Bit-Zahl: (FREQ2 << 16) | (FREQ1 << 8) | FREQ0
@@ -524,6 +562,12 @@ def create_value_schema(value_schema: Dict[str, Any]) -> Dict[str, Any]:
524562
"description": "Frequency Deviation in kHz (float)."
525563
})
526564

565+
CC1101_REGISTER_SCHEMA = create_value_schema({
566+
"type": "string",
567+
"pattern": r"^[A-Z0-9]{4,8}$", # Registername wie IOCFG2, MCSM0, etc.
568+
"description": "CC1101 register name (e.g., 'IOCFG2', 'MCSM0')."
569+
})
570+
527571
# --- SEND MSG SCHEMA (PHASE 2) ---
528572
SEND_MSG_SCHEMA = {
529573
"type": "object",
@@ -556,7 +600,7 @@ def create_value_schema(value_schema: Dict[str, Any]) -> Dict[str, Any]:
556600
'get/config/decoder': { 'method': 'get_config', 'schema': BASE_SCHEMA, 'description': 'Decoder configuration (CG)' },
557601
'get/cc1101/config': { 'method': 'get_ccconf', 'schema': BASE_SCHEMA, 'description': 'CC1101 configuration registers (C0DnF)' },
558602
'get/cc1101/patable': { 'method': 'get_ccpatable', 'schema': BASE_SCHEMA, 'description': 'CC1101 PA table (C3E)' },
559-
'get/cc1101/register': { 'method': 'read_cc1101_register', 'schema': BASE_SCHEMA, 'description': 'Read CC1101 register (C<reg>)' },
603+
'get/cc1101/register': { 'method': 'read_cc1101_register', 'schema': CC1101_REGISTER_SCHEMA, 'description': 'Read CC1101 register (C<reg>)' },
560604
'get/cc1101/frequency': { 'method': 'get_frequency', 'schema': BASE_SCHEMA, 'description': 'CC1101 current RF frequency' },
561605
'get/cc1101/settings': { 'method': 'get_cc1101_settings', 'schema': BASE_SCHEMA, 'description': 'CC1101 key configuration settings (freq, bw, rampl, sens, dr)' },
562606

signalduino/controller.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@ async def get_cc1101_settings(self, payload: Dict[str, Any]) -> Dict[str, Any]:
166166
"""Delegates to SignalduinoCommands to get all key CC1101 settings."""
167167
return await self.commands.get_cc1101_settings(payload)
168168

169+
async def read_cc1101_register(self, payload: Dict[str, Any]) -> Dict[str, Any]:
170+
"""Reads a specific CC1101 register value by name (e.g., 'IOCFG2')."""
171+
return await self.commands.read_cc1101_register(payload, timeout=SDUINO_CMD_TIMEOUT)
172+
169173
async def send_command(
170174
self,
171175
command: str,

0 commit comments

Comments
 (0)