Skip to content

Commit 5f929f0

Browse files
authored
Merge pull request #849 from fronzbot/dev
0.22.5
2 parents 0944fed + eebcd0c commit 5f929f0

22 files changed

+183
-164
lines changed

.github/workflows/coverage.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ jobs:
1414
matrix:
1515
platform:
1616
- ubuntu-latest
17-
python-version: ['3.9']
17+
python-version: ['3.11']
1818

1919
steps:
20-
- uses: actions/checkout@v3
20+
- uses: actions/checkout@v4
2121
- name: Set up Python ${{ matrix.python-version }}
2222
uses: actions/setup-python@v4
2323
with:
@@ -33,7 +33,7 @@ jobs:
3333
run: |
3434
tox -r -e cov
3535
- name: Codecov
36-
uses: codecov/codecov-action@v1
36+
uses: codecov/codecov-action@v3
3737
with:
3838
token: ${{ secrets.CODECOV_TOKEN }}
3939
flags: unittests

.github/workflows/lint.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ jobs:
1414
runs-on: ubuntu-latest
1515
strategy:
1616
matrix:
17-
python-version: [3.9]
17+
python-version: [3.11]
1818

1919
steps:
20-
- uses: actions/checkout@v2
20+
- uses: actions/checkout@v4
2121
- name: Set up Python ${{ matrix.python-version }}
2222
uses: actions/setup-python@v4
2323
with:

.github/workflows/publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717
- name: Set up Python
1818
uses: actions/setup-python@v4
1919
with:
20-
python-version: '3.9'
20+
python-version: '3.11'
2121
- name: Install dependencies
2222
run: |
2323
python -m pip install --upgrade pip

.github/workflows/tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
matrix:
1515
platform:
1616
- ubuntu-latest
17-
python-version: ['3.8', '3.9', '3.10', '3.11']
17+
python-version: ['3.9', '3.10', '3.11', '3.12']
1818

1919
steps:
2020
- uses: actions/checkout@v3

CHANGES.rst

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,42 @@ Changelog
44

55
A list of changes between each release
66

7+
0.22.5 (2024-01-07)
8+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9+
10+
Warning: This release removes support for Python 3.8 and adds Python 3.12 support.
11+
12+
**Bugfixes**
13+
14+
- Add new keys for wifi, lfr, and battery (`mkmer #835 <https://github.com/fronzbot/blinkpy/pull/835>`__)
15+
- Battery level (`mkmer #837 <https://github.com/fronzbot/blinkpy/pull/837>`__)
16+
- Address not awaited warning (`mkmer #838 <https://github.com/fronzbot/blinkpy/pull/838>`__)
17+
- Catch ContentTypeError in 2FA (`mkmer #843 <https://github.com/fronzbot/blinkpy/pull/843>`__)
18+
- Handle empty put response in wait_command (`mkmer #847 <https://github.com/fronzbot/blinkpy/pull/847>`__)
19+
- Change default user agent to fix API calls (`gingerm0nkey #848 <https://github.com/fronzbot/blinkpy/pull/848>`__)
20+
- Android for new user agent (`mkmer #850 <https://github.com/fronzbot/blinkpy/pull/850>`__)
21+
22+
**Other changes**
23+
24+
- Remove Py3.8, add 3.12 (`fronzbot #839 <https://github.com/fronzbot/blinkpy/pull/839>`__)
25+
- Deprecate py38 (`fronzbot #840 <https://github.com/fronzbot/blinkpy/pull/840>`__)
26+
- Add/extract firmware version (`mkmer #842 <https://github.com/fronzbot/blinkpy/pull/842>`__)
27+
- Additional logging, fix blinksync json (`mkmer #844 <https://github.com/fronzbot/blinkpy/pull/844>`__)
28+
- Log text response (`mkmer #845 <https://github.com/fronzbot/blinkpy/pull/845>`__)
29+
- Add tests for logging (`mkmer #846 <https://github.com/fronzbot/blinkpy/pull/846>`__)
30+
- Bump ruff to 0.1.11
31+
- Bump black to 23.12.1
32+
- Bump coverage to 7.4.0
33+
- Bump pytest to 7.4.4
34+
35+
736
0.22.4 (2023-12-18)
837
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
938

