Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
853ccbce79 | ||
|
|
8153fab887 | ||
|
|
216541288e | ||
|
|
a855cceb05 | ||
|
|
d9991d5acd | ||
|
|
2ee2ae7d4e | ||
|
|
04c2be9087 | ||
|
|
34fc9bc527 | ||
|
|
1a24e1896f | ||
|
|
1d67764dc8 | ||
|
|
8f250d204f | ||
|
|
643ae8c387 | ||
|
|
f9615a2d90 | ||
|
|
f7a3b1d0ef | ||
|
|
94aed43d2e | ||
|
|
90f30deea8 | ||
|
|
1bbc71ef17 | ||
|
|
c84a0deb5f | ||
|
|
ece65a9158 | ||
|
|
5a8af75a5b | ||
|
|
84f987d29c | ||
|
|
ed25745deb | ||
|
|
a1fd05735e | ||
|
|
5a9f8f6dfc | ||
|
|
2639055372 | ||
|
|
c53b2bd777 | ||
|
|
db29bae140 | ||
|
|
52f1fde47a | ||
|
|
e705fbd403 | ||
|
|
2d437b4462 | ||
|
|
ea2b22dbf0 |
@@ -1,5 +1,5 @@
|
||||
# BlinkMonitorProtocol
|
||||
Unofficial documentation for the Client API of the Blink Wire-Free HD Home Monitoring and Alert System.
|
||||
Unofficial documentation for the Client API of the Blink Wire-Free HD Home Monitoring & Alert System.
|
||||
|
||||
Copied from https://github.com/MattTW/BlinkMonitorProtocol
|
||||
|
||||
@@ -7,9 +7,6 @@ I am not affiliated with the company in any way - this documentation is strictly
|
||||
|
||||
The Client API is a straightforward REST API using JSON and HTTPS.
|
||||
|
||||
## This Document
|
||||
The purpose here is to describe what is going on behind the scenes, and what commands we know are available to communicate with Blink servers. This is NOT a description of the blinkpy module, but a description of the commands blinkpy relies on to effectively communicate.
|
||||
|
||||
## Login
|
||||
|
||||
Client login to the Blink Servers.
|
||||
@@ -19,20 +16,25 @@ Client login to the Blink Servers.
|
||||
> "password" : "*your blink password*",
|
||||
> "client_specifier" : "iPhone 9.2 | 2.2 | 222",
|
||||
> "email" : "*your blink login/email*"
|
||||
>}' --compressed https://prod.immedia-semi.com/login
|
||||
>}' --compressed https://rest.prod.immedia-semi.com/login
|
||||
|
||||
**Response:**
|
||||
>{"authtoken":{"authtoken":"*an auth token*","message":"auth"}}
|
||||
>{"authtoken":{"authtoken":"*an auth token*","message":"auth"},"networks":{"*network id*":{"name":"*name*","onboarded":true}},"region":{"*regioncode for endpoint*":"*region name"}}
|
||||
|
||||
**Notes:**
|
||||
The authtoken value is passed in a header in future calls.
|
||||
The region code for endpoint is required to form the URL of the REST endpoint for future calls.
|
||||
Depending on the region you are registered you will need to change the REST endpoints below:
|
||||
- from `https://rest.prod.immedia-semi.com`
|
||||
- to `https://rest.prde.immedia-semi.com` if e.g. your device is registered in Germany
|
||||
Please note that at this moment it seems that all regions are not implemented equally: not all endpoints are available in all regions
|
||||
|
||||
##Networks
|
||||
## Networks
|
||||
|
||||
Obtain information about the Blink networks defined for the logged in user.
|
||||
|
||||
**Request:**
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/networks
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/networks
|
||||
|
||||
**Response:**
|
||||
JSON response containing information including Network ID and Account ID.
|
||||
@@ -46,7 +48,7 @@ Network ID is needed to issue arm/disarm calls
|
||||
Obtain information about the Blink Sync Modules on the given network.
|
||||
|
||||
**Request:**
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/network/*network_id_from_networks_call*/syncmodules
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/network/*network_id_from_networks_call*/syncmodules
|
||||
|
||||
**Response:**
|
||||
JSON response containing information about the known state of the Sync module, most notably if it is online
|
||||
@@ -56,11 +58,11 @@ Probably not strictly needed but checking result can verify that the sync module
|
||||
|
||||
|
||||
## Arm
|
||||
|
||||
|
||||
Arm the given network (start recording/reporting motion events)
|
||||
|
||||
**Request:**
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --data-binary --compressed https://prod.immedia-semi.com/network/*network_id_from_networks_call*/arm
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --data-binary --compressed https://rest.prod.immedia-semi.com/network/*network_id_from_networks_call*/arm
|
||||
|
||||
**Response:**
|
||||
JSON response containing information about the arm command request, including the command/request ID
|
||||
@@ -73,7 +75,7 @@ When this call returns, it does not mean the arm request is complete, the clien
|
||||
Disarm the given network (stop recording/reporting motion events)
|
||||
|
||||
**Request:**
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --data-binary --compressed https://prod.immedia-semi.com/network/*network_id_from_networks_call*/disarm
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --data-binary --compressed https://rest.prod.immedia-semi.com/network/*network_id_from_networks_call*/disarm
|
||||
|
||||
**Response:**
|
||||
JSON response containing information about the disarm command request, including the command/request ID
|
||||
@@ -87,7 +89,7 @@ When this call returns, it does not mean the disarm request is complete, the cl
|
||||
Get status info on the given command
|
||||
|
||||
**Request:**
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/network/*network_id*/command/*command_id*
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/network/*network_id*/command/*command_id*
|
||||
|
||||
**Response:**
|
||||
JSON response containing state information of the given command, most notably whether it has completed and was successful.
|
||||
@@ -103,7 +105,7 @@ lv_relay, arm, disarm, thumbnail, clip
|
||||
Return information displayed on the home screen of the mobile client
|
||||
|
||||
**Request:**
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/homescreen
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/homescreen
|
||||
|
||||
**Response:**
|
||||
JSON response containing information that the mobile client displays on the home page, including: status, armed state, links to thumbnails for each camera, etc.
|
||||
@@ -111,12 +113,12 @@ JSON response containing information that the mobile client displays on the home
|
||||
**Notes:**
|
||||
Not necessary to as part of issuing arm/disarm commands, but contains good summary info.
|
||||
|
||||
##Events, thumbnails & video captures
|
||||
## Events, thumbnails & video captures
|
||||
|
||||
**Request**
|
||||
Get events for a given network (sync module) -- Need network ID from home
|
||||
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/events/network/*network__id*
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/events/network/*network__id*
|
||||
|
||||
**Response**
|
||||
A json list of evets incluing URL's. Replace the "mp4" with "jpg" extension to get the thumbnail of each clip
|
||||
@@ -144,7 +146,7 @@ Note that you replace the 'mp4' with a 'jpg' to get the thumbnail
|
||||
**Request**
|
||||
Captures a new thumbnail for a camera
|
||||
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --data-binary --compressed https://prod.immedia-semi.com/network/*network_id*/camera/*camera_id*/thumbnail
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --data-binary --compressed https://rest.prod.immedia-semi.com/network/*network_id*/camera/*camera_id*/thumbnail
|
||||
|
||||
**Response**
|
||||
Command information.
|
||||
@@ -152,17 +154,17 @@ Command information.
|
||||
**Request**
|
||||
Captures a new video for a camera
|
||||
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --data-binary --compressed https://prod.immedia-semi.com/network/*network_id*/camera/*camera_id*/clip
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --data-binary --compressed https://rest.prod.immedia-semi.com/network/*network_id*/camera/*camera_id*/clip
|
||||
|
||||
**Response**
|
||||
Command information.
|
||||
|
||||
##Video Information
|
||||
## Video Information
|
||||
|
||||
**Request**
|
||||
Get the total number of videos in the system
|
||||
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/api/v2/videos/count
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/api/v2/videos/count
|
||||
|
||||
**Response**
|
||||
JSON response containing the total video count.
|
||||
@@ -170,7 +172,7 @@ JSON response containing the total video count.
|
||||
**Request**
|
||||
Gets a paginated set of video information
|
||||
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/api/v2/videos/page/0
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/api/v2/videos/page/0
|
||||
|
||||
**Response**
|
||||
JSON response containing a set of video information, including: camera name, creation time, thumbnail URI, size, length
|
||||
@@ -178,7 +180,7 @@ JSON response containing a set of video information, including: camera name, cre
|
||||
**Request**
|
||||
Gets information for a specific video by ID
|
||||
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/api/v2/video/*video_id*
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/api/v2/video/*video_id*
|
||||
|
||||
**Response**
|
||||
JSON response containing video information
|
||||
@@ -186,7 +188,7 @@ JSON response containing video information
|
||||
**Request**
|
||||
Gets a list of unwatched videos
|
||||
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/api/v2/videos/unwatched
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/api/v2/videos/unwatched
|
||||
|
||||
**Response**
|
||||
JSON response containing unwatched video information
|
||||
@@ -194,7 +196,7 @@ JSON response containing unwatched video information
|
||||
**Request**
|
||||
Deletes a video
|
||||
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --data-binary --compressed https://prod.immedia-semi.com/api/v2/video/*video_id*/delete
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --data-binary --compressed https://rest.prod.immedia-semi.com/api/v2/video/*video_id*/delete
|
||||
|
||||
**Response**
|
||||
Unknown - not tested
|
||||
@@ -202,7 +204,7 @@ Unknown - not tested
|
||||
**Request**
|
||||
Deletes all videos
|
||||
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --data-binary --compressed https://prod.immedia-semi.com/api/v2/videos/deleteall
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --data-binary --compressed https://rest.prod.immedia-semi.com/api/v2/videos/deleteall
|
||||
|
||||
**Response**
|
||||
Unknown - not tested
|
||||
@@ -212,7 +214,7 @@ Unknown - not tested
|
||||
**Request**
|
||||
Gets a list of cameras
|
||||
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/network/*network_id*/cameras
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/network/*network_id*/cameras
|
||||
|
||||
**Response**
|
||||
JSON response containing camera information
|
||||
@@ -220,7 +222,7 @@ JSON response containing camera information
|
||||
**Request**
|
||||
Gets information for one camera
|
||||
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/network/*network_id*/camera/*camera_id*
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/network/*network_id*/camera/*camera_id*
|
||||
|
||||
**Response**
|
||||
JSON response containing camera information
|
||||
@@ -228,7 +230,7 @@ JSON response containing camera information
|
||||
**Request**
|
||||
Gets camera sensor information
|
||||
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/network/*network_id*/camera/*camera_id*/signals
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/network/*network_id*/camera/*camera_id*/signals
|
||||
|
||||
**Response**
|
||||
JSON response containing camera sensor information, such as wifi strength, temperature, and battery level
|
||||
@@ -236,7 +238,7 @@ JSON response containing camera sensor information, such as wifi strength, tempe
|
||||
**Request**
|
||||
Enables motion detection for one camera
|
||||
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: $auth_token" --data-binary --compressed https://prod.immedia-semi.com/network/*network_id*/camera/*camera_id*/enable
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: $auth_token" --data-binary --compressed https://rest.prod.immedia-semi.com/network/*network_id*/camera/*camera_id*/enable
|
||||
|
||||
**Response**
|
||||
JSON response containing camera information
|
||||
@@ -244,7 +246,7 @@ JSON response containing camera information
|
||||
**Request**
|
||||
Disables motion detection for one camera
|
||||
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: $auth_token" --data-binary --compressed https://prod.immedia-semi.com/network/*network_id*/camera/*camera_id*/disable
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: $auth_token" --data-binary --compressed https://rest.prod.immedia-semi.com/network/*network_id*/camera/*camera_id*/disable
|
||||
|
||||
**Response**
|
||||
JSON response containing camera information
|
||||
@@ -257,7 +259,7 @@ JSON response containing camera information
|
||||
**Request**
|
||||
Gets information about devices that have connected to the blink service
|
||||
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/account/clients
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/account/clients
|
||||
|
||||
**Response**
|
||||
JSON response containing client information, including: type, name, connection time, user ID
|
||||
@@ -265,7 +267,7 @@ JSON response containing client information, including: type, name, connection t
|
||||
**Request**
|
||||
Gets information about supported regions
|
||||
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/regions
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/regions
|
||||
|
||||
**Response**
|
||||
JSON response containing region information
|
||||
@@ -273,7 +275,7 @@ JSON response containing region information
|
||||
**Request**
|
||||
Gets information about system health
|
||||
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/health
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/health
|
||||
|
||||
**Response**
|
||||
"all ports tested are open"
|
||||
@@ -281,7 +283,7 @@ Gets information about system health
|
||||
**Request**
|
||||
Gets information about programs
|
||||
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://prod.immedia-semi.com/api/v1/networks/*network_id*/programs
|
||||
>curl -H "Host: prod.immedia-semi.com" -H "TOKEN_AUTH: *authtoken from login*" --compressed https://rest.prod.immedia-semi.com/api/v1/networks/*network_id*/programs
|
||||
|
||||
**Response**
|
||||
Unknown.
|
||||
|
||||
+10
@@ -3,6 +3,16 @@ Changelog
|
||||
|
||||
A list of changes between each release
|
||||
|
||||
0.11.1 (2019-01-02)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
- Fixed incorrect backup login url
|
||||
- Added calibrated temperature property for cameras
|
||||
|
||||
|
||||
0.11.0 (2018-11-23)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
- Added support for multiple sync modules
|
||||
|
||||
0.10.3 (2018-11-18)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
- Use networks endpoint rather than homecreen to retrieve arm/disarm status (`@md-reddevil <https://github.com/fronzbot/blinkpy/pull/119>`__)
|
||||
|
||||
+41
-35
@@ -4,41 +4,55 @@ Everyone is welcome to contribute to blinkpy! The process to get started is desc
|
||||
|
||||
## Fork the Repository
|
||||
|
||||
You can do this right in gituhb: just click the 'fork' button at the top right.
|
||||
You can do this right in github: just click the 'fork' button at the top right.
|
||||
|
||||
## Setup Local Repository
|
||||
## Start Developing
|
||||
|
||||
```shell
|
||||
$ git clone https://github.com/<YOUR_GIT_USERNAME>/blinkpy.git
|
||||
$ cd blinkpy
|
||||
$ git remote add upstream https://github.com/fronzbot/blinkpy.git
|
||||
```
|
||||
1. Setup Local Repository
|
||||
```shell
|
||||
$ git clone https://github.com/<YOUR_GIT_USERNAME>/blinkpy.git
|
||||
$ cd blinkpy
|
||||
$ git remote add upstream https://github.com/fronzbot/blinkpy.git
|
||||
```
|
||||
|
||||
## Create a Local Branch
|
||||
2. Create a Local Branch
|
||||
|
||||
First, you will want to create a new branch to hold your changes:
|
||||
``git checkout -b <your-branch-name>``
|
||||
|
||||
First, you will want to create a new branch to hold your changes:
|
||||
``git checkout -b <your-branch-name>``
|
||||
Next, you need to make sure you pull from the 'dev' branch:
|
||||
``git pull origin dev``
|
||||
|
||||
## Make changes
|
||||
3. Make changes
|
||||
|
||||
Now you can make changes to your code. It is worthwhile to test your code as you progress (see the **Testing** section)
|
||||
|
||||
Now you can make changes to your code. It is worthwhile to test your code as you progress (see the **Testing** section)
|
||||
4. Commit Your Changes
|
||||
|
||||
To commit changes to your branch, simply add the files you want and the commit them to the branch. After that, you can push to your fork on GitHub:
|
||||
```shell
|
||||
$ git add .
|
||||
$ git commit -m "Put your commit text here. Please be concise, but descriptive."
|
||||
$ git push origin HEAD
|
||||
```
|
||||
|
||||
5. Submit your pull request on GitHub
|
||||
|
||||
- On GitHub, navigate to the [blinkpy](https://github.com/fronzbot/blinkpy) repository.
|
||||
- In the "Branch" menu, choose the branch that contains your commits (from your fork).
|
||||
- To the right of the Branch menu, click New pull request.
|
||||
- The base branch dropdown menu should read `dev`. Use the compare branch drop-down menu to choose the branch you made your changes in.
|
||||
- Type a title and complete the provided description for your pull request.
|
||||
- Click Create pull request.
|
||||
- More detailed instructions can be found here: [Creating a Pull Request](https://help.github.com/articles/creating-a-pull-request/)
|
||||
|
||||
6. Prior to merge approval
|
||||
|
||||
Finally, the `blinkpy` repository uses continuous integration tools to run tests prior to merging. If there are any problems, you will see a red 'X' next to your pull request. To see what's wrong, you can find your pull request [here](https://travis- ci.org/fronzbot/blinkpy/pull_requests) and click on the failing test to see the logs. Those logs will indicate, as best as they can, what is causing that test to fail.
|
||||
|
||||
## Commit Your Changes
|
||||
|
||||
To commit changes to your branch, simply add the files you want and the commit them to the branch. After that, you can push to your fork on GitHub:
|
||||
|
||||
```shell
|
||||
$ git add .
|
||||
$ git commit -m "Put your commit text here. Please be concise, but descriptive."
|
||||
$ git push origin HEAD
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
It is important to test the code to make sure your changes don't break anything major and that they pass PEP8 style conventions.
|
||||
FIrst, you need to locally install ``tox``
|
||||
First, you need to locally install ``tox``
|
||||
|
||||
```shell
|
||||
$ pip3 install tox
|
||||
@@ -52,11 +66,11 @@ $ tox
|
||||
|
||||
### Tips
|
||||
|
||||
If you only want to see if you can pass the local tests, you can run ``tox -e py34``. If you just want to check for style violations, you can run ``tox -e lint``. Regardless, when you submit a pull request, your code MUST pass both the unit tests, and the linters.
|
||||
If you only want to see if you can pass the local tests, you can run `tox -e py35` (or whatever python version you have installed. Only `py35`, `py36`, and `py37` will be accepted). If you just want to check for style violations, you can run `tox -e lint`. Regardless, when you submit a pull request, your code MUST pass both the unit tests, and the linters.
|
||||
|
||||
If you need to change anything in ``requirements.txt`` for any reason, you'll want to regenerate the virtual envrionments used by ``tox`` by running with the ``-r`` flag: ``tox -r``
|
||||
If you need to change anything in `requirements.txt` for any reason, you'll want to regenerate the virtual envrionments used by `tox` by running with the `-r` flag: `tox -r`
|
||||
|
||||
Please do not locally disable any linter warnings within the ``blinkpy.py`` module itself (it's ok to do this in any of the ``test_*.py`` files)
|
||||
If you want to run a single test (perhaps you only changed a small thing in one file) you can run `tox -e py35 -- tests/<testname>.py -x`. This will run the test `<testname>.py` and stop testing upon the first failure, making it easier to figure out why a particular test might be failing. The test structure mimics the library structure, so if you changed something in `sync_module.py`, the associated test file would be in `test_sync_module.py` (ie. the filename is prepended with `test_`.
|
||||
|
||||
# Catching Up With Reality
|
||||
|
||||
@@ -73,11 +87,3 @@ If rebase detects conflicts, repeat the following process until all changes have
|
||||
2. Add the modified file: ``git add <file>`` or ``git add .``.
|
||||
3. Continue rebase: ``git rebase --continue``.
|
||||
4. Repeat until all conflicts resolved.
|
||||
|
||||
# Creating a Pull Request
|
||||
|
||||
Please follow these steps to create a pull request against the ``dev`` branch: [Creating a Pull Request](https://help.github.com/articles/creating-a-pull-request/)
|
||||
|
||||
# Monitor Build Status
|
||||
|
||||
Once you create your PR, you can monitor the status of your build [here](https://travis-ci.org/fronzbot/blinkpy), Your code will be tested to ensure it passes and won't cause any problems after merging.
|
||||
+13
-10
@@ -1,7 +1,6 @@
|
||||
blinkpy |Build Status| |Coverage Status| |Docs| |PyPi Version| |Python Version|
|
||||
================================================================================
|
||||
A Python library for the Blink Camera system
|
||||
Only compatible with Python 3+
|
||||
|
||||
Disclaimer:
|
||||
~~~~~~~~~~~~~~~
|
||||
@@ -32,12 +31,16 @@ To install the current development version, perform the following steps. Note t
|
||||
$ pip3 install --upgrade dist/*.whl
|
||||
|
||||
|
||||
If you'd like to contribute to this library, please read the `contributing instructions <https://github.com/fronzbot/blinkpy/blob/dev/CONTRIBUTING.md>`__.
|
||||
|
||||
For more information on how to use this library, please `read the docs <https://blinkpy.readthedocs.io/en/latest/>`__.
|
||||
|
||||
Purpose
|
||||
===========
|
||||
This library was built with the intention of allowing easy communication with Blink camera systems, specifically so I can add a module into homeassistant https://home-assistant.io
|
||||
This library was built with the intention of allowing easy communication with Blink camera systems, specifically to support the `Blink component <https://home-assistant.io/components/blink>`__ in `homeassistant <https://home-assistant.io/>`__.
|
||||
|
||||
Usage
|
||||
=========
|
||||
Quick Start
|
||||
=============
|
||||
The simplest way to use this package from a terminal is to call ``Blink.start()`` which will prompt for your Blink username and password and then log you in. Alternatively, you can instantiate the Blink class with a username and password, and call ``Blink.start()`` to login and setup without prompt, as shown below. In addition, http requests are throttled internally via use of the ``Blink.refresh_rate`` variable, which can be set at initialization and defaults to 30 seconds.
|
||||
|
||||
.. code:: python
|
||||
@@ -48,7 +51,7 @@ The simplest way to use this package from a terminal is to call ``Blink.start()`
|
||||
|
||||
If you would like to log in without setting up the cameras or system, you can simply call the ``Blink.login()`` function which will prompt for a username and password and then authenticate with the server. This is useful if you want to avoid use of the ``start()`` function which simply acts as a wrapper for more targeted API methods.
|
||||
|
||||
Cameras are instantiated as individual ``BlinkCamera`` classes within a ``BlinkSyncModule`` instance. Note: currently the API only supports one sync module, but multiple sync modules are planned to be supported in the future.
|
||||
Cameras are instantiated as individual ``BlinkCamera`` classes within a ``BlinkSyncModule`` instance. All of your sync modules are stored within the ``Blink.sync`` dictionary and can be accessed using the name of the sync module as the key (this is the name of your sync module in the Blink App).
|
||||
|
||||
The below code will display cameras and their available attributes:
|
||||
|
||||
@@ -59,15 +62,15 @@ The below code will display cameras and their available attributes:
|
||||
blink = blinkpy.Blink(username='YOUR USER NAME', password='YOUR PASSWORD')
|
||||
blink.start()
|
||||
|
||||
for name, camera in blink.sync.cameras.items():
|
||||
print(name) # Name of the camera
|
||||
print(camera.attributes) # Print available attributes of camera
|
||||
for name, camera in blink.cameras.items():
|
||||
print(name) # Name of the camera
|
||||
print(camera.attributes) # Print available attributes of camera
|
||||
|
||||
The most recent images and videos can be accessed as a bytes-object via internal variables. These can be updated with calls to ``Blink.refresh()`` but will only make a request if motion has been detected or other changes have been found. This can be overridden with the ``force_cache`` flag, but this should be used for debugging only since it overrides the internal request throttling.
|
||||
|
||||
.. code:: python
|
||||
|
||||
camera = blink.sync.camera['SOME CAMERA NAME']
|
||||
camera = blink.cameras['SOME CAMERA NAME']
|
||||
blink.refresh(force_cache=True) # force a cache update USE WITH CAUTION
|
||||
camera.image_from_cache.raw # bytes-like image object (jpg)
|
||||
camera.video_from_cache.raw # bytes-like video object (mp4)
|
||||
@@ -76,7 +79,7 @@ The ``blinkpy`` api also allows for saving images and videos to a file and snapp
|
||||
|
||||
.. code:: python
|
||||
|
||||
camera = blink.sync.camera['SOME CAMERA NAME']
|
||||
camera = blink.cameras['SOME CAMERA NAME']
|
||||
camera.snap_picture() # Take a new picture with the camera
|
||||
blink.refresh() # Get new information from server
|
||||
camera.image_to_file('/local/path/for/image.jpg')
|
||||
|
||||
+32
-17
@@ -14,14 +14,15 @@ I am in no way affiliated with Blink, nor Immedia Inc.
|
||||
import time
|
||||
import getpass
|
||||
import logging
|
||||
from requests.structures import CaseInsensitiveDict
|
||||
import blinkpy.helpers.errors as ERROR
|
||||
from blinkpy import api
|
||||
from blinkpy.sync_module import BlinkSyncModule
|
||||
from blinkpy.helpers.util import (
|
||||
create_session, BlinkURLHandler,
|
||||
create_session, merge_dicts, BlinkURLHandler,
|
||||
BlinkAuthenticationException)
|
||||
from blinkpy.helpers.constants import (
|
||||
BLINK_URL, LOGIN_URL, LOGIN_BACKUP_URL, PROJECT_URL)
|
||||
BLINK_URL, LOGIN_URL, LOGIN_BACKUP_URL)
|
||||
|
||||
REFRESH_RATE = 30
|
||||
|
||||
@@ -46,16 +47,17 @@ class Blink():
|
||||
self._token = None
|
||||
self._auth_header = None
|
||||
self._host = None
|
||||
self.network_id = None
|
||||
self.account_id = None
|
||||
self.network_ids = []
|
||||
self.urls = None
|
||||
self.sync = None
|
||||
self.sync = CaseInsensitiveDict({})
|
||||
self.region = None
|
||||
self.region_id = None
|
||||
self.last_refresh = None
|
||||
self.refresh_rate = refresh_rate
|
||||
self.session = None
|
||||
self.networks = []
|
||||
self.cameras = CaseInsensitiveDict({})
|
||||
self._login_url = LOGIN_URL
|
||||
|
||||
@property
|
||||
@@ -75,9 +77,12 @@ class Blink():
|
||||
else:
|
||||
self.get_auth_token()
|
||||
|
||||
self.get_ids()
|
||||
self.sync = BlinkSyncModule(self)
|
||||
self.sync.start()
|
||||
networks = self.get_ids()
|
||||
for network_name, network_id in networks.items():
|
||||
sync_module = BlinkSyncModule(self, network_name, network_id)
|
||||
sync_module.start()
|
||||
self.sync[network_name] = sync_module
|
||||
self.cameras = self.merge_cameras()
|
||||
|
||||
def login(self):
|
||||
"""Prompt user for username and password."""
|
||||
@@ -136,18 +141,20 @@ class Blink():
|
||||
# Look for only onboarded network, flag warning if multiple
|
||||
# since it's unexpected
|
||||
all_networks = []
|
||||
network_dict = {}
|
||||
for network, status in self.networks.items():
|
||||
if status['onboarded']:
|
||||
all_networks.append(network)
|
||||
self.network_id = all_networks.pop(0)
|
||||
all_networks.append('{}'.format(network))
|
||||
network_dict[status['name']] = network
|
||||
|
||||
# For the first onboarded network we find, grab the account id
|
||||
for resp in response['networks']:
|
||||
if str(resp['id']) == self.network_id:
|
||||
if str(resp['id']) in all_networks:
|
||||
self.account_id = resp['account_id']
|
||||
if all_networks:
|
||||
_LOGGER.warning(("More than one onboarded network. "
|
||||
"Platform may not work as intended. "
|
||||
"If you experience problems, please "
|
||||
"open an issue on %s"), PROJECT_URL)
|
||||
break
|
||||
|
||||
self.network_ids = all_networks
|
||||
return network_dict
|
||||
|
||||
def refresh(self, force_cache=False):
|
||||
"""
|
||||
@@ -156,8 +163,9 @@ class Blink():
|
||||
:param force_cache: Force an update of the camera cache
|
||||
"""
|
||||
if self.check_if_ok_to_update() or force_cache:
|
||||
_LOGGER.debug("Attempting refresh of cameras.")
|
||||
self.sync.refresh(force_cache=force_cache)
|
||||
for sync_name, sync_module in self.sync.items():
|
||||
_LOGGER.debug("Attempting refresh of sync %s", sync_name)
|
||||
sync_module.refresh(force_cache=force_cache)
|
||||
|
||||
def check_if_ok_to_update(self):
|
||||
"""Check if it is ok to perform an http request."""
|
||||
@@ -169,3 +177,10 @@ class Blink():
|
||||
self.last_refresh = current_time
|
||||
return True
|
||||
return False
|
||||
|
||||
def merge_cameras(self):
|
||||
"""Merge all sync camera dicts into one."""
|
||||
combined = CaseInsensitiveDict({})
|
||||
for sync in self.sync:
|
||||
combined = merge_dicts(combined, self.sync[sync].cameras)
|
||||
return combined
|
||||
|
||||
@@ -24,6 +24,7 @@ class BlinkCamera():
|
||||
self.battery_voltage = None
|
||||
self.clip = None
|
||||
self.temperature = None
|
||||
self.temperature_calibrated = None
|
||||
self.battery_state = None
|
||||
self.motion_detected = None
|
||||
self.wifi_strength = None
|
||||
@@ -40,6 +41,7 @@ class BlinkCamera():
|
||||
'serial': self.serial,
|
||||
'temperature': self.temperature,
|
||||
'temperature_c': self.temperature_c,
|
||||
'temperature_calibrated': self.temperature_calibrated,
|
||||
'battery': self.battery,
|
||||
'thumbnail': self.thumbnail,
|
||||
'video': self.clip,
|
||||
@@ -47,6 +49,7 @@ class BlinkCamera():
|
||||
'motion_detected': self.motion_detected,
|
||||
'wifi_strength': self.wifi_strength,
|
||||
'network_id': self.sync.network_id,
|
||||
'sync_module': self.sync.name,
|
||||
'last_record': self.last_record
|
||||
}
|
||||
return attributes
|
||||
@@ -103,6 +106,15 @@ class BlinkCamera():
|
||||
self.temperature = config['temperature']
|
||||
self.wifi_strength = config['wifi_strength']
|
||||
|
||||
# Retrieve calibrated temperature from special endpoint
|
||||
resp = api.request_camera_sensors(self.sync.blink,
|
||||
self.network_id,
|
||||
self.camera_id)
|
||||
try:
|
||||
self.temperature_calibrated = resp['temp']
|
||||
except KeyError:
|
||||
_LOGGER.error("Could not retrieve calibrated temperature.")
|
||||
|
||||
# Check if thumbnail exists in config, if not try to
|
||||
# get it from the homescreen info in teh sync module
|
||||
# otherwise set it to None and log an error
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
import os
|
||||
|
||||
MAJOR_VERSION = 0
|
||||
MINOR_VERSION = 10
|
||||
PATCH_VERSION = 3
|
||||
MINOR_VERSION = 11
|
||||
PATCH_VERSION = 1
|
||||
|
||||
__version__ = '{}.{}.{}'.format(MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION)
|
||||
|
||||
@@ -45,10 +45,10 @@ PYPI_URL = 'https://pypi.python.org/pypi/{}'.format(PROJECT_PACKAGE_NAME)
|
||||
URLS
|
||||
'''
|
||||
BLINK_URL = 'immedia-semi.com'
|
||||
LOGIN_URL = 'https://prod.' + BLINK_URL + '/login'
|
||||
LOGIN_BACKUP_URL = 'https://rest.piri/' + BLINK_URL + '/login'
|
||||
BASE_URL = 'https://prod.' + BLINK_URL
|
||||
DEFAULT_URL = 'prod.' + BLINK_URL
|
||||
DEFAULT_URL = "{}.{}".format('prod', BLINK_URL)
|
||||
BASE_URL = "https://{}".format(DEFAULT_URL)
|
||||
LOGIN_URL = "{}/login".format(BASE_URL)
|
||||
LOGIN_BACKUP_URL = "https://{}.{}/login".format('rest.piri', BLINK_URL)
|
||||
|
||||
'''
|
||||
Dictionaries
|
||||
|
||||
@@ -9,6 +9,15 @@ import blinkpy.helpers.errors as ERROR
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def merge_dicts(dict_a, dict_b):
|
||||
"""Merge two dictionaries into one."""
|
||||
duplicates = [val for val in dict_a if val in dict_b]
|
||||
if duplicates:
|
||||
_LOGGER.warning(("Duplicates found during merge: %s. "
|
||||
"Renaming is recommended."), duplicates)
|
||||
return {**dict_a, **dict_b}
|
||||
|
||||
|
||||
def create_session():
|
||||
"""Create a session for blink communication."""
|
||||
sess = Session()
|
||||
|
||||
@@ -13,7 +13,7 @@ _LOGGER = logging.getLogger(__name__)
|
||||
class BlinkSyncModule():
|
||||
"""Class to initialize sync module."""
|
||||
|
||||
def __init__(self, blink):
|
||||
def __init__(self, blink, network_name, network_id):
|
||||
"""
|
||||
Initialize Blink sync module.
|
||||
|
||||
@@ -21,10 +21,10 @@ class BlinkSyncModule():
|
||||
"""
|
||||
self.blink = blink
|
||||
self._auth_header = blink.auth_header
|
||||
self.network_id = blink.network_id
|
||||
self.network_id = network_id
|
||||
self.region = blink.region
|
||||
self.region_id = blink.region_id
|
||||
self.name = 'sync'
|
||||
self.name = network_name
|
||||
self.serial = None
|
||||
self.status = None
|
||||
self.sync_id = None
|
||||
@@ -79,7 +79,6 @@ class BlinkSyncModule():
|
||||
"""Initialize the system."""
|
||||
response = api.request_syncmodule(self.blink, self.network_id)
|
||||
self.summary = response['syncmodule']
|
||||
self.name = self.summary['name']
|
||||
self.sync_id = self.summary['id']
|
||||
self.network_id = self.summary['network_id']
|
||||
self.serial = self.summary['serial']
|
||||
|
||||
+4
-17
@@ -1,30 +1,17 @@
|
||||
.. _core_module:
|
||||
|
||||
:mod:`blinkpy`
|
||||
Blinkpy
|
||||
----------------------
|
||||
|
||||
.. automodule:: blinkpy.blinkpy
|
||||
:members:
|
||||
|
||||
.. automodule:: blinkpy.sync_module
|
||||
:members:
|
||||
|
||||
.. automodule:: blinkpy.camera
|
||||
:members:
|
||||
|
||||
.. automodule:: blinkpy.helpers.util
|
||||
|
||||
.. autoclass:: blinkpy.blinkpy.Blink
|
||||
:members:
|
||||
|
||||
.. autoclass:: blinkpy.sync_module.BlinkSyncModule
|
||||
:members:
|
||||
|
||||
.. autoclass:: blinkpy.camera.BlinkCamera
|
||||
:members:
|
||||
|
||||
.. autoclass:: blinkpy.helpers.util.BlinkURLHandler
|
||||
:members:
|
||||
|
||||
.. autofunction:: blinkpy.helpers.util.create_session
|
||||
|
||||
.. autofunction:: blinkpy.helpers.util.http_req
|
||||
|
||||
.. autofunction:: blinkpy.helpers.util.attempt_reauthorization
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
API Reference
|
||||
----------------------
|
||||
|
||||
.. automodule:: blinkpy.api
|
||||
:members:
|
||||
|
||||
@@ -70,3 +70,15 @@ class TestBlinkFunctions(unittest.TestCase):
|
||||
self.assertEqual(self.blink.region, 'UNKNOWN')
|
||||
# pylint: disable=protected-access
|
||||
self.assertEqual(self.blink._token, 'foobar123')
|
||||
|
||||
def test_merge_cameras(self, mock_sess):
|
||||
"""Test merge camera functionality."""
|
||||
first_dict = {'foo': 'bar', 'test': 123}
|
||||
next_dict = {'foobar': 456, 'bar': 'foo'}
|
||||
self.blink.sync['foo'] = BlinkSyncModule(self.blink, 'foo', 1)
|
||||
self.blink.sync['bar'] = BlinkSyncModule(self.blink, 'bar', 2)
|
||||
self.blink.sync['foo'].cameras = first_dict
|
||||
self.blink.sync['bar'].cameras = next_dict
|
||||
result = self.blink.merge_cameras()
|
||||
expected = {'foo': 'bar', 'test': 123, 'foobar': 456, 'bar': 'foo'}
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
+25
-5
@@ -30,7 +30,7 @@ class TestBlinkSetup(unittest.TestCase):
|
||||
self.blink_no_cred = Blink()
|
||||
self.blink = Blink(username=USERNAME,
|
||||
password=PASSWORD)
|
||||
self.blink.sync = BlinkSyncModule(self.blink)
|
||||
self.blink.sync['test'] = BlinkSyncModule(self.blink, 'test', '1234')
|
||||
self.blink.urls = BlinkURLHandler('test')
|
||||
self.blink.session = create_session()
|
||||
|
||||
@@ -110,13 +110,28 @@ class TestBlinkSetup(unittest.TestCase):
|
||||
'networks': [{'id': 1234, 'account_id': 1111},
|
||||
{'id': 5678, 'account_id': 2222}]
|
||||
}
|
||||
self.blink.networks = {'0000': {'onboarded': False},
|
||||
'5678': {'onboarded': True},
|
||||
'1234': {'onboarded': False}}
|
||||
self.blink.networks = {'0000': {'onboarded': False, 'name': 'foo'},
|
||||
'5678': {'onboarded': True, 'name': 'bar'},
|
||||
'1234': {'onboarded': False, 'name': 'test'}}
|
||||
self.blink.get_ids()
|
||||
self.assertEqual(self.blink.network_id, '5678')
|
||||
self.assertTrue('5678' in self.blink.network_ids)
|
||||
self.assertEqual(self.blink.account_id, 2222)
|
||||
|
||||
@mock.patch('blinkpy.api.request_networks')
|
||||
def test_multiple_onboarded_networks(self, mock_net, mock_sess):
|
||||
"""Check that we handle multiple networks appropriately."""
|
||||
mock_net.return_value = {
|
||||
'networks': [{'id': 0000, 'account_id': 2222},
|
||||
{'id': 5678, 'account_id': 1111}]
|
||||
}
|
||||
self.blink.networks = {'0000': {'onboarded': False, 'name': 'foo'},
|
||||
'5678': {'onboarded': True, 'name': 'bar'},
|
||||
'1234': {'onboarded': True, 'name': 'test'}}
|
||||
self.blink.get_ids()
|
||||
self.assertTrue('5678' in self.blink.network_ids)
|
||||
self.assertTrue('1234' in self.blink.network_ids)
|
||||
self.assertEqual(self.blink.account_id, 1111)
|
||||
|
||||
@mock.patch('blinkpy.blinkpy.time.time')
|
||||
def test_throttle(self, mock_time, mock_sess):
|
||||
"""Check throttling functionality."""
|
||||
@@ -128,3 +143,8 @@ class TestBlinkSetup(unittest.TestCase):
|
||||
self.assertEqual(result, True)
|
||||
self.assertEqual(self.blink.check_if_ok_to_update(), False)
|
||||
self.assertEqual(self.blink.last_refresh, now)
|
||||
|
||||
def test_sync_case_insensitive_dict(self, mock_sess):
|
||||
"""Check that we can access sync modules ignoring case."""
|
||||
self.assertEqual(self.blink.sync['test'].name, 'test')
|
||||
self.assertEqual(self.blink.sync['TEST'].name, 'test')
|
||||
|
||||
+12
-5
@@ -46,10 +46,10 @@ class TestBlinkCameraSetup(unittest.TestCase):
|
||||
self.blink._auth_header = header
|
||||
self.blink.session = create_session()
|
||||
self.blink.urls = BlinkURLHandler('test')
|
||||
self.blink.sync = BlinkSyncModule(self.blink)
|
||||
self.camera = BlinkCamera(self.blink.sync)
|
||||
self.blink.sync['test'] = BlinkSyncModule(self.blink, 'test', 1234)
|
||||
self.camera = BlinkCamera(self.blink.sync['test'])
|
||||
self.camera.name = 'foobar'
|
||||
self.blink.sync.cameras['foobar'] = self.camera
|
||||
self.blink.sync['test'].cameras['foobar'] = self.camera
|
||||
|
||||
def tearDown(self):
|
||||
"""Clean up after test."""
|
||||
@@ -98,6 +98,7 @@ class TestBlinkCameraSetup(unittest.TestCase):
|
||||
self.camera.last_record = ['1']
|
||||
self.camera.sync.all_clips = {'new': {'1': '/test.mp4'}}
|
||||
mock_sess.side_effect = [
|
||||
mresp.MockResponse({'temp': 71}, 200),
|
||||
'test',
|
||||
'foobar'
|
||||
]
|
||||
@@ -110,6 +111,7 @@ class TestBlinkCameraSetup(unittest.TestCase):
|
||||
self.assertEqual(self.camera.battery, 50)
|
||||
self.assertEqual(self.camera.temperature, 68)
|
||||
self.assertEqual(self.camera.temperature_c, 20)
|
||||
self.assertEqual(self.camera.temperature_calibrated, 71)
|
||||
self.assertEqual(self.camera.wifi_strength, 4)
|
||||
self.assertEqual(self.camera.thumbnail,
|
||||
'https://rest.test.immedia-semi.com/thumb.jpg')
|
||||
@@ -120,7 +122,11 @@ class TestBlinkCameraSetup(unittest.TestCase):
|
||||
|
||||
def test_thumbnail_not_in_info(self, mock_sess):
|
||||
"""Test that we grab thumbanil if not in camera_info."""
|
||||
mock_sess.side_effect = ['foobar', 'barfoo']
|
||||
mock_sess.side_effect = [
|
||||
mresp.MockResponse({'temp': 71}, 200),
|
||||
'foobar',
|
||||
'barfoo'
|
||||
]
|
||||
self.camera.last_record = ['1']
|
||||
self.camera.sync.record_dates['new'] = ['1']
|
||||
self.camera.sync.all_clips = {'new': {'1': '/test.mp4'}}
|
||||
@@ -175,7 +181,8 @@ class TestBlinkCameraSetup(unittest.TestCase):
|
||||
self.assertEqual(self.camera.thumbnail, None)
|
||||
self.assertEqual(
|
||||
logrecord.output,
|
||||
["ERROR:blinkpy.camera:Could not find thumbnail for camera new"]
|
||||
["ERROR:blinkpy.camera:Could not retrieve calibrated temperature.",
|
||||
"ERROR:blinkpy.camera:Could not find thumbnail for camera new"]
|
||||
)
|
||||
|
||||
def test_no_video_clips(self, mock_sess):
|
||||
|
||||
+16
-17
@@ -24,7 +24,7 @@ class TestBlinkSyncModule(unittest.TestCase):
|
||||
'TOKEN_AUTH': 'foobar123'
|
||||
}
|
||||
self.blink.urls = blinkpy.BlinkURLHandler('test')
|
||||
self.blink.sync = BlinkSyncModule(self.blink)
|
||||
self.blink.sync['test'] = BlinkSyncModule(self.blink, 'test', '1234')
|
||||
self.camera = BlinkCamera(self.blink.sync)
|
||||
|
||||
def tearDown(self):
|
||||
@@ -35,12 +35,12 @@ class TestBlinkSyncModule(unittest.TestCase):
|
||||
def test_get_events(self, mock_resp):
|
||||
"""Test get events function."""
|
||||
mock_resp.return_value = {'event': True}
|
||||
self.assertEqual(self.blink.sync.get_events(), True)
|
||||
self.assertEqual(self.blink.sync['test'].get_events(), True)
|
||||
|
||||
def test_get_camera_info(self, mock_resp):
|
||||
"""Test get camera info function."""
|
||||
mock_resp.return_value = {'devicestatus': True}
|
||||
self.assertEqual(self.blink.sync.get_camera_info(), True)
|
||||
self.assertEqual(self.blink.sync['test'].get_camera_info(), True)
|
||||
|
||||
def test_get_videos_one_page(self, mock_resp):
|
||||
"""Test video access."""
|
||||
@@ -54,13 +54,13 @@ class TestBlinkSyncModule(unittest.TestCase):
|
||||
expected_videos = {'foobar': [
|
||||
{'clip': '/test/clip_1900_01_01_12_00_00AM.mp4',
|
||||
'thumb': '/test/thumb'}]}
|
||||
expected_records = {'foobar': ['1900_01_01_12_00_00AM']}
|
||||
expected_recs = {'foobar': ['1900_01_01_12_00_00AM']}
|
||||
expected_clips = {'foobar': {
|
||||
'1900_01_01_12_00_00AM': '/test/clip_1900_01_01_12_00_00AM.mp4'}}
|
||||
self.blink.sync.get_videos(start_page=0, end_page=0)
|
||||
self.assertEqual(self.blink.sync.videos, expected_videos)
|
||||
self.assertEqual(self.blink.sync.record_dates, expected_records)
|
||||
self.assertEqual(self.blink.sync.all_clips, expected_clips)
|
||||
self.blink.sync['test'].get_videos(start_page=0, end_page=0)
|
||||
self.assertEqual(self.blink.sync['test'].videos, expected_videos)
|
||||
self.assertEqual(self.blink.sync['test'].record_dates, expected_recs)
|
||||
self.assertEqual(self.blink.sync['test'].all_clips, expected_clips)
|
||||
|
||||
def test_get_videos_multi_page(self, mock_resp):
|
||||
"""Test video access with multiple pages."""
|
||||
@@ -71,17 +71,16 @@ class TestBlinkSyncModule(unittest.TestCase):
|
||||
'thumbnail': '/foobar'
|
||||
}
|
||||
]
|
||||
self.blink.sync.get_videos()
|
||||
self.blink.sync['test'].get_videos()
|
||||
self.assertEqual(mock_resp.call_count, 2)
|
||||
mock_resp.reset_mock()
|
||||
self.blink.sync.get_videos(start_page=0, end_page=9)
|
||||
self.blink.sync['test'].get_videos(start_page=0, end_page=9)
|
||||
self.assertEqual(mock_resp.call_count, 10)
|
||||
|
||||
def test_sync_start(self, mock_resp):
|
||||
"""Test sync start function."""
|
||||
mock_resp.side_effect = [
|
||||
{'syncmodule': {
|
||||
'name': 'test',
|
||||
'id': 1234,
|
||||
'network_id': 5678,
|
||||
'serial': '12345678',
|
||||
@@ -93,9 +92,9 @@ class TestBlinkSyncModule(unittest.TestCase):
|
||||
None,
|
||||
None
|
||||
]
|
||||
self.blink.sync.start()
|
||||
self.assertEqual(self.blink.sync.name, 'test')
|
||||
self.assertEqual(self.blink.sync.sync_id, 1234)
|
||||
self.assertEqual(self.blink.sync.network_id, 5678)
|
||||
self.assertEqual(self.blink.sync.serial, '12345678')
|
||||
self.assertEqual(self.blink.sync.status, 'foobar')
|
||||
self.blink.sync['test'].start()
|
||||
self.assertEqual(self.blink.sync['test'].name, 'test')
|
||||
self.assertEqual(self.blink.sync['test'].sync_id, 1234)
|
||||
self.assertEqual(self.blink.sync['test'].network_id, 5678)
|
||||
self.assertEqual(self.blink.sync['test'].serial, '12345678')
|
||||
self.assertEqual(self.blink.sync['test'].status, 'foobar')
|
||||
|
||||
Reference in New Issue
Block a user