{"id":15371380,"url":"https://github.com/codingjoe/ssdp","last_synced_at":"2025-04-12T14:19:16.010Z","repository":{"id":28434704,"uuid":"117351978","full_name":"codingjoe/ssdp","owner":"codingjoe","description":"Python asyncio library for Simple Service Discovery Protocol (SSDP).","archived":false,"fork":false,"pushed_at":"2024-11-15T09:41:12.000Z","size":59,"stargazers_count":44,"open_issues_count":2,"forks_count":12,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-12T14:19:09.751Z","etag":null,"topics":["asyncio","iot","protocol","python","ssdp","upnp"],"latest_commit_sha":null,"homepage":"https://en.wikipedia.org/wiki/Simple_Service_Discovery_Protocol","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/codingjoe.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"codingjoe","custom":"https://www.paypal.me/codingjoe"}},"created_at":"2018-01-13T14:53:48.000Z","updated_at":"2025-02-26T07:36:48.000Z","dependencies_parsed_at":"2024-06-11T21:46:04.475Z","dependency_job_id":"83bf2d74-60ca-42e4-8a44-100f7676ece9","html_url":"https://github.com/codingjoe/ssdp","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codingjoe%2Fssdp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codingjoe%2Fssdp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codingjoe%2Fssdp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codingjoe%2Fssdp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/codingjoe","download_url":"https://codeload.github.com/codingjoe/ssdp/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248578876,"owners_count":21127714,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asyncio","iot","protocol","python","ssdp","upnp"],"created_at":"2024-10-01T13:46:39.309Z","updated_at":"2025-04-12T14:19:15.991Z","avatar_url":"https://github.com/codingjoe.png","language":"Python","funding_links":["https://github.com/sponsors/codingjoe","https://www.paypal.me/codingjoe"],"categories":[],"sub_categories":[],"readme":"# Python SSDP\n\nPython asyncio library for Simple Service Discovery Protocol (SSDP).\n\nSSDP is a UPnP substandard. For more information see:\nhttps://en.wikipedia.org/wiki/Simple_Service_Discovery_Protocol\n\n## Setup\n\n```bash\npython3 -m pip install ssdp # lightweight, without any dependencies\n# or\npython3 -m pip install ssdp[cli] # with cli support for testing and debugging\n```\n\n## Usage\n\n### CLI\n\n```console-interactive\n$ ssdp --help\nUsage: ssdp [OPTIONS] COMMAND [ARGS]...\n\n  SSDP command line interface.\n\nOptions:\n  -v, --verbose  Increase verbosity.\n  --help         Show this message and exit.\n\nCommands:\n  discover  Send out an M-SEARCH request and listening for responses.\n```\n\n#### Discover\n\nDiscover devices on the network and print the responses.\n\n```console\nssdp discover --help\nUsage: ssdp discover [OPTIONS]\n\n  Send out an M-SEARCH request and listening for responses.\n\nOptions:\n  -b, --bind TEXT             Specify alternate bind address [default: all\n                              interfaces]\n  --search-target, --st TEXT  Search target [default: ssdp:all]\n  --max-wait, --mx INTEGER    Maximum wait time in seconds [default: 5]\n  --help                      Show this message and exit.\n```\n\nExample:\n\n```console\n$ ssdp discover\n[::]:1900 - - [Sun Jun 11 12:07:09 2023] M-SEARCH * HTTP/1.1\nHOST: 239.255.255.250:1900\nMAN: \"ssdp:discover\"\nMX: 5\nST: ssdp:all\n\n[::ffff:192.168.178.1]:1900 - - [Sun Jun 11 12:07:09 2023] HTTP/1.1 200 OK\nCache-Control: max-age=1800\nLocation: http://192.168.178.1:49000/MediaServerDevDesc.xml\nServer: FRITZ!Box 7590 UPnP/1.0 AVM FRITZ!Box 7590 154.07.50\nExt:\nST: upnp:rootdevice\nUSN: uuid:fa095ecc-e13e-40e7-8e6c-3ca62f98471f::upnp:rootdevice\n```\n\n### Python API\n\n#### Messages\n\nThe SSDP library provides two classes for SSDP messages: `SSDPRequest` and\n`SSDPResponse`. Both classes are subclasses of `SSDPMessage` and provide\nthe following methods:\n\n- `parse`: Parse a SSDP message from a string.\n- `__bytes__`: Convert the SSDP message to a bytes object.\n- `__str__`: Convert the SSDP message to a string.\n\nYou can parse a SSDP message from a string with the `parse` method.\nIt will return a `SSDPRequest` or `SSDPResponse` object depending\non the message type.\n\n```pycon\n\u003e\u003e\u003e import ssdp.messages\n\u003e\u003e\u003e ssdp.messages.SSDPRequest.parse('NOTIFY * HTTP/1.1\\r\\n\\r\\n')\n\u003cssdp.messages.SSDPRequest object at 0x7f8b1c0b6a90\u003e\n\u003e\u003e\u003e ssdp.messages.SSDPResponse.parse('HTTP/1.1 200 OK\\r\\n\\r\\n')\n\u003cssdp.messages.SSDPResponse object at 0x7f8b1c0b6a90\u003e\n```\n\n##### SSDPRequest\n\n```pycon\n\u003e\u003e\u003e from ssdp.messages import SSDPRequest\n\u003e\u003e\u003e SSDPRequest('NOTIFY', headers={\n...     'HOST': '10.0.0.42',\n...     'NT': 'upnp:rootdevice',\n...     'NTS': 'ssdp:alive',\n... })\n\u003cssdp.messages.SSDPRequest object at 0x7f8b1c0b6a90\u003e\n```\n\nThe `SSDPRequest` class provides the a `sendto` method to send the request\nover a open transport.\n\n```pycon\n\u003e\u003e\u003e from ssdp import network, messages\n\u003e\u003e\u003e notify = messages.SSDPRequest('NOTIFY')\n\u003e\u003e\u003e notify.sendto(transport, (network.MULTICAST_ADDRESS_IPV4, network.PORT))\n```\n\n##### SSDPResponse\n\n```pycon\n\u003e\u003e\u003e from ssdp.messages import SSDPResponse\n\u003e\u003e\u003e SSDPResponse(200, 'OK', headers={\n...     'CACHE-CONTROL': 'max-age=1800',\n...     'LOCATION': 'http://10.0.0.1:80/description.xml',\n...     'SERVER': 'Linux/2.6.18 UPnP/1.0 quick_ssdp/1.0',\n...     'ST': 'upnp:rootdevice',\n... })\n\u003cssdp.messages.SSDPResponse object at 0x7f8b1c0b6a90\u003e\n```\n\n#### Asyncio SSD Protocol datagram endpoint\n\nThe `aio.SimpleServiceDiscoveryProtocol` class is a subclass of\n`asyncio.DatagramProtocol` and provides the following additional methods:\n\n- `response_received`: Called when a SSDP response was received.\n- `request_received`: Called when a SSDP request was received.\n\nThe protocol can be used to react to SSDP messages in an asyncio event loop.\n\nThis example sends a SSDP NOTIFY message and prints all received SSDP messages:\n\n```python\n#!/usr/bin/env python3\nimport asyncio\nimport socket\n\nfrom ssdp import aio, messages, network\n\n\nclass MyProtocol(aio.SimpleServiceDiscoveryProtocol):\n\n  def response_received(self, response, addr):\n    print(response, addr)\n\n  def request_received(self, request, addr):\n    print(request, addr)\n\n\nloop = asyncio.get_event_loop()\nconnect = loop.create_datagram_endpoint(MyProtocol, family=socket.AF_INET)\ntransport, protocol = loop.run_until_complete(connect)\n\nnotify = messages.SSDPRequest('NOTIFY')\nnotify.sendto(transport, (network.MULTICAST_ADDRESS_IPV4, network.PORT))\n\ntry:\n  loop.run_forever()\nexcept KeyboardInterrupt:\n  pass\n\ntransport.close()\nloop.close()\n```\n\n## SSDP lexer plugin for [Pygments][pygments]\n\nThe SSDP library comes with a lexer plugin for [Pygments][pygments]\nto highlight SSDP messages. It's based on a HTTP lexer and adds SSDP\nspecific keywords.\n\nYou can install the plugin with the following command:\n\n```bash\npip install ssdp[pymgments]  # included in ssdp[cli]\n```\n\nYou can either get the lexer by name:\n\n```pycon\n\u003e\u003e\u003e from pygments.lexers import get_lexer_by_name\n\u003e\u003e\u003e get_lexer_by_name('ssdp')\n\u003cpygments.lexers.SSDPLexer\u003e\n```\n\nHighlighting a SSDP message, could look like this:\n\n```python\n#/usr/bin/env python3\nfrom pygments import highlight\nfrom pygments.lexers import get_lexer_by_name\nfrom pygments.formatters import TerminalFormatter\n\n\nif __name__ == '__main__':\n    lexer = get_lexer_by_name('ssdp')\n    formatter = TerminalFormatter()\n    code = 'NOTIFY * HTTP/1.1\\r\\nHOST: localhost:1900'\n    msg = highlight(code, lexer, formatter)\n    print(msg)\n```\n\n[pygments]: https://pygments.org/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodingjoe%2Fssdp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcodingjoe%2Fssdp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodingjoe%2Fssdp/lists"}