1039
**Bugfixes**
1140

12-
- Allow kwargs to throttled functions, await sleep in throttle (`mkmer #823 <https://github.com/fronzbot/blinkpy/pull/800>`__)
13-
- add missing entry in type_key_map (`@Rosi2143 <https://github.com/fronzbot/blinkpy/pull/813>`__)
41+
- Allow kwargs to throttled functions, await sleep in throttle (`mkmer #823 <https://github.com/fronzbot/blinkpy/pull/823>`__)
42+
- add missing entry in type_key_map (`@Rosi2143 #813 <https://github.com/fronzbot/blinkpy/pull/813>`__)
1443

1544
** Other Changes **
1645

README.rst

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
blinkpy |Build Status| |Coverage Status| |PyPi Version| |Codestyle|
22
=============================================================================================
3-
A Python library for the Blink Camera system (Python 3.8+)
3+
A Python library for the Blink Camera system (Python 3.9+)
44

55
Like the library? Consider buying me a cup of coffee!
66

@@ -32,9 +32,7 @@ To install the current development version, perform the following steps. Note t
3232
$ cd ~
3333
$ git clone https://github.com/fronzbot/blinkpy.git
3434
$ cd blinkpy
35-
$ rm -rf build dist
36-
$ python3 setup.py bdist_wheel
37-
$ pip3 install --upgrade dist/*.whl
35+
$ pip install .
3836
3937
4038
If you'd like to contribute to this library, please read the `contributing instructions <https://github.com/fronzbot/blinkpy/blob/dev/CONTRIBUTING.rst>`__.

blinkpy/api.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -503,8 +503,11 @@ async def http_post(blink, url, is_retry=False, data=None, json=True, timeout=TI
503503
async def wait_for_command(blink, json_data: dict) -> bool:
504504
"""Wait for command to complete."""
505505
_LOGGER.debug("Command Wait %s", json_data)
506-
network_id = json_data.get("network_id")
507-
command_id = json_data.get("id")
506+
try:
507+
network_id = json_data.get("network_id")
508+
command_id = json_data.get("id")
509+
except AttributeError:
510+
return False
508511
if command_id and network_id:
509512
for _ in range(0, MAX_RETRY):
510513
_LOGGER.debug("Making GET request waiting for command")

blinkpy/auth.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
"""Login handler for blink."""
22
import logging
3-
from aiohttp import ClientSession, ClientConnectionError
3+
from aiohttp import (
4+
ClientSession,
5+
ClientConnectionError,
6+
ContentTypeError,
7+
ClientResponse,
8+
)
49
from blinkpy import api
510
from blinkpy.helpers import util
611
from blinkpy.helpers.constants import (
@@ -123,7 +128,7 @@ async def startup(self):
123128
if None in self.login_attributes.values():
124129
await self.refresh_token()
125130

126-
async def validate_response(self, response, json_resp):
131+
async def validate_response(self, response: ClientResponse, json_resp):
127132
"""Check for valid response."""
128133
if not json_resp:
129134
self.is_errored = False
@@ -137,6 +142,9 @@ async def validate_response(self, response, json_resp):
137142
json_data = await response.json()
138143
except (AttributeError, ValueError) as error:
139144
raise BlinkBadResponse from error
145+
except ContentTypeError as error:
146+
_LOGGER.warning("Got text for JSON response: %s", await response.text())
147+
raise BlinkBadResponse from error
140148

141149
self.is_errored = False
142150
return json_data
@@ -172,10 +180,11 @@ async def query(
172180
url=url, data=data, headers=headers, timeout=timeout
173181
)
174182
return await self.validate_response(response, json_resp)
175-
except (ClientConnectionError, TimeoutError):
183+
except (ClientConnectionError, TimeoutError) as er:
176184
_LOGGER.error(
177-
"Connection error. Endpoint %s possibly down or throttled.",
185+
"Connection error. Endpoint %s possibly down or throttled. Error: %s",
178186
url,
187+
er,
179188
)
180189
except BlinkBadResponse:
181190
code = None
@@ -220,8 +229,11 @@ async def send_auth_key(self, blink, key):
220229
if not blink.available:
221230
_LOGGER.error("%s", json_resp["message"])
222231
return False
223-
except (KeyError, TypeError):
224-
_LOGGER.error("Did not receive valid response from server.")
232+
except (KeyError, TypeError, ContentTypeError) as er:
233+
_LOGGER.error(
234+
"Did not receive valid response from server. Error: %s",
235+
er,
236+
)
225237
return False
226238
return True
227239

blinkpy/camera.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@ def __init__(self, sync):
2727
self.network_id = None
2828
self.thumbnail = None
2929
self.serial = None
30+
self.version = None
3031
self.motion_enabled = None
31-
self.battery_voltage = None
32+
self.battery_level = None
3233
self.clip = None
3334
# A clip remains in the recent clips list until is has
3435
# been downloaded or has been expired.
@@ -43,6 +44,7 @@ def __init__(self, sync):
4344
self._cached_video = None
4445
self.camera_type = ""
4546
self.product_type = None
47+
self.sync_signal_strength = None
4648

4749
@property
4850
def attributes(self):
@@ -51,11 +53,12 @@ def attributes(self):
5153
"name": self.name,
5254
"camera_id": self.camera_id,
5355
"serial": self.serial,
56+
"version": self.version,
5457
"temperature": self.temperature,
5558
"temperature_c": self.temperature_c,
5659
"temperature_calibrated": self.temperature_calibrated,
5760
"battery": self.battery,
58-
"battery_voltage": self.battery_voltage,
61+
"battery_level": self.battery_level,
5962
"thumbnail": self.thumbnail,
6063
"video": self.clip,
6164
"recent_clips": self.recent_clips,
@@ -64,6 +67,7 @@ def attributes(self):
6467
"wifi_strength": self.wifi_strength,
6568
"network_id": self.sync.network_id,
6669
"sync_module": self.sync.name,
70+
"sync_signal_strength": self.sync_signal_strength,
6771
"last_record": self.last_record,
6872
"type": self.product_type,
6973
}
@@ -229,15 +233,18 @@ def extract_config_info(self, config):
229233
self.name = config.get("name", "unknown")
230234
self.camera_id = str(config.get("id", "unknown"))
231235
self.network_id = str(config.get("network_id", "unknown"))
232-
self.serial = config.get("serial", None)
236+
self.serial = config.get("serial")
237+
self.version = config.get("fw_version")
233238
self.motion_enabled = config.get("enabled", "unknown")
234-
self.battery_voltage = config.get("battery_voltage", None)
235-
self.battery_state = config.get("battery_state", None) or config.get(
236-
"battery", None
237-
)
238-
self.temperature = config.get("temperature", None)
239-
self.wifi_strength = config.get("wifi_strength", None)
240-
self.product_type = config.get("type", None)
239+
self.battery_state = config.get("battery_state") or config.get("battery")
240+
self.temperature = config.get("temperature")
241+
if signals := config.get("signals"):
242+
self.wifi_strength = signals.get("wifi")
243+
self.battery_level = signals.get("battery")
244+
self.sync_signal_strength = signals.get("lfr")
245+
else:
246+
self.wifi_strength = config.get("wifi_strength")
247+
self.product_type = config.get("type")
241248

242249
async def get_sensor_info(self):
243250
"""Retrieve calibrated temperature from special endpoint."""

blinkpy/helpers/constants.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,8 @@
2020
"""
2121
OTHER
2222
"""
23-
DEFAULT_USER_AGENT = (
24-
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) "
25-
"AppleWebKit/537.36 (KHTML, like Gecko) "
26-
"Chrome/71.0.3578.98 Safari/537.36"
27-
)
23+
24+
DEFAULT_USER_AGENT = "27.0ANDROID_28373244"
2825
DEVICE_ID = "Blinkpy"
2926
TIMESTAMP_FORMAT = "%Y-%m-%dT%H:%M:%S%z"
3027
DEFAULT_MOTION_INTERVAL = 1

blinkpy/sync_module.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def __init__(self, blink, network_name, network_id, camera_list):
3434
self.region_id = blink.auth.region_id
3535
self.name = network_name
3636
self.serial = None
37+
self.version = None
3738
self.status = "offline"
3839
self.sync_id = None
3940
self.host = None
@@ -72,6 +73,7 @@ def attributes(self):
7273
"id": self.sync_id,
7374
"network_id": self.network_id,
7475
"serial": self.serial,
76+
"version": self.version,
7577
"status": self.status,
7678
"region_id": self.region_id,
7779
"local_storage": self.local_storage,
@@ -153,6 +155,7 @@ async def sync_initialize(self):
153155
"Could not retrieve sync module information with response: %s", response
154156
)
155157
return False
158+
self.version = self.summary.get("fw_version")
156159
return response
157160

158161
async def _init_local_storage(self, sync_id):

blinksync/blinksync.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ async def main():
100100
working = None
101101
frame = None
102102
await session.close()
103+
await blink.save(f"{path}/blink.json")
103104

104105

105106
# Run the program

pyproject.toml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "blinkpy"
7-
version = "0.22.4"
7+
version = "0.22.5"
88
license = {text = "MIT"}
99
description = "A Blink camera Python Library."
1010
readme = "README.rst"
@@ -15,13 +15,13 @@ classifiers = [
1515
"Intended Audience :: Developers",
1616
"License :: OSI Approved :: MIT License",
1717
"Operating System :: OS Independent",
18-
"Programming Language :: Python :: 3.8",
1918
"Programming Language :: Python :: 3.9",
2019
"Programming Language :: Python :: 3.10",
2120
"Programming Language :: Python :: 3.11",
21+
"Programming Language :: Python :: 3.12",
2222
"Topic :: Home Automation",
2323
]
24-
requires-python = ">=3.8.0"
24+
requires-python = ">=3.9.0"
2525
dynamic = ["dependencies"]
2626

2727
[tool.setuptools.dynamic]
@@ -79,13 +79,14 @@ ignore = [
7979
"UP006", # keep type annotation style as is
8080
"UP007", # keep type annotation style as is
8181
"UP015", # Unnecessary open mode parameters
82+
"UP017", # UTC stuff
8283
# Ignored due to performance: https://github.com/charliermarsh/ruff/issues/2923
8384
"UP038", # Use `X | Y` in `isinstance` call instead of `(X, Y)`
8485
]
8586

8687
line-length = 88
8788

88-
target-version = "py39"
89+
target-version = "py311"
8990

9091
[tool.ruff.per-file-ignores]
9192

requirements_test.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
ruff==0.1.8
2-
black==23.12.0
1+
ruff==0.1.11
2+
black==23.12.1
33
build==1.0.3
4-
coverage==7.3.2
5-
pytest==7.4.3
4+
coverage==7.4.0
5+
pytest==7.4.4
66
pytest-cov==4.1.0
77
pytest-sugar==0.9.7
88
pytest-timeout==2.2.0

tests/mock_responses.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,28 @@
55
class MockResponse:
66
"""Class for mock request response."""
77

8-
def __init__(self, json_data, status_code, headers={}, raw_data=None):
8+
def __init__(
9+
self,
10+
json_data,
11+
status_code,
12+
headers={},
13+
raw_data=None,
14+
raise_error=None,
15+
):
916
"""Initialize mock get response."""
1017
self.json_data = json_data
1118
self.status = status_code
1219
self.raw_data = raw_data
1320
self.reason = "foobar"
1421
self.headers = headers
1522
self.read = mock.AsyncMock(return_value=self.raw_data)
23+
self.raise_error = raise_error
24+
self.text = mock.AsyncMock(return_vlaue="some text")
1625

1726
async def json(self):
1827
"""Return json data from get_request."""
28+
if self.raise_error:
29+
raise self.raise_error("I'm broken", "")
1930
return self.json_data
2031

2132
def get(self, name):

tests/test_api.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,3 +183,6 @@ async def test_wait_for_command(self, mock_resp):
183183
mock_resp.side_effect = (COMMAND_COMPLETE_BAD, {})
184184
response = await api.wait_for_command(self.blink, COMMAND_RESPONSE)
185185
self.assertFalse(response)
186+
187+
response = await api.wait_for_command(self.blink, None)
188+
self.assertFalse(response)

0 commit comments

Comments
 (0)