Skip to content

Commit 6bf6a84

Browse files
committed
Add functionality and documentation for debug mode
1 parent 4a1e302 commit 6bf6a84

File tree

3 files changed

+70
-3
lines changed

3 files changed

+70
-3
lines changed

README.md

+53-1
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ The following commands are required, which are the same as the Stream Deck softw
157157

158158
- `-info`: Additional information (formatted as json) about the plugin environment, as provided by the Stream Deck software.
159159

160-
There are also two additional options for specifying action scripts to load. Note that you can't use both of these options together, and the Stream Deck software doesn't pass in these options.
160+
There are also two additional options for specifying action scripts to load. Note that you can't use both of these options together, and the Stream Deck software doesn't pass in these options.
161161

162162
- Plugin Directory: Pass the directory containing the plugin files as a positional argument:
163163

@@ -172,6 +172,58 @@ There are also two additional options for specifying action scripts to load. No
172172
streamdeck --action-scripts actions1.py actions2.py
173173
```
174174

175+
In addition to these, there is an additional option to use **debug mode**, which is discussed below.
176+
177+
#### Debugging
178+
179+
The SDK supports remote debugging capabilities, allowing you to attach a debugger after the plugin has started. This is particularly useful since Stream Deck plugins run as separate processes.
180+
181+
To enable debug mode, pass in the option `--debug {debug port number}`, which tells the plugin to wait for a debugger to attach on that port number.
182+
183+
```bash
184+
streamdeck --debug 5675
185+
```
186+
187+
When running in debug mode, the plugin will pause for 10 seconds after initialization, giving you time to attach your debugger. You'll see a message in the logs indicating that the plugin is waiting for a debugger to attach.
188+
189+
NOTE: If things get messy, and you have a prior instance already listening to that port, you should kill the process with something like the following command:
190+
191+
```bash
192+
kill $(lsof -t -i:$DEBUG_PORT)
193+
```
194+
195+
#### Debugging with VS Code
196+
197+
1. Create a launch configuration in `.vscode/launch.json`:
198+
199+
```json
200+
{
201+
"version": "0.2.0",
202+
"configurations": [
203+
{
204+
"name": "Python: Attach to Stream Deck Plugin",
205+
"type": "debugpy",
206+
"request": "attach",
207+
"connect": {
208+
"host": "localhost",
209+
"port": 5678
210+
}
211+
"pathMappings": [
212+
{
213+
"localRoot": "${workspaceFolder}",
214+
"remoteRoot": "."
215+
}
216+
],
217+
"justMyCode": false,
218+
}
219+
]
220+
}
221+
```
222+
223+
2. Start your plugin with debugging enabled
224+
3. When you see the "waiting for debugger" message, use VS Code's Run and Debug view to attach using the configuration above
225+
4. Set breakpoints and debug as normal
226+
175227
176228
#### Configuration
177229

pyproject.toml

+1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
"pytest-mock >= 3.14.0",
7575
"pytest-sugar >= 1.0.0",
7676
"tox >= 4.23.2",
77+
"debugpy",
7778
]
7879

7980
[project.urls]

streamdeck/__main__.py

+16-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import logging
33
import sys
44
from pathlib import Path
5-
from typing import Annotated, Union
5+
from typing import Annotated, Optional
66

77
import typer
88

@@ -18,14 +18,25 @@
1818
plugin = typer.Typer()
1919

2020

21+
def setup_debug_mode(debug_port: int) -> None:
22+
"""Setup the debug mode for the plugin and wait for the debugger to attach."""
23+
import debugpy
24+
25+
debugpy.listen(debug_port)
26+
logger.info("Starting in debug mode. Waiting for debugger to attach on port %d...", debug_port)
27+
debugpy.wait_for_client()
28+
logger.info("Debugger attached.")
29+
30+
2131
@plugin.command()
2232
def main(
2333
port: Annotated[int, typer.Option("-p", "-port")],
2434
plugin_registration_uuid: Annotated[str, typer.Option("-pluginUUID")],
2535
register_event: Annotated[str, typer.Option("-registerEvent")],
2636
info: Annotated[str, typer.Option("-info")],
2737
plugin_dir: Annotated[Path, typer.Option(file_okay=False, exists=True, readable=True)] = Path.cwd(), # noqa: B008
28-
action_scripts: Union[list[str], None] = None, # noqa: UP007
38+
action_scripts: Optional[list[str]] = None, # noqa: UP007
39+
debug_port: Annotated[Optional[int], typer.Option("--debug", "-d")] = None, # noqa: UP007
2940
) -> None:
3041
"""Start the Stream Deck plugin with the given configuration.
3142
@@ -43,6 +54,9 @@ def main(
4354
# a child logger with `logging.getLogger("streamdeck.mycomponent")`, all with the same handler/formatter configuration.
4455
configure_streamdeck_logger(name="streamdeck", plugin_uuid=plugin_uuid)
4556

57+
if debug_port:
58+
setup_debug_mode(debug_port)
59+
4660
pyproject = PyProjectConfigs.validate_from_toml_file(plugin_dir / "pyproject.toml", action_scripts=action_scripts)
4761
actions = pyproject.streamdeck_plugin_actions
4862

0 commit comments

Comments
 (0)