pyremootio 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyremootio-0.1.0/.gitignore +13 -0
- pyremootio-0.1.0/LICENSE +21 -0
- pyremootio-0.1.0/PKG-INFO +134 -0
- pyremootio-0.1.0/README.md +104 -0
- pyremootio-0.1.0/examples/log_events.py +73 -0
- pyremootio-0.1.0/examples/trigger.py +71 -0
- pyremootio-0.1.0/pyproject.toml +95 -0
- pyremootio-0.1.0/src/pyremootio/__init__.py +47 -0
- pyremootio-0.1.0/src/pyremootio/client.py +691 -0
- pyremootio-0.1.0/src/pyremootio/const.py +15 -0
- pyremootio-0.1.0/src/pyremootio/crypto.py +169 -0
- pyremootio-0.1.0/src/pyremootio/exceptions.py +37 -0
- pyremootio-0.1.0/src/pyremootio/models.py +244 -0
- pyremootio-0.1.0/src/pyremootio/py.typed +0 -0
- pyremootio-0.1.0/tests/__init__.py +0 -0
- pyremootio-0.1.0/tests/fake_device.py +159 -0
- pyremootio-0.1.0/tests/test_client.py +417 -0
- pyremootio-0.1.0/tests/test_crypto.py +172 -0
- pyremootio-0.1.0/tests/test_models.py +95 -0
pyremootio-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Remootio
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING WITHOUT LIMITATION THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: pyremootio
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Async Python client for the Remootio Websocket API
|
|
5
|
+
Project-URL: Homepage, https://github.com/remootio/pyremootio
|
|
6
|
+
Project-URL: Documentation, https://github.com/remootio/remootio-api-documentation
|
|
7
|
+
Project-URL: Source, https://github.com/remootio/pyremootio
|
|
8
|
+
Project-URL: Issues, https://github.com/remootio/pyremootio/issues
|
|
9
|
+
Author-email: Remootio <hello@remootio.com>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: asyncio,garage,gate,remootio,websocket
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Framework :: AsyncIO
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Home Automation
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: >=3.12
|
|
22
|
+
Requires-Dist: aiohttp>=3.9.0
|
|
23
|
+
Requires-Dist: cryptography>=42.0.0
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: mypy>=1.11.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: ruff>=0.6.0; extra == 'dev'
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# pyremootio
|
|
32
|
+
|
|
33
|
+
Async Python client for the [Remootio](https://www.remootio.com) local Websocket API.
|
|
34
|
+
|
|
35
|
+
Enable the Websocket API in the Remootio app and copy the API Secret Key, API Auth Key, and device IP.
|
|
36
|
+
|
|
37
|
+
Protocol details: [Remootio Websocket API documentation](https://github.com/remootio/remootio-api-documentation).
|
|
38
|
+
|
|
39
|
+
## Install
|
|
40
|
+
|
|
41
|
+
Python 3.12 or newer:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install pyremootio
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
From a clone of this repo (includes tests and examples):
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
python3.12 -m venv .venv
|
|
51
|
+
.venv/bin/pip install -e ".[dev]"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Run examples with `.venv/bin/python`.
|
|
55
|
+
|
|
56
|
+
## Usage
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
import asyncio
|
|
60
|
+
import aiohttp
|
|
61
|
+
from pyremootio import RemootioClient
|
|
62
|
+
|
|
63
|
+
async def main() -> None:
|
|
64
|
+
async with aiohttp.ClientSession() as session:
|
|
65
|
+
client = RemootioClient(
|
|
66
|
+
"<ip_address>", # IP address of your Remootio device
|
|
67
|
+
"<secret_key>", # API Secret Key from the Remootio app
|
|
68
|
+
"<auth_key>", # API Auth Key from the Remootio app
|
|
69
|
+
session,
|
|
70
|
+
)
|
|
71
|
+
await client.connect()
|
|
72
|
+
try:
|
|
73
|
+
response = await client.trigger()
|
|
74
|
+
print("TRIGGER success=%s state=%s" % (response.success, response.state))
|
|
75
|
+
finally:
|
|
76
|
+
await client.disconnect()
|
|
77
|
+
|
|
78
|
+
asyncio.run(main())
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`connect()` runs HELLO, AUTH, and the first QUERY action to authenticate the client. After that, `listen()` receives device events.
|
|
82
|
+
|
|
83
|
+
Logging uses the standard `pyremootio` logger:
|
|
84
|
+
|
|
85
|
+
| Level | What you see |
|
|
86
|
+
| --- | --- |
|
|
87
|
+
| `DEBUG` | PING / PONG keepalive |
|
|
88
|
+
| `INFO` | connect, authenticate, disconnect (with reason) |
|
|
89
|
+
| `WARNING` | connection lost, reconnect failed |
|
|
90
|
+
| `ERROR` | unexpected receive-loop or listener failures |
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
import logging
|
|
94
|
+
logging.getLogger("pyremootio").setLevel(logging.DEBUG)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Events
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
async def on_event(event):
|
|
101
|
+
print(event.type, event.state)
|
|
102
|
+
|
|
103
|
+
unsubscribe = client.listen(on_event)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
`StateChange` is sent when a sensor is installed. Enable API logging in the app for the full event set.
|
|
107
|
+
|
|
108
|
+
### Actions
|
|
109
|
+
|
|
110
|
+
| Method | Device action |
|
|
111
|
+
| --- | --- |
|
|
112
|
+
| `query()` | Current door state |
|
|
113
|
+
| `open(duration_minutes=None)` | Open if closed (sensor required) |
|
|
114
|
+
| `close(duration_minutes=None)` | Close if open (sensor required) |
|
|
115
|
+
| `trigger(duration_minutes=None)` | Pulse the control output |
|
|
116
|
+
| `trigger_secondary(duration_minutes=None)` | Pulse the free relay output |
|
|
117
|
+
| `restart()` | Reboot the device (connection drops) |
|
|
118
|
+
|
|
119
|
+
`duration_minutes` holds the output active. It is rejected unless `api_version` is 3 or later. Failed actions raise `RemootioActionError`.
|
|
120
|
+
|
|
121
|
+
## Examples
|
|
122
|
+
|
|
123
|
+
- [`examples/trigger.py`](examples/trigger.py) — connect, trigger, wait for `StateChange`
|
|
124
|
+
- [`examples/log_events.py`](examples/log_events.py) — log device events to stdout
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
.venv/bin/python examples/trigger.py --host <ip_address> --secret-key <secret_key> --auth-key <auth_key>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Tests
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
pytest
|
|
134
|
+
```
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# pyremootio
|
|
2
|
+
|
|
3
|
+
Async Python client for the [Remootio](https://www.remootio.com) local Websocket API.
|
|
4
|
+
|
|
5
|
+
Enable the Websocket API in the Remootio app and copy the API Secret Key, API Auth Key, and device IP.
|
|
6
|
+
|
|
7
|
+
Protocol details: [Remootio Websocket API documentation](https://github.com/remootio/remootio-api-documentation).
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
Python 3.12 or newer:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install pyremootio
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
From a clone of this repo (includes tests and examples):
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
python3.12 -m venv .venv
|
|
21
|
+
.venv/bin/pip install -e ".[dev]"
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Run examples with `.venv/bin/python`.
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
import asyncio
|
|
30
|
+
import aiohttp
|
|
31
|
+
from pyremootio import RemootioClient
|
|
32
|
+
|
|
33
|
+
async def main() -> None:
|
|
34
|
+
async with aiohttp.ClientSession() as session:
|
|
35
|
+
client = RemootioClient(
|
|
36
|
+
"<ip_address>", # IP address of your Remootio device
|
|
37
|
+
"<secret_key>", # API Secret Key from the Remootio app
|
|
38
|
+
"<auth_key>", # API Auth Key from the Remootio app
|
|
39
|
+
session,
|
|
40
|
+
)
|
|
41
|
+
await client.connect()
|
|
42
|
+
try:
|
|
43
|
+
response = await client.trigger()
|
|
44
|
+
print("TRIGGER success=%s state=%s" % (response.success, response.state))
|
|
45
|
+
finally:
|
|
46
|
+
await client.disconnect()
|
|
47
|
+
|
|
48
|
+
asyncio.run(main())
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`connect()` runs HELLO, AUTH, and the first QUERY action to authenticate the client. After that, `listen()` receives device events.
|
|
52
|
+
|
|
53
|
+
Logging uses the standard `pyremootio` logger:
|
|
54
|
+
|
|
55
|
+
| Level | What you see |
|
|
56
|
+
| --- | --- |
|
|
57
|
+
| `DEBUG` | PING / PONG keepalive |
|
|
58
|
+
| `INFO` | connect, authenticate, disconnect (with reason) |
|
|
59
|
+
| `WARNING` | connection lost, reconnect failed |
|
|
60
|
+
| `ERROR` | unexpected receive-loop or listener failures |
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
import logging
|
|
64
|
+
logging.getLogger("pyremootio").setLevel(logging.DEBUG)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Events
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
async def on_event(event):
|
|
71
|
+
print(event.type, event.state)
|
|
72
|
+
|
|
73
|
+
unsubscribe = client.listen(on_event)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`StateChange` is sent when a sensor is installed. Enable API logging in the app for the full event set.
|
|
77
|
+
|
|
78
|
+
### Actions
|
|
79
|
+
|
|
80
|
+
| Method | Device action |
|
|
81
|
+
| --- | --- |
|
|
82
|
+
| `query()` | Current door state |
|
|
83
|
+
| `open(duration_minutes=None)` | Open if closed (sensor required) |
|
|
84
|
+
| `close(duration_minutes=None)` | Close if open (sensor required) |
|
|
85
|
+
| `trigger(duration_minutes=None)` | Pulse the control output |
|
|
86
|
+
| `trigger_secondary(duration_minutes=None)` | Pulse the free relay output |
|
|
87
|
+
| `restart()` | Reboot the device (connection drops) |
|
|
88
|
+
|
|
89
|
+
`duration_minutes` holds the output active. It is rejected unless `api_version` is 3 or later. Failed actions raise `RemootioActionError`.
|
|
90
|
+
|
|
91
|
+
## Examples
|
|
92
|
+
|
|
93
|
+
- [`examples/trigger.py`](examples/trigger.py) — connect, trigger, wait for `StateChange`
|
|
94
|
+
- [`examples/log_events.py`](examples/log_events.py) — log device events to stdout
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
.venv/bin/python examples/trigger.py --host <ip_address> --secret-key <secret_key> --auth-key <auth_key>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Tests
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
pytest
|
|
104
|
+
```
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Connect and print every event the device sends (enable API with logging).
|
|
3
|
+
|
|
4
|
+
Example (from this folder, after installing into .venv):
|
|
5
|
+
|
|
6
|
+
<ip_address> is the IP address of the Remootio device.
|
|
7
|
+
<secret_key> is the secret key of the Remootio device, you can find it in the Remootio app.
|
|
8
|
+
<auth_key> is the auth key of the Remootio device, you can find it in the Remootio app.
|
|
9
|
+
|
|
10
|
+
.venv/bin/python examples/log_events.py --host <ip_address> --secret-key <secret_key> --auth-key <auth_key>
|
|
11
|
+
|
|
12
|
+
for example:
|
|
13
|
+
.venv/bin/python examples/log_events.py --host 10.23.1.106 --secret-key D0A7E9B4E31AB7BCF2219C9A587ACA7DDB572EAB08459D0ACC52F7C83121B19C --auth-key 3C3B25A1227B9FA87E4A4E259B661F98E522531D2250BAE0C3F1FE3B02762183
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import argparse
|
|
19
|
+
import asyncio
|
|
20
|
+
import logging
|
|
21
|
+
|
|
22
|
+
import aiohttp
|
|
23
|
+
|
|
24
|
+
from pyremootio import RemootioClient, RemootioEvent
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
async def main() -> None:
|
|
28
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
29
|
+
parser.add_argument("--host", required=True)
|
|
30
|
+
parser.add_argument("--secret-key", required=True)
|
|
31
|
+
parser.add_argument("--auth-key", required=True)
|
|
32
|
+
parser.add_argument("--port", type=int, default=8080)
|
|
33
|
+
parser.add_argument(
|
|
34
|
+
"--log-level",
|
|
35
|
+
default="DEBUG",
|
|
36
|
+
choices=["DEBUG", "INFO", "WARNING", "ERROR"],
|
|
37
|
+
help="pyremootio log level (default: DEBUG, includes PING/PONG)",
|
|
38
|
+
)
|
|
39
|
+
args = parser.parse_args()
|
|
40
|
+
|
|
41
|
+
logging.basicConfig(
|
|
42
|
+
level=logging.INFO,
|
|
43
|
+
format="%(asctime)s [%(levelname)s] %(message)s",
|
|
44
|
+
)
|
|
45
|
+
logging.getLogger("pyremootio").setLevel(getattr(logging, args.log_level))
|
|
46
|
+
|
|
47
|
+
async def on_event(event: RemootioEvent) -> None:
|
|
48
|
+
logging.info("%s state=%s cnt=%s data=%s", event.type, event.state, event.cnt, event.data)
|
|
49
|
+
|
|
50
|
+
async with aiohttp.ClientSession() as session:
|
|
51
|
+
client = RemootioClient(
|
|
52
|
+
args.host,
|
|
53
|
+
args.secret_key,
|
|
54
|
+
args.auth_key,
|
|
55
|
+
session,
|
|
56
|
+
port=args.port,
|
|
57
|
+
)
|
|
58
|
+
client.listen(on_event)
|
|
59
|
+
await client.connect(reconnect=True)
|
|
60
|
+
logging.info(
|
|
61
|
+
"Listening (serial=%s, api=%s, state=%s)",
|
|
62
|
+
client.serial_number,
|
|
63
|
+
client.api_version,
|
|
64
|
+
client.state,
|
|
65
|
+
)
|
|
66
|
+
try:
|
|
67
|
+
await asyncio.Event().wait()
|
|
68
|
+
finally:
|
|
69
|
+
await client.disconnect()
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
if __name__ == "__main__":
|
|
73
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Connect, trigger the control output, and disconnect after a StateChange.
|
|
3
|
+
|
|
4
|
+
Example (from this folder, after installing into .venv):
|
|
5
|
+
|
|
6
|
+
<ip_address> is the IP address of the Remootio device.
|
|
7
|
+
<secret_key> is the secret key of the Remootio device, you can find it in the Remootio app.
|
|
8
|
+
<auth_key> is the auth key of the Remootio device, you can find it in the Remootio app.
|
|
9
|
+
|
|
10
|
+
.venv/bin/python examples/trigger.py --host <ip_address> --secret-key <secret_key> --auth-key <auth_key>
|
|
11
|
+
|
|
12
|
+
for example:
|
|
13
|
+
.venv/bin/python examples/trigger.py --host 10.23.1.106 --secret-key D0A7E9B4E31AB7BCF2219C9A587ACA7DDB572EAB08459D0ACC52F7C83121B19C --auth-key 3C3B25A1227B9FA87E4A4E259B661F98E522531D2250BAE0C3F1FE3B02762183
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import argparse
|
|
19
|
+
import asyncio
|
|
20
|
+
import logging
|
|
21
|
+
|
|
22
|
+
import aiohttp
|
|
23
|
+
|
|
24
|
+
from pyremootio import DoorState, EventType, RemootioClient, RemootioEvent
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
async def main() -> None:
|
|
28
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
29
|
+
parser.add_argument("--host", required=True)
|
|
30
|
+
parser.add_argument("--secret-key", required=True)
|
|
31
|
+
parser.add_argument("--auth-key", required=True)
|
|
32
|
+
parser.add_argument("--port", type=int, default=8080)
|
|
33
|
+
args = parser.parse_args()
|
|
34
|
+
|
|
35
|
+
logging.basicConfig(level=logging.INFO)
|
|
36
|
+
done = asyncio.Event()
|
|
37
|
+
|
|
38
|
+
async def on_event(event: RemootioEvent) -> None:
|
|
39
|
+
if event.event_type is EventType.STATE_CHANGE:
|
|
40
|
+
logging.info("Door state changed to %s", event.state)
|
|
41
|
+
done.set()
|
|
42
|
+
|
|
43
|
+
async with aiohttp.ClientSession() as session:
|
|
44
|
+
client = RemootioClient(
|
|
45
|
+
args.host,
|
|
46
|
+
args.secret_key,
|
|
47
|
+
args.auth_key,
|
|
48
|
+
session,
|
|
49
|
+
port=args.port,
|
|
50
|
+
)
|
|
51
|
+
client.listen(on_event)
|
|
52
|
+
await client.connect()
|
|
53
|
+
try:
|
|
54
|
+
logging.info(
|
|
55
|
+
"Authenticated (serial=%s, api=%s, state=%s)",
|
|
56
|
+
client.serial_number,
|
|
57
|
+
client.api_version,
|
|
58
|
+
client.state,
|
|
59
|
+
)
|
|
60
|
+
response = await client.trigger()
|
|
61
|
+
logging.info("TRIGGER success=%s state=%s", response.success, response.state)
|
|
62
|
+
if response.state is DoorState.NO_SENSOR:
|
|
63
|
+
logging.info("No sensor installed; disconnecting without waiting")
|
|
64
|
+
return
|
|
65
|
+
await asyncio.wait_for(done.wait(), timeout=30)
|
|
66
|
+
finally:
|
|
67
|
+
await client.disconnect()
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
if __name__ == "__main__":
|
|
71
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pyremootio"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Async Python client for the Remootio Websocket API"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.12"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Remootio", email = "hello@remootio.com" },
|
|
14
|
+
]
|
|
15
|
+
keywords = ["remootio", "asyncio", "garage", "gate", "websocket"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Framework :: AsyncIO",
|
|
19
|
+
"Intended Audience :: Developers",
|
|
20
|
+
"License :: OSI Approved :: MIT License",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Programming Language :: Python :: 3.13",
|
|
23
|
+
"Topic :: Home Automation",
|
|
24
|
+
"Typing :: Typed",
|
|
25
|
+
]
|
|
26
|
+
dependencies = [
|
|
27
|
+
"aiohttp>=3.9.0",
|
|
28
|
+
"cryptography>=42.0.0",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.optional-dependencies]
|
|
32
|
+
dev = [
|
|
33
|
+
"pytest>=8.0.0",
|
|
34
|
+
"pytest-asyncio>=0.24.0",
|
|
35
|
+
"ruff>=0.6.0",
|
|
36
|
+
"mypy>=1.11.0",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
[project.urls]
|
|
40
|
+
Homepage = "https://github.com/remootio/pyremootio"
|
|
41
|
+
Documentation = "https://github.com/remootio/remootio-api-documentation"
|
|
42
|
+
Source = "https://github.com/remootio/pyremootio"
|
|
43
|
+
Issues = "https://github.com/remootio/pyremootio/issues"
|
|
44
|
+
|
|
45
|
+
[tool.hatch.version]
|
|
46
|
+
path = "src/pyremootio/__init__.py"
|
|
47
|
+
|
|
48
|
+
[tool.hatch.build.targets.sdist]
|
|
49
|
+
include = [
|
|
50
|
+
"/src",
|
|
51
|
+
"/tests",
|
|
52
|
+
"/examples",
|
|
53
|
+
"/README.md",
|
|
54
|
+
"/LICENSE",
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
[tool.pytest.ini_options]
|
|
58
|
+
asyncio_mode = "auto"
|
|
59
|
+
asyncio_default_fixture_loop_scope = "function"
|
|
60
|
+
testpaths = ["tests"]
|
|
61
|
+
pythonpath = ["src"]
|
|
62
|
+
|
|
63
|
+
[tool.ruff]
|
|
64
|
+
target-version = "py312"
|
|
65
|
+
line-length = 99
|
|
66
|
+
src = ["src", "tests", "examples"]
|
|
67
|
+
|
|
68
|
+
[tool.ruff.lint]
|
|
69
|
+
select = [
|
|
70
|
+
"B",
|
|
71
|
+
"C4",
|
|
72
|
+
"E",
|
|
73
|
+
"F",
|
|
74
|
+
"I",
|
|
75
|
+
"PERF",
|
|
76
|
+
"PLC",
|
|
77
|
+
"PLE",
|
|
78
|
+
"PLW",
|
|
79
|
+
"RUF",
|
|
80
|
+
"SIM",
|
|
81
|
+
"UP",
|
|
82
|
+
"W",
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
[tool.ruff.lint.isort]
|
|
86
|
+
known-first-party = ["pyremootio"]
|
|
87
|
+
|
|
88
|
+
[tool.ruff.lint.per-file-ignores]
|
|
89
|
+
"examples/*.py" = ["E501"]
|
|
90
|
+
|
|
91
|
+
[tool.mypy]
|
|
92
|
+
python_version = "3.12"
|
|
93
|
+
strict = true
|
|
94
|
+
mypy_path = "src"
|
|
95
|
+
packages = ["pyremootio"]
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Async Python client for the Remootio Websocket API."""
|
|
2
|
+
|
|
3
|
+
from pyremootio.client import RemootioClient
|
|
4
|
+
from pyremootio.exceptions import (
|
|
5
|
+
RemootioActionError,
|
|
6
|
+
RemootioAuthenticationError,
|
|
7
|
+
RemootioConnectionError,
|
|
8
|
+
RemootioCryptoError,
|
|
9
|
+
RemootioError,
|
|
10
|
+
RemootioTimeoutError,
|
|
11
|
+
)
|
|
12
|
+
from pyremootio.models import (
|
|
13
|
+
ActionErrorCode,
|
|
14
|
+
ActionResponse,
|
|
15
|
+
ActionType,
|
|
16
|
+
ConnectionVia,
|
|
17
|
+
Credentials,
|
|
18
|
+
DeviceErrorMessage,
|
|
19
|
+
DoorState,
|
|
20
|
+
EventType,
|
|
21
|
+
KeyType,
|
|
22
|
+
RemootioEvent,
|
|
23
|
+
ServerHello,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
__all__ = [
|
|
27
|
+
"ActionErrorCode",
|
|
28
|
+
"ActionResponse",
|
|
29
|
+
"ActionType",
|
|
30
|
+
"ConnectionVia",
|
|
31
|
+
"Credentials",
|
|
32
|
+
"DeviceErrorMessage",
|
|
33
|
+
"DoorState",
|
|
34
|
+
"EventType",
|
|
35
|
+
"KeyType",
|
|
36
|
+
"RemootioActionError",
|
|
37
|
+
"RemootioAuthenticationError",
|
|
38
|
+
"RemootioClient",
|
|
39
|
+
"RemootioConnectionError",
|
|
40
|
+
"RemootioCryptoError",
|
|
41
|
+
"RemootioError",
|
|
42
|
+
"RemootioEvent",
|
|
43
|
+
"RemootioTimeoutError",
|
|
44
|
+
"ServerHello",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
__version__ = "0.1.0"
|