uiprotect 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.
Potentially problematic release.
This version of uiprotect might be problematic. Click here for more details.
- uiprotect-0.1.0/LICENSE +23 -0
- uiprotect-0.1.0/PKG-INFO +245 -0
- uiprotect-0.1.0/README.md +205 -0
- uiprotect-0.1.0/pyproject.toml +192 -0
- uiprotect-0.1.0/src/uiprotect/__init__.py +13 -0
- uiprotect-0.1.0/src/uiprotect/__main__.py +24 -0
- uiprotect-0.1.0/src/uiprotect/api.py +1936 -0
- uiprotect-0.1.0/src/uiprotect/cli/__init__.py +314 -0
- uiprotect-0.1.0/src/uiprotect/cli/backup.py +1103 -0
- uiprotect-0.1.0/src/uiprotect/cli/base.py +238 -0
- uiprotect-0.1.0/src/uiprotect/cli/cameras.py +574 -0
- uiprotect-0.1.0/src/uiprotect/cli/chimes.py +180 -0
- uiprotect-0.1.0/src/uiprotect/cli/doorlocks.py +125 -0
- uiprotect-0.1.0/src/uiprotect/cli/events.py +258 -0
- uiprotect-0.1.0/src/uiprotect/cli/lights.py +119 -0
- uiprotect-0.1.0/src/uiprotect/cli/liveviews.py +65 -0
- uiprotect-0.1.0/src/uiprotect/cli/nvr.py +154 -0
- uiprotect-0.1.0/src/uiprotect/cli/sensors.py +278 -0
- uiprotect-0.1.0/src/uiprotect/cli/viewers.py +76 -0
- uiprotect-0.1.0/src/uiprotect/data/__init__.py +157 -0
- uiprotect-0.1.0/src/uiprotect/data/base.py +1116 -0
- uiprotect-0.1.0/src/uiprotect/data/bootstrap.py +634 -0
- uiprotect-0.1.0/src/uiprotect/data/convert.py +77 -0
- uiprotect-0.1.0/src/uiprotect/data/devices.py +3384 -0
- uiprotect-0.1.0/src/uiprotect/data/nvr.py +1520 -0
- uiprotect-0.1.0/src/uiprotect/data/types.py +630 -0
- uiprotect-0.1.0/src/uiprotect/data/user.py +236 -0
- uiprotect-0.1.0/src/uiprotect/data/websocket.py +236 -0
- uiprotect-0.1.0/src/uiprotect/exceptions.py +41 -0
- uiprotect-0.1.0/src/uiprotect/py.typed +0 -0
- uiprotect-0.1.0/src/uiprotect/release_cache.json +1 -0
- uiprotect-0.1.0/src/uiprotect/stream.py +166 -0
- uiprotect-0.1.0/src/uiprotect/test_util/__init__.py +531 -0
- uiprotect-0.1.0/src/uiprotect/test_util/anonymize.py +257 -0
- uiprotect-0.1.0/src/uiprotect/utils.py +610 -0
- uiprotect-0.1.0/src/uiprotect/websocket.py +225 -0
uiprotect-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
|
|
2
|
+
MIT License
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2024 UI Protect Maintainers
|
|
5
|
+
Copyright (c) 2020 Bjarne Riis
|
|
6
|
+
|
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
in the Software without restriction, including without limitation the rights
|
|
10
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
furnished to do so, subject to the following conditions:
|
|
13
|
+
|
|
14
|
+
The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
copies or substantial portions of the Software.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
SOFTWARE.
|
uiprotect-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: uiprotect
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python API for Unifi Protect (Unofficial)
|
|
5
|
+
Home-page: https://github.com/uilibs/uiprotect
|
|
6
|
+
License: MIT
|
|
7
|
+
Author: UI Protect Maintainers
|
|
8
|
+
Author-email: ui@koston.org
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Natural Language :: English
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
20
|
+
Requires-Dist: aiofiles (>=23)
|
|
21
|
+
Requires-Dist: aiohttp (>=3.9.0)
|
|
22
|
+
Requires-Dist: aioshutil (>=1.3)
|
|
23
|
+
Requires-Dist: async-timeout (>=3.0.1)
|
|
24
|
+
Requires-Dist: dateparser (>=1.1.0)
|
|
25
|
+
Requires-Dist: orjson (>=3.9)
|
|
26
|
+
Requires-Dist: packaging (>=23)
|
|
27
|
+
Requires-Dist: pillow (>=10)
|
|
28
|
+
Requires-Dist: platformdirs (>=4)
|
|
29
|
+
Requires-Dist: pydantic (!=1.9.1)
|
|
30
|
+
Requires-Dist: pyjwt (>=2.6)
|
|
31
|
+
Requires-Dist: rich (>=10)
|
|
32
|
+
Requires-Dist: typer[all] (>0.6)
|
|
33
|
+
Requires-Dist: yarl (>=1.9)
|
|
34
|
+
Project-URL: Bug Tracker, https://github.com/uilibs/uiprotect/issues
|
|
35
|
+
Project-URL: Changelog, https://github.com/uilibs/uiprotect/blob/main/CHANGELOG.md
|
|
36
|
+
Project-URL: Documentation, https://uiprotect.readthedocs.io
|
|
37
|
+
Project-URL: Repository, https://github.com/uilibs/uiprotect
|
|
38
|
+
Description-Content-Type: text/markdown
|
|
39
|
+
|
|
40
|
+
# Unofficial UniFi Protect Python API and CLI
|
|
41
|
+
|
|
42
|
+
<p align="center">
|
|
43
|
+
<a href="https://github.com/uilibs/uiprotect/actions/workflows/ci.yml?query=branch%3Amain">
|
|
44
|
+
<img src="https://img.shields.io/github/actions/workflow/status/uilibs/uiprotect/ci.yml?branch=main&label=CI&logo=github&style=flat-square" alt="CI Status" >
|
|
45
|
+
</a>
|
|
46
|
+
<a href="https://uiprotect.readthedocs.io">
|
|
47
|
+
<img src="https://img.shields.io/readthedocs/uiprotect.svg?logo=read-the-docs&logoColor=fff&style=flat-square" alt="Documentation Status">
|
|
48
|
+
</a>
|
|
49
|
+
<a href="https://codecov.io/gh/uilibs/uiprotect">
|
|
50
|
+
<img src="https://img.shields.io/codecov/c/github/uilibs/uiprotect.svg?logo=codecov&logoColor=fff&style=flat-square" alt="Test coverage percentage">
|
|
51
|
+
</a>
|
|
52
|
+
</p>
|
|
53
|
+
<p align="center">
|
|
54
|
+
<a href="https://python-poetry.org/">
|
|
55
|
+
<img src="https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json" alt="Poetry">
|
|
56
|
+
</a>
|
|
57
|
+
<a href="https://github.com/astral-sh/ruff">
|
|
58
|
+
<img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff">
|
|
59
|
+
</a>
|
|
60
|
+
<a href="https://github.com/pre-commit/pre-commit">
|
|
61
|
+
<img src="https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white&style=flat-square" alt="pre-commit">
|
|
62
|
+
</a>
|
|
63
|
+
</p>
|
|
64
|
+
<p align="center">
|
|
65
|
+
<a href="https://pypi.org/project/uiprotect/">
|
|
66
|
+
<img src="https://img.shields.io/pypi/v/uiprotect.svg?logo=python&logoColor=fff&style=flat-square" alt="PyPI Version">
|
|
67
|
+
</a>
|
|
68
|
+
<img src="https://img.shields.io/pypi/pyversions/uiprotect.svg?style=flat-square&logo=python&logoColor=fff" alt="Supported Python versions">
|
|
69
|
+
<img src="https://img.shields.io/pypi/l/uiprotect.svg?style=flat-square" alt="License">
|
|
70
|
+
</p>
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
**Documentation**: <a href="https://uiprotect.readthedocs.io" target="_blank">https://uiprotect.readthedocs.io </a>
|
|
75
|
+
|
|
76
|
+
**Source Code**: <a href="https://github.com/uilibs/uiprotect" target="_blank">https://github.com/uilibs/uiprotect </a>
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
Python API for Unifi Protect (Unofficial)
|
|
81
|
+
|
|
82
|
+
## Installation
|
|
83
|
+
|
|
84
|
+
Install this via pip (or your favorite package manager):
|
|
85
|
+
|
|
86
|
+
`pip install uiprotect`
|
|
87
|
+
|
|
88
|
+
## Credits
|
|
89
|
+
|
|
90
|
+
- Bjarne Riis ([@briis](https://github.com/briis/)) for the original pyunifiprotect package
|
|
91
|
+
- Christopher Bailey ([@AngellusMortis](https://github.com/AngellusMortis/)) for the maintaining the pyunifiprotect package
|
|
92
|
+
|
|
93
|
+
## Contributors ✨
|
|
94
|
+
|
|
95
|
+
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
|
|
96
|
+
|
|
97
|
+
<!-- prettier-ignore-start -->
|
|
98
|
+
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
|
99
|
+
<!-- markdownlint-disable -->
|
|
100
|
+
<!-- markdownlint-enable -->
|
|
101
|
+
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
|
102
|
+
<!-- prettier-ignore-end -->
|
|
103
|
+
|
|
104
|
+
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
|
|
105
|
+
|
|
106
|
+
`uiprotect` is an unofficial API for UniFi Protect. There is no affiliation with Ubiquiti.
|
|
107
|
+
|
|
108
|
+
This module communicates with UniFi Protect surveillance software installed on a UniFi OS Console such as a Ubiquiti CloudKey+ or UniFi Dream Machine Pro.
|
|
109
|
+
|
|
110
|
+
The API is not documented by Ubiquiti, so there might be misses and/or frequent changes in this module, as Ubiquiti evolves the software.
|
|
111
|
+
|
|
112
|
+
The module is primarily written for the purpose of being used in Home Assistant core [integration for UniFi Protect](https://www.home-assistant.io/integrations/unifiprotect) but might be used for other purposes also.
|
|
113
|
+
|
|
114
|
+
## Smart Detections now Require Remote Access to enable
|
|
115
|
+
|
|
116
|
+
Smart Detections (person, vehicle, animal, face), a feature that previously could be used with local only console, [now requires you to enable remote access to enable](https://community.ui.com/questions/Cannot-enable-Smart-Detections/e3d50641-5c00-4607-9723-453cda557e35#answer/1d146426-89aa-4022-a0ae-fd5000846028).
|
|
117
|
+
|
|
118
|
+
Enabling Remote Access may grant other users access to your console [due to the fact Ubiquiti can reconfigure access controls at any time](https://community.ui.com/questions/Bug-Fix-Cloud-Access-Misconfiguration/fe8d4479-e187-4471-bf95-b2799183ceb7).
|
|
119
|
+
|
|
120
|
+
If you are not okay with the feature being locked behind Remote Access access, [let Ubiquiti know](https://community.ui.com/questions/Cannot-enable-Smart-Detections/e3d50641-5c00-4607-9723-453cda557e35).
|
|
121
|
+
|
|
122
|
+
## Documentation
|
|
123
|
+
|
|
124
|
+
[Full documentation for the project](https://uilibs.github.io/uiprotect/).
|
|
125
|
+
|
|
126
|
+
## Requirements
|
|
127
|
+
|
|
128
|
+
If you want to install `uiprotect` natively, the below are the requirements:
|
|
129
|
+
|
|
130
|
+
- [UniFi Protect](https://ui.com/camera-security) version 1.20+
|
|
131
|
+
- Latest version of library is generally only tested against the two latest minor version. This is either two latest stable versions (such as 1.21.x and 2.0.x) or the latest EA version and stable version (such as 2.2.x EA and 2.1.x).
|
|
132
|
+
- [Python](https://www.python.org/) 3.9+
|
|
133
|
+
- POSIX compatible system
|
|
134
|
+
- Library is only test on Linux, specifically the latest Debian version available for the official Python Docker images, but there is no reason the library should not work on any Linux distro or MacOS.
|
|
135
|
+
- [ffmpeg](https://ffmpeg.org/)
|
|
136
|
+
- ffmpeg is primarily only for streaming audio to Protect cameras, this can be considered a soft requirement
|
|
137
|
+
|
|
138
|
+
Alternatively you can use the [provided Docker container](#using-docker-container), in which case the only requirement is [Docker](https://docs.docker.com/desktop/) or another OCI compatible orchestrator (such as Kubernetes or podman).
|
|
139
|
+
|
|
140
|
+
Windows is **not supported**. If you need to use `uiprotect` on Windows, use Docker Desktop and the provided docker container or [WSL](https://docs.microsoft.com/en-us/windows/wsl/install).
|
|
141
|
+
|
|
142
|
+
## Install
|
|
143
|
+
|
|
144
|
+
### From PyPi
|
|
145
|
+
|
|
146
|
+
`uiprotect` is available on PyPi:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
pip install uiprotect
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### From Github
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
pip install git+https://github.com/uilibs/uiprotect.git#egg=uiprotect
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Using Docker Container
|
|
159
|
+
|
|
160
|
+
A Docker container is also provided so you do not need to install/manage Python as well. You can add the following to your `.bashrc` or similar.
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
function unifi-protect() {
|
|
164
|
+
docker run --rm -it \
|
|
165
|
+
-e UFP_USERNAME=YOUR_USERNAME_HERE \
|
|
166
|
+
-e UFP_PASSWORD=YOUR_PASSWORD_HERE \
|
|
167
|
+
-e UFP_ADDRESS=YOUR_IP_ADDRESS \
|
|
168
|
+
-e UFP_PORT=443 \
|
|
169
|
+
-e UFP_SSL_VERIFY=True \
|
|
170
|
+
-e TZ=America/New_York \
|
|
171
|
+
-v $PWD:/data ghcr.io/uilibs/uiprotect:latest "$@"
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Some notes about the Docker version since it is running inside of a container:
|
|
176
|
+
|
|
177
|
+
- You can update at any time using the command `docker pull ghcr.io/uilibs/uiprotect:latest`
|
|
178
|
+
- Your local current working directory (`$PWD`) will automatically be mounted to `/data` inside of the container. For commands that output files, this is the _only_ path you can write to and have the file persist.
|
|
179
|
+
- The container supports `linux/amd64` and `linux/arm64` natively. This means it will also work well on MacOS or Windows using Docker Desktop.
|
|
180
|
+
- `TZ` should be the [Olson timezone name](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) for the timezone your UniFi Protect instance is in.
|
|
181
|
+
- For more details on `TZ` and other environment variables, check the [command line docs](https://uilibs.github.io/uiprotect/latest/cli/)
|
|
182
|
+
|
|
183
|
+
## Quickstart
|
|
184
|
+
|
|
185
|
+
### CLI
|
|
186
|
+
|
|
187
|
+
!!! warning "About Ubiquiti SSO accounts"
|
|
188
|
+
Ubiquiti SSO accounts are not supported and actively discouraged from being used. There is no option to use MFA. You are expected to use local access user. `uiprotect` is not designed to allow you to use your owner account to access the your console or to be used over the public Internet as both pose a security risk.
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
export UFP_USERNAME=YOUR_USERNAME_HERE
|
|
192
|
+
export UFP_PASSWORD=YOUR_PASSWORD_HERE
|
|
193
|
+
export UFP_ADDRESS=YOUR_IP_ADDRESS
|
|
194
|
+
export UFP_PORT=443
|
|
195
|
+
# change to false if you do not have a valid HTTPS Certificate for your instance
|
|
196
|
+
export UFP_SSL_VERIFY=True
|
|
197
|
+
|
|
198
|
+
unifi-protect --help
|
|
199
|
+
unifi-protect nvr
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Python
|
|
203
|
+
|
|
204
|
+
UniFi Protect itself is 100% async, so as such this library is primarily designed to be used in an async context.
|
|
205
|
+
|
|
206
|
+
The main interface for the library is the `uiprotect.ProtectApiClient`:
|
|
207
|
+
|
|
208
|
+
```python
|
|
209
|
+
from uiprotect import ProtectApiClient
|
|
210
|
+
|
|
211
|
+
protect = ProtectApiClient(host, port, username, password, verify_ssl=True)
|
|
212
|
+
|
|
213
|
+
await protect.update() # this will initialize the protect .bootstrap and open a Websocket connection for updates
|
|
214
|
+
|
|
215
|
+
# get names of your cameras
|
|
216
|
+
for camera in protect.bootstrap.cameras.values():
|
|
217
|
+
print(camera.name)
|
|
218
|
+
|
|
219
|
+
# subscribe to Websocket for updates to UFP
|
|
220
|
+
def callback(msg: WSSubscriptionMessage):
|
|
221
|
+
# do stuff
|
|
222
|
+
|
|
223
|
+
unsub = protect.subscribe_websocket(callback)
|
|
224
|
+
|
|
225
|
+
# remove subscription
|
|
226
|
+
unsub()
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## TODO / Planned / Not Implemented
|
|
231
|
+
|
|
232
|
+
Generally any feature missing from the library is planned to be done eventually / nice to have with the following exceptions
|
|
233
|
+
|
|
234
|
+
### UniFi OS Features
|
|
235
|
+
|
|
236
|
+
Anything that is strictly a UniFi OS feature. If it ever done, it will be in a separate library that interacts with this one. Examples include:
|
|
237
|
+
|
|
238
|
+
- Managing RAID and disks
|
|
239
|
+
- Creating and managing users
|
|
240
|
+
|
|
241
|
+
Examples include:
|
|
242
|
+
|
|
243
|
+
- Stream sharing
|
|
244
|
+
- Smart Detections, including person, vehicle, animals license plate and faces
|
|
245
|
+
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# Unofficial UniFi Protect Python API and CLI
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<a href="https://github.com/uilibs/uiprotect/actions/workflows/ci.yml?query=branch%3Amain">
|
|
5
|
+
<img src="https://img.shields.io/github/actions/workflow/status/uilibs/uiprotect/ci.yml?branch=main&label=CI&logo=github&style=flat-square" alt="CI Status" >
|
|
6
|
+
</a>
|
|
7
|
+
<a href="https://uiprotect.readthedocs.io">
|
|
8
|
+
<img src="https://img.shields.io/readthedocs/uiprotect.svg?logo=read-the-docs&logoColor=fff&style=flat-square" alt="Documentation Status">
|
|
9
|
+
</a>
|
|
10
|
+
<a href="https://codecov.io/gh/uilibs/uiprotect">
|
|
11
|
+
<img src="https://img.shields.io/codecov/c/github/uilibs/uiprotect.svg?logo=codecov&logoColor=fff&style=flat-square" alt="Test coverage percentage">
|
|
12
|
+
</a>
|
|
13
|
+
</p>
|
|
14
|
+
<p align="center">
|
|
15
|
+
<a href="https://python-poetry.org/">
|
|
16
|
+
<img src="https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json" alt="Poetry">
|
|
17
|
+
</a>
|
|
18
|
+
<a href="https://github.com/astral-sh/ruff">
|
|
19
|
+
<img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff">
|
|
20
|
+
</a>
|
|
21
|
+
<a href="https://github.com/pre-commit/pre-commit">
|
|
22
|
+
<img src="https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white&style=flat-square" alt="pre-commit">
|
|
23
|
+
</a>
|
|
24
|
+
</p>
|
|
25
|
+
<p align="center">
|
|
26
|
+
<a href="https://pypi.org/project/uiprotect/">
|
|
27
|
+
<img src="https://img.shields.io/pypi/v/uiprotect.svg?logo=python&logoColor=fff&style=flat-square" alt="PyPI Version">
|
|
28
|
+
</a>
|
|
29
|
+
<img src="https://img.shields.io/pypi/pyversions/uiprotect.svg?style=flat-square&logo=python&logoColor=fff" alt="Supported Python versions">
|
|
30
|
+
<img src="https://img.shields.io/pypi/l/uiprotect.svg?style=flat-square" alt="License">
|
|
31
|
+
</p>
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
**Documentation**: <a href="https://uiprotect.readthedocs.io" target="_blank">https://uiprotect.readthedocs.io </a>
|
|
36
|
+
|
|
37
|
+
**Source Code**: <a href="https://github.com/uilibs/uiprotect" target="_blank">https://github.com/uilibs/uiprotect </a>
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
Python API for Unifi Protect (Unofficial)
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
Install this via pip (or your favorite package manager):
|
|
46
|
+
|
|
47
|
+
`pip install uiprotect`
|
|
48
|
+
|
|
49
|
+
## Credits
|
|
50
|
+
|
|
51
|
+
- Bjarne Riis ([@briis](https://github.com/briis/)) for the original pyunifiprotect package
|
|
52
|
+
- Christopher Bailey ([@AngellusMortis](https://github.com/AngellusMortis/)) for the maintaining the pyunifiprotect package
|
|
53
|
+
|
|
54
|
+
## Contributors ✨
|
|
55
|
+
|
|
56
|
+
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
|
|
57
|
+
|
|
58
|
+
<!-- prettier-ignore-start -->
|
|
59
|
+
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
|
60
|
+
<!-- markdownlint-disable -->
|
|
61
|
+
<!-- markdownlint-enable -->
|
|
62
|
+
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
|
63
|
+
<!-- prettier-ignore-end -->
|
|
64
|
+
|
|
65
|
+
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
|
|
66
|
+
|
|
67
|
+
`uiprotect` is an unofficial API for UniFi Protect. There is no affiliation with Ubiquiti.
|
|
68
|
+
|
|
69
|
+
This module communicates with UniFi Protect surveillance software installed on a UniFi OS Console such as a Ubiquiti CloudKey+ or UniFi Dream Machine Pro.
|
|
70
|
+
|
|
71
|
+
The API is not documented by Ubiquiti, so there might be misses and/or frequent changes in this module, as Ubiquiti evolves the software.
|
|
72
|
+
|
|
73
|
+
The module is primarily written for the purpose of being used in Home Assistant core [integration for UniFi Protect](https://www.home-assistant.io/integrations/unifiprotect) but might be used for other purposes also.
|
|
74
|
+
|
|
75
|
+
## Smart Detections now Require Remote Access to enable
|
|
76
|
+
|
|
77
|
+
Smart Detections (person, vehicle, animal, face), a feature that previously could be used with local only console, [now requires you to enable remote access to enable](https://community.ui.com/questions/Cannot-enable-Smart-Detections/e3d50641-5c00-4607-9723-453cda557e35#answer/1d146426-89aa-4022-a0ae-fd5000846028).
|
|
78
|
+
|
|
79
|
+
Enabling Remote Access may grant other users access to your console [due to the fact Ubiquiti can reconfigure access controls at any time](https://community.ui.com/questions/Bug-Fix-Cloud-Access-Misconfiguration/fe8d4479-e187-4471-bf95-b2799183ceb7).
|
|
80
|
+
|
|
81
|
+
If you are not okay with the feature being locked behind Remote Access access, [let Ubiquiti know](https://community.ui.com/questions/Cannot-enable-Smart-Detections/e3d50641-5c00-4607-9723-453cda557e35).
|
|
82
|
+
|
|
83
|
+
## Documentation
|
|
84
|
+
|
|
85
|
+
[Full documentation for the project](https://uilibs.github.io/uiprotect/).
|
|
86
|
+
|
|
87
|
+
## Requirements
|
|
88
|
+
|
|
89
|
+
If you want to install `uiprotect` natively, the below are the requirements:
|
|
90
|
+
|
|
91
|
+
- [UniFi Protect](https://ui.com/camera-security) version 1.20+
|
|
92
|
+
- Latest version of library is generally only tested against the two latest minor version. This is either two latest stable versions (such as 1.21.x and 2.0.x) or the latest EA version and stable version (such as 2.2.x EA and 2.1.x).
|
|
93
|
+
- [Python](https://www.python.org/) 3.9+
|
|
94
|
+
- POSIX compatible system
|
|
95
|
+
- Library is only test on Linux, specifically the latest Debian version available for the official Python Docker images, but there is no reason the library should not work on any Linux distro or MacOS.
|
|
96
|
+
- [ffmpeg](https://ffmpeg.org/)
|
|
97
|
+
- ffmpeg is primarily only for streaming audio to Protect cameras, this can be considered a soft requirement
|
|
98
|
+
|
|
99
|
+
Alternatively you can use the [provided Docker container](#using-docker-container), in which case the only requirement is [Docker](https://docs.docker.com/desktop/) or another OCI compatible orchestrator (such as Kubernetes or podman).
|
|
100
|
+
|
|
101
|
+
Windows is **not supported**. If you need to use `uiprotect` on Windows, use Docker Desktop and the provided docker container or [WSL](https://docs.microsoft.com/en-us/windows/wsl/install).
|
|
102
|
+
|
|
103
|
+
## Install
|
|
104
|
+
|
|
105
|
+
### From PyPi
|
|
106
|
+
|
|
107
|
+
`uiprotect` is available on PyPi:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
pip install uiprotect
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### From Github
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
pip install git+https://github.com/uilibs/uiprotect.git#egg=uiprotect
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Using Docker Container
|
|
120
|
+
|
|
121
|
+
A Docker container is also provided so you do not need to install/manage Python as well. You can add the following to your `.bashrc` or similar.
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
function unifi-protect() {
|
|
125
|
+
docker run --rm -it \
|
|
126
|
+
-e UFP_USERNAME=YOUR_USERNAME_HERE \
|
|
127
|
+
-e UFP_PASSWORD=YOUR_PASSWORD_HERE \
|
|
128
|
+
-e UFP_ADDRESS=YOUR_IP_ADDRESS \
|
|
129
|
+
-e UFP_PORT=443 \
|
|
130
|
+
-e UFP_SSL_VERIFY=True \
|
|
131
|
+
-e TZ=America/New_York \
|
|
132
|
+
-v $PWD:/data ghcr.io/uilibs/uiprotect:latest "$@"
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Some notes about the Docker version since it is running inside of a container:
|
|
137
|
+
|
|
138
|
+
- You can update at any time using the command `docker pull ghcr.io/uilibs/uiprotect:latest`
|
|
139
|
+
- Your local current working directory (`$PWD`) will automatically be mounted to `/data` inside of the container. For commands that output files, this is the _only_ path you can write to and have the file persist.
|
|
140
|
+
- The container supports `linux/amd64` and `linux/arm64` natively. This means it will also work well on MacOS or Windows using Docker Desktop.
|
|
141
|
+
- `TZ` should be the [Olson timezone name](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) for the timezone your UniFi Protect instance is in.
|
|
142
|
+
- For more details on `TZ` and other environment variables, check the [command line docs](https://uilibs.github.io/uiprotect/latest/cli/)
|
|
143
|
+
|
|
144
|
+
## Quickstart
|
|
145
|
+
|
|
146
|
+
### CLI
|
|
147
|
+
|
|
148
|
+
!!! warning "About Ubiquiti SSO accounts"
|
|
149
|
+
Ubiquiti SSO accounts are not supported and actively discouraged from being used. There is no option to use MFA. You are expected to use local access user. `uiprotect` is not designed to allow you to use your owner account to access the your console or to be used over the public Internet as both pose a security risk.
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
export UFP_USERNAME=YOUR_USERNAME_HERE
|
|
153
|
+
export UFP_PASSWORD=YOUR_PASSWORD_HERE
|
|
154
|
+
export UFP_ADDRESS=YOUR_IP_ADDRESS
|
|
155
|
+
export UFP_PORT=443
|
|
156
|
+
# change to false if you do not have a valid HTTPS Certificate for your instance
|
|
157
|
+
export UFP_SSL_VERIFY=True
|
|
158
|
+
|
|
159
|
+
unifi-protect --help
|
|
160
|
+
unifi-protect nvr
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Python
|
|
164
|
+
|
|
165
|
+
UniFi Protect itself is 100% async, so as such this library is primarily designed to be used in an async context.
|
|
166
|
+
|
|
167
|
+
The main interface for the library is the `uiprotect.ProtectApiClient`:
|
|
168
|
+
|
|
169
|
+
```python
|
|
170
|
+
from uiprotect import ProtectApiClient
|
|
171
|
+
|
|
172
|
+
protect = ProtectApiClient(host, port, username, password, verify_ssl=True)
|
|
173
|
+
|
|
174
|
+
await protect.update() # this will initialize the protect .bootstrap and open a Websocket connection for updates
|
|
175
|
+
|
|
176
|
+
# get names of your cameras
|
|
177
|
+
for camera in protect.bootstrap.cameras.values():
|
|
178
|
+
print(camera.name)
|
|
179
|
+
|
|
180
|
+
# subscribe to Websocket for updates to UFP
|
|
181
|
+
def callback(msg: WSSubscriptionMessage):
|
|
182
|
+
# do stuff
|
|
183
|
+
|
|
184
|
+
unsub = protect.subscribe_websocket(callback)
|
|
185
|
+
|
|
186
|
+
# remove subscription
|
|
187
|
+
unsub()
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## TODO / Planned / Not Implemented
|
|
192
|
+
|
|
193
|
+
Generally any feature missing from the library is planned to be done eventually / nice to have with the following exceptions
|
|
194
|
+
|
|
195
|
+
### UniFi OS Features
|
|
196
|
+
|
|
197
|
+
Anything that is strictly a UniFi OS feature. If it ever done, it will be in a separate library that interacts with this one. Examples include:
|
|
198
|
+
|
|
199
|
+
- Managing RAID and disks
|
|
200
|
+
- Creating and managing users
|
|
201
|
+
|
|
202
|
+
Examples include:
|
|
203
|
+
|
|
204
|
+
- Stream sharing
|
|
205
|
+
- Smart Detections, including person, vehicle, animals license plate and faces
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "uiprotect"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Python API for Unifi Protect (Unofficial)"
|
|
5
|
+
authors = ["UI Protect Maintainers <ui@koston.org>"]
|
|
6
|
+
license = "MIT"
|
|
7
|
+
readme = "README.md"
|
|
8
|
+
repository = "https://github.com/uilibs/uiprotect"
|
|
9
|
+
documentation = "https://uiprotect.readthedocs.io"
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Development Status :: 2 - Pre-Alpha",
|
|
12
|
+
"Intended Audience :: Developers",
|
|
13
|
+
"Natural Language :: English",
|
|
14
|
+
"Operating System :: OS Independent",
|
|
15
|
+
"Topic :: Software Development :: Libraries",
|
|
16
|
+
]
|
|
17
|
+
packages = [
|
|
18
|
+
{ include = "uiprotect", from = "src" },
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
[tool.poetry.urls]
|
|
22
|
+
"Bug Tracker" = "https://github.com/uilibs/uiprotect/issues"
|
|
23
|
+
"Changelog" = "https://github.com/uilibs/uiprotect/blob/main/CHANGELOG.md"
|
|
24
|
+
|
|
25
|
+
[tool.poetry.scripts]
|
|
26
|
+
uiprotect = "uiprotect.cli:app"
|
|
27
|
+
|
|
28
|
+
[tool.poetry.dependencies]
|
|
29
|
+
python = ">=3.10"
|
|
30
|
+
rich = ">=10"
|
|
31
|
+
typer = {version = ">0.6", extras = ["all"]}
|
|
32
|
+
async-timeout = ">=3.0.1"
|
|
33
|
+
aiofiles = ">=23"
|
|
34
|
+
aiohttp = ">=3.9.0"
|
|
35
|
+
aioshutil = ">=1.3"
|
|
36
|
+
dateparser = ">=1.1.0"
|
|
37
|
+
orjson = ">=3.9"
|
|
38
|
+
packaging = ">=23"
|
|
39
|
+
pillow = ">=10"
|
|
40
|
+
platformdirs = ">=4"
|
|
41
|
+
pydantic = "!=1.9.1"
|
|
42
|
+
pyjwt = ">=2.6"
|
|
43
|
+
yarl = ">=1.9"
|
|
44
|
+
|
|
45
|
+
[tool.poetry.group.dev.dependencies]
|
|
46
|
+
pytest = "^7.0"
|
|
47
|
+
pytest-cov = "^3.0"
|
|
48
|
+
aiosqlite = ">=0.20.0"
|
|
49
|
+
asttokens = "^2.4.1"
|
|
50
|
+
pytest-asyncio = "^0.23.7"
|
|
51
|
+
pytest-benchmark = "^4.0.0"
|
|
52
|
+
pytest-sugar = "^1.0.0"
|
|
53
|
+
pytest-timeout = "^2.3.1"
|
|
54
|
+
pytest-xdist = "^3.6.1"
|
|
55
|
+
types-aiofiles = "^23.2.0.20240403"
|
|
56
|
+
types-dateparser = "^1.2.0.20240420"
|
|
57
|
+
mypy = "^1.10.0"
|
|
58
|
+
|
|
59
|
+
[tool.poetry.group.docs]
|
|
60
|
+
optional = true
|
|
61
|
+
|
|
62
|
+
[tool.poetry.group.docs.dependencies]
|
|
63
|
+
myst-parser = { version = ">=0.16", python = ">=3.11"}
|
|
64
|
+
sphinx = { version = ">=4.0", python = ">=3.11"}
|
|
65
|
+
furo = { version = ">=2023.5.20", python = ">=3.11"}
|
|
66
|
+
sphinx-autobuild = { version = ">=2024.0.0", python = ">=3.11"}
|
|
67
|
+
|
|
68
|
+
[tool.semantic_release]
|
|
69
|
+
version_toml = ["pyproject.toml:tool.poetry.version"]
|
|
70
|
+
version_variables = [
|
|
71
|
+
"src/uiprotect/__init__.py:__version__",
|
|
72
|
+
"docs/conf.py:release",
|
|
73
|
+
]
|
|
74
|
+
build_command = "pip install poetry && poetry build"
|
|
75
|
+
|
|
76
|
+
[tool.semantic_release.changelog]
|
|
77
|
+
exclude_commit_patterns = [
|
|
78
|
+
"chore*",
|
|
79
|
+
"ci*",
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
[tool.semantic_release.changelog.environment]
|
|
83
|
+
keep_trailing_newline = true
|
|
84
|
+
|
|
85
|
+
[tool.semantic_release.branches.main]
|
|
86
|
+
match = "main"
|
|
87
|
+
|
|
88
|
+
[tool.semantic_release.branches.noop]
|
|
89
|
+
match = "(?!main$)"
|
|
90
|
+
prerelease = true
|
|
91
|
+
|
|
92
|
+
[tool.pytest.ini_options]
|
|
93
|
+
addopts = "-v -Wdefault --cov=uiprotect --cov-report=term-missing:skip-covered -n=auto"
|
|
94
|
+
pythonpath = ["src"]
|
|
95
|
+
|
|
96
|
+
[tool.coverage.run]
|
|
97
|
+
branch = true
|
|
98
|
+
|
|
99
|
+
[tool.coverage.report]
|
|
100
|
+
exclude_lines = [
|
|
101
|
+
"pragma: no cover",
|
|
102
|
+
"@overload",
|
|
103
|
+
"if TYPE_CHECKING",
|
|
104
|
+
"raise NotImplementedError",
|
|
105
|
+
'if __name__ == "__main__":',
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
[tool.ruff]
|
|
109
|
+
target-version = "py38"
|
|
110
|
+
line-length = 88
|
|
111
|
+
|
|
112
|
+
[tool.ruff.lint]
|
|
113
|
+
ignore = [
|
|
114
|
+
"S101", # use of assert
|
|
115
|
+
"D203", # 1 blank line required before class docstring
|
|
116
|
+
"D212", # Multi-line docstring summary should start at the first line
|
|
117
|
+
"D100", # Missing docstring in public module
|
|
118
|
+
"D101", # Missing docstring in public module
|
|
119
|
+
"D102", # Missing docstring in public method
|
|
120
|
+
"D103", # Missing docstring in public module
|
|
121
|
+
"D104", # Missing docstring in public package
|
|
122
|
+
"D105", # Missing docstring in magic method
|
|
123
|
+
"D107", # Missing docstring in `__init__`
|
|
124
|
+
"D400", # First line should end with a period
|
|
125
|
+
"D401", # First line of docstring should be in imperative mood
|
|
126
|
+
"D205", # 1 blank line required between summary line and description
|
|
127
|
+
"D415", # First line should end with a period, question mark, or exclamation point
|
|
128
|
+
"D417", # Missing argument descriptions in the docstring
|
|
129
|
+
"E501", # Line too long
|
|
130
|
+
"RUF012", # Mutable class attributes should be annotated with `typing.ClassVar`
|
|
131
|
+
"B008", # Do not perform function call
|
|
132
|
+
"S110", # `try`-`except`-`pass` detected, consider logging the exception
|
|
133
|
+
"D106", # Missing docstring in public nested class
|
|
134
|
+
"UP007", # typer needs Optional syntax
|
|
135
|
+
]
|
|
136
|
+
select = [
|
|
137
|
+
"B", # flake8-bugbear
|
|
138
|
+
"D", # flake8-docstrings
|
|
139
|
+
"C4", # flake8-comprehensions
|
|
140
|
+
"S", # flake8-bandit
|
|
141
|
+
"F", # pyflake
|
|
142
|
+
"E", # pycodestyle
|
|
143
|
+
"W", # pycodestyle
|
|
144
|
+
"UP", # pyupgrade
|
|
145
|
+
"I", # isort
|
|
146
|
+
"RUF", # ruff specific
|
|
147
|
+
]
|
|
148
|
+
|
|
149
|
+
[tool.ruff.lint.per-file-ignores]
|
|
150
|
+
"tests/**/*" = [
|
|
151
|
+
"D100",
|
|
152
|
+
"D101",
|
|
153
|
+
"D102",
|
|
154
|
+
"D103",
|
|
155
|
+
"D104",
|
|
156
|
+
"S101",
|
|
157
|
+
]
|
|
158
|
+
"setup.py" = ["D100"]
|
|
159
|
+
"conftest.py" = ["D100"]
|
|
160
|
+
"docs/conf.py" = ["D100"]
|
|
161
|
+
|
|
162
|
+
[tool.ruff.isort]
|
|
163
|
+
known-first-party = ["uiprotect", "tests"]
|
|
164
|
+
|
|
165
|
+
[tool.mypy]
|
|
166
|
+
disable_error_code = "import-untyped,unused-ignore"
|
|
167
|
+
check_untyped_defs = true
|
|
168
|
+
ignore_missing_imports = true
|
|
169
|
+
disallow_any_generics = true
|
|
170
|
+
disallow_incomplete_defs = true
|
|
171
|
+
disallow_untyped_defs = true
|
|
172
|
+
mypy_path = "src/"
|
|
173
|
+
no_implicit_optional = true
|
|
174
|
+
show_error_codes = true
|
|
175
|
+
warn_unreachable = true
|
|
176
|
+
warn_unused_ignores = true
|
|
177
|
+
exclude = [
|
|
178
|
+
'docs/.*',
|
|
179
|
+
'setup.py',
|
|
180
|
+
]
|
|
181
|
+
|
|
182
|
+
[[tool.mypy.overrides]]
|
|
183
|
+
module = "tests.*"
|
|
184
|
+
allow_untyped_defs = true
|
|
185
|
+
|
|
186
|
+
[[tool.mypy.overrides]]
|
|
187
|
+
module = "docs.*"
|
|
188
|
+
ignore_errors = true
|
|
189
|
+
|
|
190
|
+
[build-system]
|
|
191
|
+
requires = ["poetry-core>=1.0.0"]
|
|
192
|
+
build-backend = "poetry.core.masonry.api"
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Unofficial UniFi Protect Python API and Command Line Interface."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from uiprotect.api import ProtectApiClient
|
|
6
|
+
from uiprotect.exceptions import Invalid, NotAuthorized, NvrError
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"Invalid",
|
|
10
|
+
"NotAuthorized",
|
|
11
|
+
"NvrError",
|
|
12
|
+
"ProtectApiClient",
|
|
13
|
+
]
|