From 91c92b0fcb721f94f9472a432f3e8d3e81774135 Mon Sep 17 00:00:00 2001 From: Bobrock Date: Sun, 13 Dec 2020 12:41:46 -0600 Subject: [PATCH] Apply intial changes to make repo perform better as a Python module --- Pipfile | 16 -- Pipfile.lock | 169 ------------------ README.md | 113 +----------- api/__init__.py | 4 - {api => reolink_api}/APIHandler.py | 30 ++-- Camera.py => reolink_api/Camera.py | 4 +- .../ConfigHandler.py | 1 - RtspClient.py => reolink_api/RtspClient.py | 7 +- reolink_api/__init__.py | 4 + {api => reolink_api}/alarm.py | 0 {api => reolink_api}/device.py | 9 +- {api => reolink_api}/display.py | 0 reolink_api/download.py | 15 ++ {api => reolink_api}/image.py | 42 ++--- reolink_api/motion.py | 41 +++++ {api => reolink_api}/network.py | 6 +- {api => reolink_api}/ptz.py | 0 {api => reolink_api}/recording.py | 2 +- resthandle.py => reolink_api/resthandle.py | 4 +- {api => reolink_api}/system.py | 0 {api => reolink_api}/user.py | 0 util.py => reolink_api/util.py | 0 {api => reolink_api}/zoom.py | 0 requirements.txt | 4 - setup.py | 88 ++++----- test.py | 5 - 26 files changed, 158 insertions(+), 406 deletions(-) delete mode 100644 Pipfile delete mode 100644 Pipfile.lock delete mode 100644 api/__init__.py rename {api => reolink_api}/APIHandler.py (92%) rename Camera.py => reolink_api/Camera.py (84%) rename ConfigHandler.py => reolink_api/ConfigHandler.py (99%) rename RtspClient.py => reolink_api/RtspClient.py (94%) create mode 100644 reolink_api/__init__.py rename {api => reolink_api}/alarm.py (100%) rename {api => reolink_api}/device.py (83%) rename {api => reolink_api}/display.py (100%) create mode 100644 reolink_api/download.py rename {api => reolink_api}/image.py (67%) create mode 100644 reolink_api/motion.py rename {api => reolink_api}/network.py (94%) rename {api => reolink_api}/ptz.py (100%) rename {api => reolink_api}/recording.py (99%) rename resthandle.py => reolink_api/resthandle.py (94%) rename {api => reolink_api}/system.py (100%) rename {api => reolink_api}/user.py (100%) rename util.py => reolink_api/util.py (100%) rename {api => reolink_api}/zoom.py (100%) delete mode 100644 requirements.txt delete mode 100644 test.py diff --git a/Pipfile b/Pipfile deleted file mode 100644 index defbd59..0000000 --- a/Pipfile +++ /dev/null @@ -1,16 +0,0 @@ -[[source]] -name = "pypi" -url = "https://pypi.org/simple" -verify_ssl = true - -[dev-packages] - -[packages] -pillow = "*" -pyyaml = "*" -requests = "*" -numpy = "*" -opencv-python = "*" -pysocks = "*" - -[requires] diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index 15b8698..0000000 --- a/Pipfile.lock +++ /dev/null @@ -1,169 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "6700bce6ed08db166eff9d3105158923ffd2ffbf35c814a4d0133552bda03b5a" - }, - "pipfile-spec": 6, - "requires": {}, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "certifi": { - "hashes": [ - "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3", - "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f" - ], - "version": "==2019.11.28" - }, - "chardet": { - "hashes": [ - "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", - "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" - ], - "version": "==3.0.4" - }, - "idna": { - "hashes": [ - "sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb", - "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa" - ], - "version": "==2.9" - }, - "numpy": { - "hashes": [ - "sha256:1786a08236f2c92ae0e70423c45e1e62788ed33028f94ca99c4df03f5be6b3c6", - "sha256:17aa7a81fe7599a10f2b7d95856dc5cf84a4eefa45bc96123cbbc3ebc568994e", - "sha256:20b26aaa5b3da029942cdcce719b363dbe58696ad182aff0e5dcb1687ec946dc", - "sha256:2d75908ab3ced4223ccba595b48e538afa5ecc37405923d1fea6906d7c3a50bc", - "sha256:39d2c685af15d3ce682c99ce5925cc66efc824652e10990d2462dfe9b8918c6a", - "sha256:56bc8ded6fcd9adea90f65377438f9fea8c05fcf7c5ba766bef258d0da1554aa", - "sha256:590355aeade1a2eaba17617c19edccb7db8d78760175256e3cf94590a1a964f3", - "sha256:70a840a26f4e61defa7bdf811d7498a284ced303dfbc35acb7be12a39b2aa121", - "sha256:77c3bfe65d8560487052ad55c6998a04b654c2fbc36d546aef2b2e511e760971", - "sha256:9537eecf179f566fd1c160a2e912ca0b8e02d773af0a7a1120ad4f7507cd0d26", - "sha256:9acdf933c1fd263c513a2df3dceecea6f3ff4419d80bf238510976bf9bcb26cd", - "sha256:ae0975f42ab1f28364dcda3dde3cf6c1ddab3e1d4b2909da0cb0191fa9ca0480", - "sha256:b3af02ecc999c8003e538e60c89a2b37646b39b688d4e44d7373e11c2debabec", - "sha256:b6ff59cee96b454516e47e7721098e6ceebef435e3e21ac2d6c3b8b02628eb77", - "sha256:b765ed3930b92812aa698a455847141869ef755a87e099fddd4ccf9d81fffb57", - "sha256:c98c5ffd7d41611407a1103ae11c8b634ad6a43606eca3e2a5a269e5d6e8eb07", - "sha256:cf7eb6b1025d3e169989416b1adcd676624c2dbed9e3bcb7137f51bfc8cc2572", - "sha256:d92350c22b150c1cae7ebb0ee8b5670cc84848f6359cf6b5d8f86617098a9b73", - "sha256:e422c3152921cece8b6a2fb6b0b4d73b6579bd20ae075e7d15143e711f3ca2ca", - "sha256:e840f552a509e3380b0f0ec977e8124d0dc34dc0e68289ca28f4d7c1d0d79474", - "sha256:f3d0a94ad151870978fb93538e95411c83899c9dc63e6fb65542f769568ecfa5" - ], - "index": "pypi", - "version": "==1.18.1" - }, - "opencv-python": { - "hashes": [ - "sha256:0f2e739c582e8c5e432130648bc6d66a56bc65f4cd9ff0bc7033033d2130c7a3", - "sha256:0f3d159ad6cb9cbd188c726f87485f0799a067a0a15f34c25d7b5c8db3cb2e50", - "sha256:167a6aff9bd124a3a67e0ec25d0da5ecdc8d96a56405e3e5e7d586c4105eb1bb", - "sha256:1b90d50bc7a31e9573a8da1b80fcd1e4d9c86c0e5f76387858e1b87eb8b0332b", - "sha256:2baf1213ae2fd678991f905d7b2b94eddfdfb5f75757db0f0b31eebd48ca200d", - "sha256:312dda54c7e809c20d7409418060ae0e9cdbe82975e7ced429eb3c234ffc0d4a", - "sha256:32384e675f7cefe707cac40a95eeb142d6869065e39c5500374116297cd8ca6d", - "sha256:5c50634dd8f2f866fd99fd939292ce10e52bef82804ebc4e7f915221c3b7e951", - "sha256:6841bb9cc24751dbdf94e7eefc4e6d70ec297952501954471299fd12ab67391c", - "sha256:68c1c846dd267cd7e293d3fc0bb238db0a744aa1f2e721e327598f00cb982098", - "sha256:703910aaa1dcd25a412f78a190fb7a352d9a64ee7d9a35566d786f3cc66ebf20", - "sha256:8002959146ed21959e3118c60c8e94ceac02eea15b691da6c62cff4787c63f7f", - "sha256:889eef049d38488b5b4646c48a831feed37c0fd44f3d83c05cff80f4baded145", - "sha256:8c76983c9ec3e4cf3a4c1d172ec4285332d9fb1c7194d724aff0c518437471ee", - "sha256:9cd9bd72f4a9743ef6f11f0f96784bd215a542e996db1717d4c2d3d03eb81a1b", - "sha256:a1a5517301dc8d56243a14253d231ec755b94486b4fff2ae68269bc941bb1f2e", - "sha256:a2b08aec2eacae868723136383d9eb84a33062a7a7ec5ec3bd2c423bd1355946", - "sha256:a8529a79233f3581a66984acd16bce52ab0163f6f77568dd69e9ee4956d2e1db", - "sha256:afbc81a3870739610a9f9a1197374d6a45892cf1933c90fc5617d39790991ed3", - "sha256:baeb5dd8b21c718580687f5b4efd03f8139b1c56239cdf6b9805c6946e80f268", - "sha256:db1d49b753e6e6c76585f21d09c7e9812176732baa9bddb64bc2fc6cd24d4179", - "sha256:e242ed419aeb2488e0f9ee6410a34917f0f8d62b3ae96aa3170d83bae75004e2", - "sha256:e36a8857be2c849e54009f1bee25e8c34fbc683fcd38c6c700af4cba5f8d57c2", - "sha256:e699232fd033ef0053efec2cba0a7505514f374ba7b18c732a77cb5304311ef9", - "sha256:eae3da9231d87980f8082d181c276a04f7a6fdac130cebd467390b96dd05f944", - "sha256:ee6814c94dbf1cae569302afef9dd29efafc52373e8770ded0db549a3b6e0c00", - "sha256:f01a87a015227d8af407161eb48222fc3c8b01661cdc841e2b86eee4f1a7a417" - ], - "index": "pypi", - "version": "==4.2.0.32" - }, - "pillow": { - "hashes": [ - "sha256:0a628977ac2e01ca96aaae247ec2bd38e729631ddf2221b4b715446fd45505be", - "sha256:4d9ed9a64095e031435af120d3c910148067087541131e82b3e8db302f4c8946", - "sha256:54ebae163e8412aff0b9df1e88adab65788f5f5b58e625dc5c7f51eaf14a6837", - "sha256:5bfef0b1cdde9f33881c913af14e43db69815c7e8df429ceda4c70a5e529210f", - "sha256:5f3546ceb08089cedb9e8ff7e3f6a7042bb5b37c2a95d392fb027c3e53a2da00", - "sha256:5f7ae9126d16194f114435ebb79cc536b5682002a4fa57fa7bb2cbcde65f2f4d", - "sha256:62a889aeb0a79e50ecf5af272e9e3c164148f4bd9636cc6bcfa182a52c8b0533", - "sha256:7406f5a9b2fd966e79e6abdaf700585a4522e98d6559ce37fc52e5c955fade0a", - "sha256:8453f914f4e5a3d828281a6628cf517832abfa13ff50679a4848926dac7c0358", - "sha256:87269cc6ce1e3dee11f23fa515e4249ae678dbbe2704598a51cee76c52e19cda", - "sha256:875358310ed7abd5320f21dd97351d62de4929b0426cdb1eaa904b64ac36b435", - "sha256:8ac6ce7ff3892e5deaab7abaec763538ffd011f74dc1801d93d3c5fc541feee2", - "sha256:91b710e3353aea6fc758cdb7136d9bbdcb26b53cefe43e2cba953ac3ee1d3313", - "sha256:9d2ba4ed13af381233e2d810ff3bab84ef9f18430a9b336ab69eaf3cd24299ff", - "sha256:a62ec5e13e227399be73303ff301f2865bf68657d15ea50b038d25fc41097317", - "sha256:ab76e5580b0ed647a8d8d2d2daee170e8e9f8aad225ede314f684e297e3643c2", - "sha256:bf4003aa538af3f4205c5fac56eacaa67a6dd81e454ffd9e9f055fff9f1bc614", - "sha256:bf598d2e37cf8edb1a2f26ed3fb255191f5232badea4003c16301cb94ac5bdd0", - "sha256:c18f70dc27cc5d236f10e7834236aff60aadc71346a5bc1f4f83a4b3abee6386", - "sha256:c5ed816632204a2fc9486d784d8e0d0ae754347aba99c811458d69fcdfd2a2f9", - "sha256:dc058b7833184970d1248135b8b0ab702e6daa833be14035179f2acb78ff5636", - "sha256:ff3797f2f16bf9d17d53257612da84dd0758db33935777149b3334c01ff68865" - ], - "index": "pypi", - "version": "==7.0.0" - }, - "pysocks": { - "hashes": [ - "sha256:08e69f092cc6dbe92a0fdd16eeb9b9ffbc13cadfe5ca4c7bd92ffb078b293299", - "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5", - "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0" - ], - "index": "pypi", - "version": "==1.7.1" - }, - "pyyaml": { - "hashes": [ - "sha256:059b2ee3194d718896c0ad077dd8c043e5e909d9180f387ce42012662a4946d6", - "sha256:1cf708e2ac57f3aabc87405f04b86354f66799c8e62c28c5fc5f88b5521b2dbf", - "sha256:24521fa2890642614558b492b473bee0ac1f8057a7263156b02e8b14c88ce6f5", - "sha256:4fee71aa5bc6ed9d5f116327c04273e25ae31a3020386916905767ec4fc5317e", - "sha256:70024e02197337533eef7b85b068212420f950319cc8c580261963aefc75f811", - "sha256:74782fbd4d4f87ff04159e986886931456a1894c61229be9eaf4de6f6e44b99e", - "sha256:940532b111b1952befd7db542c370887a8611660d2b9becff75d39355303d82d", - "sha256:cb1f2f5e426dc9f07a7681419fe39cee823bb74f723f36f70399123f439e9b20", - "sha256:dbbb2379c19ed6042e8f11f2a2c66d39cceb8aeace421bfc29d085d93eda3689", - "sha256:e3a057b7a64f1222b56e47bcff5e4b94c4f61faac04c7c4ecb1985e18caa3994", - "sha256:e9f45bd5b92c7974e59bcd2dcc8631a6b6cc380a904725fce7bc08872e691615" - ], - "index": "pypi", - "version": "==5.3" - }, - "requests": { - "hashes": [ - "sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee", - "sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6" - ], - "index": "pypi", - "version": "==2.23.0" - }, - "urllib3": { - "hashes": [ - "sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc", - "sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc" - ], - "version": "==1.25.8" - } - }, - "develop": {} -} diff --git a/README.md b/README.md index 37f295f..e8ef0da 100644 --- a/README.md +++ b/README.md @@ -1,114 +1,15 @@ -

