diff --git a/CHANGES.rst b/CHANGES.rst index cf43887d..e48065ed 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,6 +4,27 @@ Changelog A list of changes between each release + +0.22.6 (2024-01-24) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Bugfixes** + +- Test for None type in poll_local_storage_manifest (`@mkmer #859 `__) +- Update image after snap by (`@mkmer #861 `__) +- fix missing ':' before port number in rtsps adress (`@Rosi2143 #863 `__) +- New temperature location (`@mkmer #867 `__) + +**Other changes** + +- Add properties for version information (`@mkmer #854 `__) +- Complete header match (`@mkmer #856 `__) +- Bump ruff from 0.1.11 to 0.1.13 (`@dependabot #858 `__) +- Add option to change agent from Auth() init (`@mkmer #860 `__) +- Add notification key to login (`@mkmer #862 `__) +- Bump ruff from 0.1.13 to 0.1.14 (`@dependabot #868 `__) + + 0.22.5 (2024-01-07) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -11,22 +32,22 @@ Warning: This release removes support for Python 3.8 and adds Python 3.12 suppor **Bugfixes** -- Add new keys for wifi, lfr, and battery (`mkmer #835 `__) -- Battery level (`mkmer #837 `__) -- Address not awaited warning (`mkmer #838 `__) -- Catch ContentTypeError in 2FA (`mkmer #843 `__) -- Handle empty put response in wait_command (`mkmer #847 `__) -- Change default user agent to fix API calls (`gingerm0nkey #848 `__) -- Android for new user agent (`mkmer #850 `__) +- Add new keys for wifi, lfr, and battery (`@mkmer #835 `__) +- Battery level (`@mkmer #837 `__) +- Address not awaited warning (`@mkmer #838 `__) +- Catch ContentTypeError in 2FA (`@mkmer #843 `__) +- Handle empty put response in wait_command (`@mkmer #847 `__) +- Change default user agent to fix API calls (`@gingerm0nkey #848 `__) +- Android for new user agent (`@mkmer #850 `__) **Other changes** -- Remove Py3.8, add 3.12 (`fronzbot #839 `__) -- Deprecate py38 (`fronzbot #840 `__) -- Add/extract firmware version (`mkmer #842 `__) -- Additional logging, fix blinksync json (`mkmer #844 `__) -- Log text response (`mkmer #845 `__) -- Add tests for logging (`mkmer #846 `__) +- Remove Py3.8, add 3.12 (`@fronzbot #839 `__) +- Deprecate py38 (`@fronzbot #840 `__) +- Add/extract firmware version (`@mkmer #842 `__) +- Additional logging, fix blinksync json (`@mkmer #844 `__) +- Log text response (`@mkmer #845 `__) +- Add tests for logging (`@mkmer #846 `__) - Bump ruff to 0.1.11 - Bump black to 23.12.1 - Bump coverage to 7.4.0 @@ -38,7 +59,7 @@ Warning: This release removes support for Python 3.8 and adds Python 3.12 suppor **Bugfixes** -- Allow kwargs to throttled functions, await sleep in throttle (`mkmer #823 `__) +- Allow kwargs to throttled functions, await sleep in throttle (`@mkmer #823 `__) - add missing entry in type_key_map (`@Rosi2143 #813 `__) ** Other Changes ** diff --git a/blinkpy/api.py b/blinkpy/api.py index 82485dad..60a177ad 100644 --- a/blinkpy/api.py +++ b/blinkpy/api.py @@ -37,6 +37,7 @@ async def request_login( "Content-Type": "application/json", "user-agent": DEFAULT_USER_AGENT, } + data = dumps( { "email": login_data["username"], diff --git a/blinkpy/auth.py b/blinkpy/auth.py index bb559907..250a081a 100644 --- a/blinkpy/auth.py +++ b/blinkpy/auth.py @@ -10,6 +10,7 @@ from blinkpy.helpers import util from blinkpy.helpers.constants import ( BLINK_URL, + APP_BUILD, DEFAULT_USER_AGENT, LOGIN_ENDPOINT, TIMEOUT, @@ -21,7 +22,14 @@ class Auth: """Class to handle login communication.""" - def __init__(self, login_data=None, no_prompt=False, session=None): + def __init__( + self, + login_data=None, + no_prompt=False, + session=None, + agent=DEFAULT_USER_AGENT, + app_build=APP_BUILD, + ): """ Initialize auth handler. @@ -43,10 +51,9 @@ def __init__(self, login_data=None, no_prompt=False, session=None): self.login_response = None self.is_errored = False self.no_prompt = no_prompt - if session: - self.session = session - else: - self.session = ClientSession() + self._agent = agent + self._app_build = app_build + self.session = session if session else ClientSession() @property def login_attributes(self): @@ -64,9 +71,10 @@ def header(self): if self.token is None: return None return { + "APP-BUILD": self._app_build, "TOKEN_AUTH": self.token, - "user-agent": DEFAULT_USER_AGENT, - "content-type": "application/json", + "User-Agent": self._agent, + "Content-Type": "application/json", } def validate_login(self): diff --git a/blinkpy/camera.py b/blinkpy/camera.py index ba0a37b1..e0283439 100644 --- a/blinkpy/camera.py +++ b/blinkpy/camera.py @@ -27,7 +27,7 @@ def __init__(self, sync): self.network_id = None self.thumbnail = None self.serial = None - self.version = None + self._version = None self.motion_enabled = None self.battery_level = None self.clip = None @@ -53,7 +53,7 @@ def attributes(self): "name": self.name, "camera_id": self.camera_id, "serial": self.serial, - "version": self.version, + "version": self._version, "temperature": self.temperature, "temperature_c": self.temperature_c, "temperature_calibrated": self.temperature_calibrated, @@ -100,6 +100,11 @@ def video_from_cache(self): return self._cached_video return None + @property + def version(self): + """Return the camera Firmware version.""" + return self._version + @property def arm(self): """Return arm status of camera.""" @@ -201,9 +206,14 @@ async def get_video_clip(self, url=None): async def snap_picture(self): """Take a picture with camera to create a new thumbnail.""" - return await api.request_new_image( + ret_val = await api.request_new_image( self.sync.blink, self.network_id, self.camera_id ) + response = await self.get_media() + if response and response.status == 200: + self._cached_image = await response.read() + + return ret_val async def set_motion_detect(self, enable): """Set motion detection.""" @@ -234,16 +244,17 @@ def extract_config_info(self, config): self.camera_id = str(config.get("id", "unknown")) self.network_id = str(config.get("network_id", "unknown")) self.serial = config.get("serial") - self.version = config.get("fw_version") + self._version = config.get("fw_version") self.motion_enabled = config.get("enabled", "unknown") self.battery_state = config.get("battery_state") or config.get("battery") - self.temperature = config.get("temperature") if signals := config.get("signals"): self.wifi_strength = signals.get("wifi") self.battery_level = signals.get("battery") self.sync_signal_strength = signals.get("lfr") + self.temperature = signals.get("temp") else: self.wifi_strength = config.get("wifi_strength") + self.temperature = config.get("temperature") self.product_type = config.get("type") async def get_sensor_info(self): @@ -522,8 +533,8 @@ async def get_liveview(self): await api.wait_for_command(self.sync.blink, response) server = response["server"] server_split = server.split(":") - server_split[0] = "rtsps:" - link = "".join(server_split) + server_split[0] = "rtsps" + link = ":".join(server_split) return link diff --git a/blinkpy/helpers/constants.py b/blinkpy/helpers/constants.py index 6af0671a..6ffc530b 100644 --- a/blinkpy/helpers/constants.py +++ b/blinkpy/helpers/constants.py @@ -20,7 +20,7 @@ """ OTHER """ - +APP_BUILD = "ANDROID_28373244" DEFAULT_USER_AGENT = "27.0ANDROID_28373244" DEVICE_ID = "Blinkpy" TIMESTAMP_FORMAT = "%Y-%m-%dT%H:%M:%S%z" diff --git a/blinkpy/sync_module.py b/blinkpy/sync_module.py index 44f96a60..860b79da 100644 --- a/blinkpy/sync_module.py +++ b/blinkpy/sync_module.py @@ -34,7 +34,7 @@ def __init__(self, blink, network_name, network_id, camera_list): self.region_id = blink.auth.region_id self.name = network_name self.serial = None - self.version = None + self._version = None self.status = "offline" self.sync_id = None self.host = None @@ -73,7 +73,7 @@ def attributes(self): "id": self.sync_id, "network_id": self.network_id, "serial": self.serial, - "version": self.version, + "version": self._version, "status": self.status, "region_id": self.region_id, "local_storage": self.local_storage, @@ -95,6 +95,11 @@ def online(self): self.available = False return False + @property + def version(self): + """Return the Syncmodule Firmware version.""" + return self._version + @property def arm(self): """Return status of sync module: armed/disarmed.""" @@ -155,7 +160,7 @@ async def sync_initialize(self): "Could not retrieve sync module information with response: %s", response ) return False - self.version = self.summary.get("fw_version") + self._version = self.summary.get("fw_version") return response async def _init_local_storage(self, sync_id): @@ -496,14 +501,14 @@ async def poll_local_storage_manifest( response = await api.request_local_storage_manifest( self.blink, self.network_id, self.sync_id ) - if "id" in response: + if response and "id" in response: break # Get the manifest. else: response = await api.get_local_storage_manifest( self.blink, self.network_id, self.sync_id, manifest_request_id ) - if "clips" in response: + if response and "clips" in response: break seconds = backoff_seconds(retry=retry, default_time=3) _LOGGER.debug("[retry=%d] Retrying in %d seconds", retry + 1, seconds) diff --git a/pyproject.toml b/pyproject.toml index 0c703e76..3accbc43 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "blinkpy" -version = "0.22.5" +version = "0.22.6" license = {text = "MIT"} description = "A Blink camera Python Library." readme = "README.rst" diff --git a/requirements_test.txt b/requirements_test.txt index 3ec2cc31..d03c3dbb 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,4 +1,4 @@ -ruff==0.1.11 +ruff==0.1.14 black==23.12.1 build==1.0.3 coverage==7.4.0 diff --git a/tests/test_auth.py b/tests/test_auth.py index 31a9bda5..0d6168e9 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -132,9 +132,10 @@ def test_header(self): """Test header data.""" self.auth.token = "bar" expected_header = { + "APP-BUILD": const.APP_BUILD, "TOKEN_AUTH": "bar", - "user-agent": const.DEFAULT_USER_AGENT, - "content-type": "application/json", + "User-Agent": const.DEFAULT_USER_AGENT, + "Content-Type": "application/json", } self.assertDictEqual(self.auth.header, expected_header) diff --git a/tests/test_camera_functions.py b/tests/test_camera_functions.py index e01aafca..f2a353ef 100644 --- a/tests/test_camera_functions.py +++ b/tests/test_camera_functions.py @@ -22,8 +22,7 @@ "serial": "12345678", "enabled": False, "battery_state": "ok", - "temperature": 68, - "signals": {"lfr": 5, "wifi": 4, "battery": 3}, + "signals": {"lfr": 5, "wifi": 4, "battery": 3, "temp": 68}, "thumbnail": "/thumb", } diff --git a/tests/test_cameras.py b/tests/test_cameras.py index 25f68489..678301d0 100644 --- a/tests/test_cameras.py +++ b/tests/test_cameras.py @@ -89,10 +89,13 @@ def test_missing_attributes(self, mock_resp): """Test that attributes return None if missing.""" self.camera.temperature = None self.camera.serial = None + self.camera._version = None attr = self.camera.attributes self.assertEqual(attr["serial"], None) self.assertEqual(attr["temperature"], None) self.assertEqual(attr["temperature_c"], None) + self.assertEqual(attr["version"], None) + self.assertEqual(self.camera.version, None) def test_mini_missing_attributes(self, mock_resp): """Test that attributes return None if missing.""" diff --git a/tests/test_sync_module.py b/tests/test_sync_module.py index b0fd81cb..0e41b12c 100644 --- a/tests/test_sync_module.py +++ b/tests/test_sync_module.py @@ -128,6 +128,7 @@ async def test_get_camera_info(self, mock_resp) -> None: self.assertEqual( await self.blink.sync["test"].get_camera_info("1234"), "foobar" ) + self.assertEqual(self.blink.sync["test"].version, None) async def test_get_camera_info_fail(self, mock_resp) -> None: """Test handling of failed get camera info function."""