Skip to content

Commit

Permalink
Merge pull request #136 from fronzbot/dev
Browse files Browse the repository at this point in the history
0.11.1
  • Loading branch information
fronzbot authored Jan 2, 2019
2 parents 1a24e18 + 8153fab commit 853ccbc
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 41 deletions.
70 changes: 36 additions & 34 deletions API.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
# 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

I am not affiliated with the company in any way - this documentation is strictly **"AS-IS"**. My goal was to uncover enough to arm and disarm the system programatically so that I can issue those commands in sync with my home alarm system arm/disarm. Just some raw notes at this point but should be enough for creating programmatic APIs. Lots more to be discovered and documented - feel free to contribute!

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.
Expand All @@ -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.
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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.
Expand All @@ -103,20 +105,20 @@ 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.

**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
Expand Down Expand Up @@ -144,65 +146,65 @@ 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.

**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.

**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

**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

**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

**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

**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
Expand All @@ -212,39 +214,39 @@ 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

**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

**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

**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

**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
Expand All @@ -257,31 +259,31 @@ 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

**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

**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"

**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 changes: 10 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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>`__)
Expand Down
11 changes: 11 additions & 0 deletions blinkpy/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def __init__(self, sync):
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
Expand All @@ -40,6 +41,7 @@ def attributes(self):
'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,
Expand Down Expand Up @@ -104,6 +106,15 @@ def update(self, config, force_cache=False):
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
Expand Down
10 changes: 5 additions & 5 deletions blinkpy/helpers/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

MAJOR_VERSION = 0
MINOR_VERSION = 11
PATCH_VERSION = 0
PATCH_VERSION = 1

__version__ = '{}.{}.{}'.format(MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION)

Expand Down Expand Up @@ -45,10 +45,10 @@
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
Expand Down
11 changes: 9 additions & 2 deletions tests/test_cameras.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ def test_camera_update(self, mock_sess):
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'
]
Expand All @@ -110,6 +111,7 @@ def test_camera_update(self, mock_sess):
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')
Expand All @@ -120,7 +122,11 @@ def test_camera_update(self, mock_sess):

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'}}
Expand Down Expand Up @@ -175,7 +181,8 @@ def test_no_thumbnails(self, mock_sess):
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):
Expand Down

0 comments on commit 853ccbc

Please sign in to comment.