Skip to content

Commit 91af39b

Browse files
authored
Merge pull request #1 from Patrick762/server
Add standalone server
2 parents 40368ab + 0dd111b commit 91af39b

File tree

8 files changed

+628
-33
lines changed

8 files changed

+628
-33
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
11
**/__pycache__/
2+
build
3+
*.egg-info
4+
*.db
5+
*.db-journal
6+
*.png

README.md

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,40 @@
33
# streamdeckapi
44
Stream Deck API Library for Home Assistant Stream Deck Integration
55

6-
Only compatible with separate [Stream Deck Plugin](https://github.com/Patrick762/streamdeckapi-plugin)
6+
Only compatible with separate [Stream Deck Plugin](https://github.com/Patrick762/streamdeckapi-plugin) or the bundled server.
77

88
## Dependencies
99
- [websockets](https://pypi.org/project/websockets/) 11.0.2
10+
11+
## Server
12+
This library also contains a server to use the streamdeck with Linux or without the official Stream Deck Software.
13+
14+
For this to work, the following software is required:
15+
16+
- LibUSB HIDAPI [Installation instructions](https://python-elgato-streamdeck.readthedocs.io/en/stable/pages/backend_libusb_hidapi.html) or [Installation instructions](https://github.com/jamesridgway/devdeck/wiki/Installation)
17+
- cairo [Installation instructions for Windows](https://stackoverflow.com/a/73913080)
18+
19+
The event `doubleTap` is not working with this server software.
20+
21+
### Installation on Linux / Raspberry Pi
22+
23+
Install requirements:
24+
`sudo apt install -y libudev-dev libusb-1.0-0-dev libhidapi-libusb0 libjpeg-dev zlib1g-dev libopenjp2-7 libtiff5`
25+
26+
Allow all users non-root access to Stream Deck Devices:
27+
```bash
28+
sudo tee /etc/udev/rules.d/10-streamdeck.rules << EOF
29+
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0fd9", GROUP="users", TAG+="uaccess"
30+
EOF
31+
```
32+
33+
Reload access rules:
34+
`sudo udevadm control --reload-rules`
35+
36+
Install the package:
37+
`pip install streamdeckapi`
38+
39+
Reboot your system
40+
41+
Start the server:
42+
`streamdeckapi-server`

setup.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
with codecs.open(os.path.join(here, "README.md"), encoding="utf-8") as fh:
88
long_description = "\n" + fh.read()
99

10-
VERSION = '0.0.2'
11-
DESCRIPTION = 'Stream Deck API Library'
10+
VERSION = "0.0.3"
11+
DESCRIPTION = "Stream Deck API Library"
1212

1313
# Setting up
1414
setup(
@@ -21,14 +21,27 @@
2121
long_description=long_description,
2222
url="https://github.com/Patrick762/streamdeckapi",
2323
packages=find_packages(),
24-
install_requires=["websockets==11.0.2"],
24+
install_requires=[
25+
"requests==2.28.2",
26+
"websockets==11.0.2",
27+
"aiohttp==3.8.4",
28+
"human-readable-ids==0.1.3",
29+
"jsonpickle==3.0.1",
30+
"streamdeck==0.9.3",
31+
"pillow>=9.4.0,<10.0.0",
32+
"cairosvg==2.7.0",
33+
"ssdpy==0.4.1",
34+
],
2535
keywords=[],
36+
entry_points={
37+
"console_scripts": ["streamdeckapi-server = streamdeckapi.server:start"]
38+
},
2639
classifiers=[
2740
"Development Status :: 1 - Planning",
2841
"Intended Audience :: Developers",
2942
"Programming Language :: Python :: 3",
3043
"Operating System :: Unix",
3144
"Operating System :: MacOS :: MacOS X",
3245
"Operating System :: Microsoft :: Windows",
33-
]
46+
],
3447
)

streamdeckapi/__init__.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1 @@
11
"""Stream Deck API."""
2-
3-
from streamdeckapi.api import StreamDeckApi
4-
from streamdeckapi.types import SDInfo, SDWebsocketMessage, SDSize, SDApplication, SDButton, SDButtonPosition, SDDevice
5-
from streamdeckapi.tools import get_model

streamdeckapi/api.py

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,9 @@
99
from websockets.client import connect
1010
from websockets.exceptions import WebSocketException
1111

12-
from .types import SDInfo, SDWebsocketMessage
12+
from streamdeckapi.const import PLUGIN_ICON, PLUGIN_INFO, PLUGIN_PORT
1313

14-
_PLUGIN_PORT = 6153
15-
_PLUGIN_INFO = "/sd/info"
16-
_PLUGIN_ICON = "/sd/icon"
14+
from .types import SDInfo, SDWebsocketMessage
1715

1816
_LOGGER = logging.getLogger(__name__)
1917

@@ -53,17 +51,17 @@ def host(self) -> str:
5351
@property
5452
def _info_url(self) -> str:
5553
"""URL to info endpoint."""
56-
return f"http://{self._host}:{_PLUGIN_PORT}{_PLUGIN_INFO}"
54+
return f"http://{self._host}:{PLUGIN_PORT}{PLUGIN_INFO}"
5755

5856
@property
5957
def _icon_url(self) -> str:
6058
"""URL to icon endpoint."""
61-
return f"http://{self._host}:{_PLUGIN_PORT}{_PLUGIN_ICON}/"
59+
return f"http://{self._host}:{PLUGIN_PORT}{PLUGIN_ICON}/"
6260

6361
@property
6462
def _websocket_url(self) -> str:
6563
"""URL to websocket."""
66-
return f"ws://{self._host}:{_PLUGIN_PORT}"
64+
return f"ws://{self._host}:{PLUGIN_PORT}"
6765

6866
#
6967
# API Methods
@@ -92,7 +90,8 @@ def _post_request(url: str, data: str, headers) -> None | requests.Response:
9290
try:
9391
res = requests.post(url, data, headers=headers, timeout=5)
9492
except requests.RequestException:
95-
_LOGGER.debug("Error sending data to Stream Deck Plugin (exception)")
93+
_LOGGER.debug(
94+
"Error sending data to Stream Deck Plugin (exception)")
9695
return None
9796
if res.status_code != 200:
9897
_LOGGER.debug(
@@ -121,7 +120,8 @@ async def get_info(self, in_executor: bool = True) -> None | SDInfo:
121120
try:
122121
info = SDInfo(rjson)
123122
except KeyError:
124-
_LOGGER.debug("Error parsing response from %s to SDInfo", self._info_url)
123+
_LOGGER.debug(
124+
"Error parsing response from %s to SDInfo", self._info_url)
125125
return None
126126
return info
127127

@@ -180,7 +180,8 @@ def _on_message(self, msg: str):
180180
try:
181181
datajson = json.loads(msg)
182182
except json.JSONDecodeError:
183-
_LOGGER.debug("Method _on_message: Websocket message couldn't get parsed")
183+
_LOGGER.debug(
184+
"Method _on_message: Websocket message couldn't get parsed")
184185
return
185186
try:
186187
data = SDWebsocketMessage(datajson)
@@ -195,18 +196,17 @@ def _on_message(self, msg: str):
195196
if self._on_ws_message is not None:
196197
self._on_ws_message(data)
197198

198-
match data.event:
199-
case "keyDown":
200-
self._on_button_change(data.args, True)
201-
case "keyUp":
202-
self._on_button_change(data.args, False)
203-
case "status":
204-
self._on_ws_status_update(data.args)
205-
case _:
206-
_LOGGER.debug(
207-
"Method _on_message: Unknown event from Stream Deck Plugin received (Event: %s)",
208-
data.event,
209-
)
199+
if data.event == "keyDown":
200+
self._on_button_change(data.args, True)
201+
elif data.event == "keyUp":
202+
self._on_button_change(data.args, False)
203+
elif data.event == "status":
204+
self._on_ws_status_update(data.args)
205+
else:
206+
_LOGGER.debug(
207+
"Method _on_message: Unknown event from Stream Deck Plugin received (Event: %s)",
208+
data.event,
209+
)
210210

211211
async def _websocket_loop(self):
212212
"""Start the websocket client loop."""
@@ -226,7 +226,8 @@ async def _websocket_loop(self):
226226
)
227227
self._on_message(data)
228228
await websocket.close()
229-
_LOGGER.debug("Method _websocket_loop: Websocket closed")
229+
_LOGGER.debug(
230+
"Method _websocket_loop: Websocket closed")
230231
except WebSocketException:
231232
_LOGGER.debug(
232233
"Method _websocket_loop: Websocket client crashed. Restarting it"

streamdeckapi/const.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
"""Stream Deck API const."""
2+
3+
PLUGIN_PORT = 6153
4+
PLUGIN_INFO = "/sd/info"
5+
PLUGIN_ICON = "/sd/icon"
6+
7+
DB_FILE = "streamdeckapi.db"
8+
SD_SSDP = "urn:home-assistant-device:stream-deck"
9+
DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S.%f"
10+
LONG_PRESS_SECONDS = 2

0 commit comments

Comments
 (0)