Reolink Python Api Client

- -

- GitHub - GitHub tag (latest SemVer) - PyPI -

- ---- - +# (Forked) Reolink Python Api Client A Reolink Camera client written in Python. -Other Supported Languages: - - Go: [reolink-go-api](https://github.com/ReolinkCameraAPI/reolink-go-api) - -### Join us on Discord - - https://discord.gg/8z3fdAmZJP +_NB! for the original API client of this fork, go [here](https://github.com/ReolinkCameraAPI/reolink-python-api)_ ### Purpose -This repository's purpose is to deliver a complete API for the Reolink Camera's, ( TESTED on RLC-411WS ) +This repository's purpose is to deliver a complete API for the Reolink Camera's, (tested on RLC-522) +### Installation -### But Reolink gives an API in their documentation +```bash +python3 -m pip install git+https://github.com/barretobrock/reolink-python-api.git +``` -Not really. They only deliver a really basic API to retrieve Image data and Video data. - -### How? - -You can get the Restful API calls by looking through the HTTP Requests made the camera web console. I use Google Chrome developer mode (ctr + shift + i) -> Network. - -### Get started - -Implement a "Camera" object by passing it an IP address, Username and Password. By instantiating the object, it will try retrieve a login token from the Reolink Camera. This token is necessary to interact with the Camera using other commands. - -See the `examples` directory. - -### Using the library as a Python Module - -Install the package via Pip - - pip install reolink-api==0.0.5 - -## Contributors - ---- - -### Styling and Standards - -This project intends to stick with [PEP8](https://www.python.org/dev/peps/pep-0008/) - -### API Requests Implementation Plan: - -Stream: -- [X] Blocking RTSP stream -- [X] Non-Blocking RTSP stream - -GET: -- [X] Login -- [X] Logout -- [X] Display -> OSD -- [X] Recording -> Encode (Clear and Fluent Stream) -- [X] Recording -> Advance (Scheduling) -- [X] Network -> General -- [X] Network -> Advanced -- [X] Network -> DDNS -- [X] Network -> NTP -- [X] Network -> E-mail -- [X] Network -> FTP -- [X] Network -> Push -- [X] Network -> WIFI -- [X] Alarm -> Motion -- [X] System -> General -- [X] System -> DST -- [X] System -> Information -- [ ] System -> Maintenance -- [X] System -> Performance -- [ ] System -> Reboot -- [X] User -> Online User -- [X] User -> Add User -- [X] User -> Manage User -- [X] Device -> HDD/SD Card -- [ ] Zoom -- [ ] Focus -- [ ] Image (Brightness, Contrast, Saturation, Hue, Sharp, Mirror, Rotate) -- [ ] Advanced Image (Anti-flicker, Exposure, White Balance, DayNight, Backlight, LED light, 3D-NR) -- [X] Image Data -> "Snap" Frame from Video Stream - -SET: -- [X] Display -> OSD -- [X] Recording -> Encode (Clear and Fluent Stream) -- [ ] Recording -> Advance (Scheduling) -- [X] Network -> General -- [X] Network -> Advanced -- [ ] Network -> DDNS -- [ ] Network -> NTP -- [ ] Network -> E-mail -- [ ] Network -> FTP -- [ ] Network -> Push -- [X] Network -> WIFI -- [ ] Alarm -> Motion -- [ ] System -> General -- [ ] System -> DST -- [X] System -> Reboot -- [X] User -> Online User -- [X] User -> Add User -- [X] User -> Manage User -- [X] Device -> HDD/SD Card (Format) -- [x] PTZ -- [x] Zoom -- [x] Focus -- [X] Image (Brightness, Contrast, Saturation, Hue, Sharp, Mirror, Rotate) -- [X] Advanced Image (Anti-flicker, Exposure, White Balance, DayNight, Backlight, LED light, 3D-NR) diff --git a/api/__init__.py b/api/__init__.py deleted file mode 100644 index 491da40..0000000 --- a/api/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from .APIHandler import APIHandler - -__version__ = "0.0.5" -VERSION = __version__ diff --git a/api/APIHandler.py b/reolink_api/APIHandler.py similarity index 92% rename from api/APIHandler.py rename to reolink_api/APIHandler.py index a4a6f07..3b4754d 100644 --- a/api/APIHandler.py +++ b/reolink_api/APIHandler.py @@ -1,26 +1,30 @@ -from .recording import RecordingAPIMixin -from .zoom import ZoomAPIMixin +from reolink_api.resthandle import Request +from .alarm import AlarmAPIMixin from .device import DeviceAPIMixin from .display import DisplayAPIMixin +from .download import DownloadAPIMixin +from .image import ImageAPIMixin +from .motion import MotionAPIMixin from .network import NetworkAPIMixin +from .ptz import PtzAPIMixin +from .recording import RecordingAPIMixin from .system import SystemAPIMixin from .user import UserAPIMixin -from .ptz import PtzAPIMixin -from .alarm import AlarmAPIMixin -from .image import ImageAPIMixin -from resthandle import Request +from .zoom import ZoomAPIMixin -class APIHandler(SystemAPIMixin, - NetworkAPIMixin, - UserAPIMixin, +class APIHandler(AlarmAPIMixin, DeviceAPIMixin, DisplayAPIMixin, - RecordingAPIMixin, - ZoomAPIMixin, + DownloadAPIMixin, + ImageAPIMixin, + MotionAPIMixin, + NetworkAPIMixin, PtzAPIMixin, - AlarmAPIMixin, - ImageAPIMixin): + RecordingAPIMixin, + SystemAPIMixin, + UserAPIMixin, + ZoomAPIMixin): """ The APIHandler class is the backend part of the API, the actual API calls are implemented in Mixins. diff --git a/Camera.py b/reolink_api/Camera.py similarity index 84% rename from Camera.py rename to reolink_api/Camera.py index a60490a..0a166f1 100644 --- a/Camera.py +++ b/reolink_api/Camera.py @@ -1,9 +1,9 @@ -from api import APIHandler +from reolink_api import APIHandler class Camera(APIHandler): - def __init__(self, ip, username="admin", password="", https=False): + def __init__(self, ip: str, username: str = "admin", password: str = "", https: bool = False): """ Initialise the Camera object by passing the ip address. The default details {"username":"admin", "password":""} will be used if nothing passed diff --git a/ConfigHandler.py b/reolink_api/ConfigHandler.py similarity index 99% rename from ConfigHandler.py rename to reolink_api/ConfigHandler.py index 67e8d62..37f255e 100644 --- a/ConfigHandler.py +++ b/reolink_api/ConfigHandler.py @@ -1,5 +1,4 @@ import io - import yaml diff --git a/RtspClient.py b/reolink_api/RtspClient.py similarity index 94% rename from RtspClient.py rename to reolink_api/RtspClient.py index 6cf37c1..655f95f 100644 --- a/RtspClient.py +++ b/reolink_api/RtspClient.py @@ -1,9 +1,7 @@ import os from threading import ThreadError - import cv2 - -from util import threaded +from reolink_api.util import threaded class RtspClient: @@ -91,9 +89,6 @@ class RtspClient: """ Opens OpenCV Video stream and returns the result according to the OpenCV documentation https://docs.opencv.org/3.4/d8/dfe/classcv_1_1VideoCapture.html#a473055e77dd7faa4d26d686226b292c1 - - :param callback: The function to callback the cv::mat frame to if required to be non-blocking. If this is left - as None, then the function returns a generator which is blocking. """ # Reset the capture object diff --git a/reolink_api/__init__.py b/reolink_api/__init__.py new file mode 100644 index 0000000..1eca8c1 --- /dev/null +++ b/reolink_api/__init__.py @@ -0,0 +1,4 @@ +from .APIHandler import APIHandler +from .Camera import Camera + +__version__ = "0.1.0" diff --git a/api/alarm.py b/reolink_api/alarm.py similarity index 100% rename from api/alarm.py rename to reolink_api/alarm.py diff --git a/api/device.py b/reolink_api/device.py similarity index 83% rename from api/device.py rename to reolink_api/device.py index deee890..68f8179 100644 --- a/api/device.py +++ b/reolink_api/device.py @@ -1,5 +1,10 @@ +from typing import List + + class DeviceAPIMixin: """API calls for getting device information.""" + DEFAULT_HDD_ID = [0] + def get_hdd_info(self) -> object: """ Gets all HDD and SD card information from Camera @@ -9,12 +14,14 @@ class DeviceAPIMixin: body = [{"cmd": "GetHddInfo", "action": 0, "param": {}}] return self._execute_command('GetHddInfo', body) - def format_hdd(self, hdd_id: [int] = [0]) -> bool: + def format_hdd(self, hdd_id: List[int] = None) -> bool: """ Format specified HDD/SD cards with their id's :param hdd_id: List of id's specified by the camera with get_hdd_info api. Default is 0 (SD card) :return: bool """ + if hdd_id is None: + hdd_id = self.DEFAULT_HDD_ID body = [{"cmd": "Format", "action": 0, "param": {"HddInfo": {"id": hdd_id}}}] r_data = self._execute_command('Format', body)[0] if r_data["value"]["rspCode"] == 200: diff --git a/api/display.py b/reolink_api/display.py similarity index 100% rename from api/display.py rename to reolink_api/display.py diff --git a/reolink_api/download.py b/reolink_api/download.py new file mode 100644 index 0000000..45494d9 --- /dev/null +++ b/reolink_api/download.py @@ -0,0 +1,15 @@ +class DownloadAPIMixin: + """API calls for downloading video files.""" + def get_file(self, filename: str) -> object: + """ + Download the selected video file + :return: response json + """ + body = [ + { + "cmd": "Download", + "source": filename, + "output": filename + } + ] + return self._execute_command('Download', body) diff --git a/api/image.py b/reolink_api/image.py similarity index 67% rename from api/image.py rename to reolink_api/image.py index 6cdb823..0fbb952 100644 --- a/api/image.py +++ b/reolink_api/image.py @@ -3,22 +3,22 @@ class ImageAPIMixin: """API calls for image settings.""" def set_adv_image_settings(self, - anti_flicker='Outdoor', - exposure='Auto', - gain_min=1, - gain_max=62, - shutter_min=1, - shutter_max=125, - blue_gain=128, - red_gain=128, - white_balance='Auto', - day_night='Auto', - back_light='DynamicRangeControl', - blc=128, - drc=128, - rotation=0, - mirroring=0, - nr3d=1) -> object: + anti_flicker: str = 'Outdoor', + exposure: str = 'Auto', + gain_min: int = 1, + gain_max: int = 62, + shutter_min: int = 1, + shutter_max: int = 125, + blue_gain: int = 128, + red_gain: int = 128, + white_balance: str = 'Auto', + day_night: str = 'Auto', + back_light: str = 'DynamicRangeControl', + blc: int = 128, + drc: int = 128, + rotation: int = 0, + mirroring: int = 0, + nr3d: int = 1) -> object: """ Sets the advanced camera settings. @@ -66,11 +66,11 @@ class ImageAPIMixin: return self._execute_command('SetIsp', body) def set_image_settings(self, - brightness=128, - contrast=62, - hue=1, - saturation=125, - sharpness=128) -> object: + brightness: int = 128, + contrast: int = 62, + hue: int = 1, + saturation: int = 125, + sharpness: int = 128) -> object: """ Sets the camera image settings. diff --git a/reolink_api/motion.py b/reolink_api/motion.py new file mode 100644 index 0000000..1ce8071 --- /dev/null +++ b/reolink_api/motion.py @@ -0,0 +1,41 @@ +from datetime import datetime as dt + + +class MotionAPIMixin: + """API calls for past motion alerts.""" + def get_motion_files(self, start: dt, end: dt = dt.now(), + streamtype: str = 'main') -> object: + """ + Get the timestamps and filenames of motion detection events for the time range provided. + + Args: + start: the starting time range to examine + end: the end time of the time range to examine + streamtype: 'main' or 'sub' - the stream to examine + :return: response json + """ + search_params = { + 'Search': { + 'channel': 0, + 'streamType': streamtype, + 'onlyStatus': 0, + 'StartTime': { + 'year': start.year, + 'mon': start.month, + 'day': start.day, + 'hour': start.hour, + 'min': start.minute, + 'sec': start.second + }, + 'EndTime': { + 'year': end.year, + 'mon': end.month, + 'day': end.day, + 'hour': end.hour, + 'min': end.minute, + 'sec': end.second + } + } + } + body = [{"cmd": "Search", "action": 1, "param": search_params}] + return self._execute_command('Search', body) diff --git a/api/network.py b/reolink_api/network.py similarity index 94% rename from api/network.py rename to reolink_api/network.py index 39af7b8..54bbe2d 100644 --- a/api/network.py +++ b/reolink_api/network.py @@ -1,7 +1,7 @@ class NetworkAPIMixin: """API calls for network settings.""" - def set_net_port(self, http_port=80, https_port=443, media_port=9000, onvif_port=8000, rtmp_port=1935, - rtsp_port=554) -> bool: + def set_net_port(self, http_port: int = 80, https_port: int = 443, media_port: int = 9000, + onvif_port: int = 8000, rtmp_port: int = 1935, rtsp_port: int = 554) -> bool: """ Set network ports If nothing is specified, the default values will be used @@ -25,7 +25,7 @@ class NetworkAPIMixin: print("Successfully Set Network Ports") return True - def set_wifi(self, ssid, password) -> object: + def set_wifi(self, ssid: str, password: str) -> object: body = [{"cmd": "SetWifi", "action": 0, "param": { "Wifi": { "ssid": ssid, diff --git a/api/ptz.py b/reolink_api/ptz.py similarity index 100% rename from api/ptz.py rename to reolink_api/ptz.py diff --git a/api/recording.py b/reolink_api/recording.py similarity index 99% rename from api/recording.py rename to reolink_api/recording.py index 8827249..195cce7 100644 --- a/api/recording.py +++ b/reolink_api/recording.py @@ -4,7 +4,7 @@ import string from urllib import parse from io import BytesIO from PIL import Image -from RtspClient import RtspClient +from reolink_api.RtspClient import RtspClient class RecordingAPIMixin: diff --git a/resthandle.py b/reolink_api/resthandle.py similarity index 94% rename from resthandle.py rename to reolink_api/resthandle.py index d2f98b7..ac3fad9 100644 --- a/resthandle.py +++ b/reolink_api/resthandle.py @@ -1,5 +1,4 @@ import json - import requests @@ -17,7 +16,8 @@ class Request: """ try: headers = {'content-type': 'application/json'} - r = requests.post(url, verify=False, params=params, json=data, headers=headers, proxies=Request.proxies) + r = requests.post(url, verify=False, params=params, json=data, headers=headers, + proxies=Request.proxies) # if params is not None: # r = requests.post(url, params=params, json=data, headers=headers, proxies=proxies) # else: diff --git a/api/system.py b/reolink_api/system.py similarity index 100% rename from api/system.py rename to reolink_api/system.py diff --git a/api/user.py b/reolink_api/user.py similarity index 100% rename from api/user.py rename to reolink_api/user.py diff --git a/util.py b/reolink_api/util.py similarity index 100% rename from util.py rename to reolink_api/util.py diff --git a/api/zoom.py b/reolink_api/zoom.py similarity index 100% rename from api/zoom.py rename to reolink_api/zoom.py diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 30b468d..0000000 --- a/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -requests -opencv-python -numpy -socks \ No newline at end of file diff --git a/setup.py b/setup.py index 98eba70..da818d1 100644 --- a/setup.py +++ b/setup.py @@ -1,32 +1,9 @@ #!/usr/bin/python3 - import os import re import codecs from setuptools import setup -# Package meta-data. -NAME = 'reolink-api' -DESCRIPTION = 'Reolink Camera API written in Python 3.6' -URL = 'https://github.com/Benehiko/ReolinkCameraAPI' -AUTHOR_EMAIL = '' -AUTHOR = 'Benehiko' -LICENSE = 'GPL-3.0' -INSTALL_REQUIRES = [ - 'pillow', - 'pyyaml', - 'requests>=2.18.4', - 'numpy', - 'opencv-python', - 'pysocks' -] - - -here = os.path.abspath(os.path.dirname(__file__)) -# read the contents of your README file -with open(os.path.join(here, 'README.md'), encoding='utf-8') as f: - long_description = f.read() - def read(*parts): with codecs.open(os.path.join(here, *parts), 'r') as fp: @@ -41,32 +18,39 @@ def find_version(*file_paths): raise RuntimeError("Unable to find version string.") -setup(name=NAME, - python_requires='>=3.6.0', - version=find_version('api', '__init__.py'), - description=DESCRIPTION, - long_description=long_description, - long_description_content_type='text/markdown', - author=AUTHOR, - author_email=AUTHOR_EMAIL, - url=URL, - license=LICENSE, - install_requires=INSTALL_REQUIRES, - py_modules=[ - 'Camera', - 'ConfigHandler', - 'RtspClient', - 'resthandle', - 'api.APIHandler', - 'api.device', - 'api.display', - 'api.network', - 'api.ptz', - 'api.recording', - 'api.system', - 'api.user', - 'api.zoom', - 'api.alarm', - 'api.image' - ] - ) +here = os.path.abspath(os.path.dirname(__file__)) +# read the contents of your README file +with open(os.path.join(here, 'README.md'), encoding='utf-8') as f: + long_description = f.read() + + +# Package meta-data. +NAME = 'reolink_api' +DESCRIPTION = 'Reolink Camera API written in Python 3.6' +URL = 'https://github.com/Benehiko/ReolinkCameraAPI' +AUTHOR_EMAIL = '' +AUTHOR = 'Benehiko' +LICENSE = 'GPL-3.0' +INSTALL_REQUIRES = [ + 'numpy==1.19.4', + 'opencv-python==4.4.0.46', + 'Pillow==8.0.1', + 'PySocks==1.7.1', + 'PyYaml==5.3.1', + 'requests>=2.18.4', +] + + +setup( + name=NAME, + python_requires='>=3.6.0', + version=find_version('reolink_api', '__init__.py'), + description=DESCRIPTION, + long_description=long_description, + long_description_content_type='text/markdown', + author=AUTHOR, + author_email=AUTHOR_EMAIL, + url=URL, + license=LICENSE, + install_requires=INSTALL_REQUIRES +) diff --git a/test.py b/test.py deleted file mode 100644 index 796f5a2..0000000 --- a/test.py +++ /dev/null @@ -1,5 +0,0 @@ -from Camera import Camera - -c = Camera("192.168.1.112", "admin", "jUa2kUzi") -# print("Getting information", c.get_information()) -c.open_video_stream()