replaced ssdp with zeroconf

This commit is contained in:
Patrick762
2023-06-15 18:05:35 +02:00
parent c5e38ed853
commit 16c15e988b
4 changed files with 35 additions and 87 deletions

View File

@@ -13,10 +13,17 @@ For this to work, the following software is required:
- 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) - 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)
- cairo [Installation instructions for Windows](https://stackoverflow.com/a/73913080) - cairo [Installation instructions for Windows](https://stackoverflow.com/a/73913080)
Cairo Installation for Windows:
```bash
pip install pipwin
pipwin install cairocffi
```
The event `doubleTap` is not working with this server software. The event `doubleTap` is not working with this server software.
### Limitations ### Limitations
Discovery over SSDP might not work. Discovery might not work.
### Installation on Linux / Raspberry Pi ### Installation on Linux / Raspberry Pi

View File

@@ -32,7 +32,7 @@ setup(
"streamdeck==0.9.3", "streamdeck==0.9.3",
"pillow>=9.4.0,<10.0.0", "pillow>=9.4.0,<10.0.0",
"cairosvg==2.7.0", "cairosvg==2.7.0",
"ssdp!=1.2.0", "zeroconf",
], ],
keywords=[], keywords=[],
entry_points={ entry_points={

View File

@@ -6,5 +6,6 @@ PLUGIN_ICON = "/sd/icon"
DB_FILE = "streamdeckapi.db" DB_FILE = "streamdeckapi.db"
SD_SSDP = "urn:home-assistant-device:stream-deck" SD_SSDP = "urn:home-assistant-device:stream-deck"
SD_ZEROCONF = "_stream-deck-api._tcp.local."
DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S.%f" DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S.%f"
LONG_PRESS_SECONDS = 2 LONG_PRESS_SECONDS = 2

View File

@@ -1,5 +1,6 @@
"""Stream Deck API Server.""" """Stream Deck API Server."""
from concurrent.futures import ProcessPoolExecutor
import re import re
import io import io
import asyncio import asyncio
@@ -7,7 +8,6 @@ import platform
import sqlite3 import sqlite3
import base64 import base64
import socket import socket
from uuid import uuid4
from datetime import datetime from datetime import datetime
from typing import List, Dict from typing import List, Dict
import aiohttp import aiohttp
@@ -19,7 +19,8 @@ from StreamDeck.Devices.StreamDeck import StreamDeck
from StreamDeck.ImageHelpers import PILHelper from StreamDeck.ImageHelpers import PILHelper
import cairosvg import cairosvg
from PIL import Image from PIL import Image
import ssdp from zeroconf import IPVersion, ServiceInfo, Zeroconf
from zeroconf.asyncio import AsyncServiceInfo, AsyncZeroconf
from streamdeckapi.const import ( from streamdeckapi.const import (
DATETIME_FORMAT, DATETIME_FORMAT,
@@ -28,7 +29,7 @@ from streamdeckapi.const import (
PLUGIN_ICON, PLUGIN_ICON,
PLUGIN_INFO, PLUGIN_INFO,
PLUGIN_PORT, PLUGIN_PORT,
SD_SSDP, SD_ZEROCONF,
) )
from streamdeckapi.types import SDApplication, SDButton, SDButtonPosition, SDDevice from streamdeckapi.types import SDApplication, SDButton, SDButtonPosition, SDDevice
@@ -391,6 +392,7 @@ async def start_server_async(host: str = "0.0.0.0", port: int = PLUGIN_PORT):
print("Started Stream Deck API server on port", PLUGIN_PORT) print("Started Stream Deck API server on port", PLUGIN_PORT)
Timer(10, broadcast_status) Timer(10, broadcast_status)
# TODO add check if websocket is used, otherwise display warning on streamdeck
def get_position(deck: StreamDeck, key: int) -> SDButtonPosition: def get_position(deck: StreamDeck, key: int) -> SDButtonPosition:
@@ -529,75 +531,6 @@ def init_all():
deck.set_key_callback_async(on_key_change) deck.set_key_callback_async(on_key_change)
def get_local_ip():
"""Get local ip address."""
connection = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
connection.connect(("192.255.255.255", 1))
address = connection.getsockname()[0]
except socket.error:
address = "127.0.0.1"
finally:
connection.close()
return address
class StreamDeckApiSsdpProtocol(ssdp.SimpleServiceDiscoveryProtocol):
"""Protocol to handle responses and requests."""
def response_received(self, response: ssdp.SSDPResponse, addr: tuple):
"""Handle an incoming response."""
print(
"received response: %s %s %s",
response.status_code,
response.reason,
response.version,
)
for header in response.headers:
print("header: %s", header)
print()
def request_received(self, request: ssdp.SSDPRequest, addr: tuple):
"""Handle an incoming request and respond to it."""
print(
"received request: %s %s %s", request.method, request.uri, request.version
)
for header in request.headers:
print("header: %s", header)
print()
# Build response and send it.
print("Sending a response back to %s:%s", *addr)
address = get_local_ip()
location = f"http://{address}:{PLUGIN_PORT}/device.xml"
usn = f"uuid:{str(uuid4())}::{SD_SSDP}"
server = "python/3 UPnP/1.1 ssdpy/0.4.1"
print(f"IP Address for SSDP: {address}")
print(f"SSDP location: {location}")
ssdp_response = ssdp.SSDPResponse(
200,
"OK",
headers={
"Cache-Control": "max-age=30",
"Location": location,
"Server": server,
"ST": SD_SSDP,
"USN": usn,
"EXT": "",
},
)
msg = bytes(ssdp_response) + b"\r\n" + b"\r\n"
self.transport.sendto(msg, addr)
class Timer: class Timer:
"""Timer class.""" """Timer class."""
@@ -619,24 +552,32 @@ class Timer:
self._task.cancel() self._task.cancel()
def start_zeroconf():
"""Start Zeroconf server."""
info = ServiceInfo(
SD_ZEROCONF,
f"Stream Deck API Server.{SD_ZEROCONF}",
addresses=[socket.inet_aton("127.0.0.1")],
port=80,
)
zeroconf = Zeroconf()
print("Zeroconf starting")
zeroconf.register_service(info)
def start(): def start():
"""Entrypoint.""" """Entrypoint."""
init_all() init_all()
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
executor = ProcessPoolExecutor(2)
# SSDP server # Zeroconf server
if platform.system() == "Windows": loop.run_in_executor(executor, start_zeroconf)
print("SSDP not working on windows. Skipping ...")
else:
connect = loop.create_datagram_endpoint(
StreamDeckApiSsdpProtocol,
family=socket.AF_INET,
local_addr=(StreamDeckApiSsdpProtocol.MULTICAST_ADDRESS, 1900),
)
transport, _ = loop.run_until_complete(connect)
StreamDeckApiSsdpProtocol.transport = transport
# API server # API server
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
@@ -647,5 +588,4 @@ def start():
except KeyboardInterrupt: except KeyboardInterrupt:
pass pass
transport.close()
loop.close() loop.close()