diff --git a/abodepy/devices/camera.py b/abodepy/devices/camera.py index a4bbe6b..dd0fff3 100644 --- a/abodepy/devices/camera.py +++ b/abodepy/devices/camera.py @@ -115,7 +115,44 @@ def image_to_file(self, path, get_image=True): return True + def privacy_mode(self, enable): + """Set camera privacy mode (camera on/off).""" + if self._json_state['privacy']: + privacy = '0' if enable else '1' + + url = CONST.PARAMS_URL + self.device_id + + camera_data = { + 'mac': self._json_state['camera_mac'], + 'privacy': privacy, + 'action': 'setParam', + 'id': self.device_id + } + + response = self._abode.send_request( + method="put", url=url, data=camera_data) + response_object = json.loads(response.text) + + _LOGGER.debug("Camera Privacy Mode Response: %s", response.text) + + if response_object['id'] != self.device_id: + raise AbodeException((ERROR.SET_STATUS_DEV_ID)) + + if response_object['privacy'] != str(privacy): + raise AbodeException((ERROR.SET_PRIVACY_MODE)) + + _LOGGER.info("Set camera %s privacy mode to: %s", self.device_id, privacy) + + return True + + return False + @property def image_url(self): """Get image URL.""" return self._image_url + + @property + def is_on(self): + """Get camera state (assumed on).""" + return self.status not in (CONST.STATUS_OFF, CONST.STATUS_OFFLINE) diff --git a/abodepy/helpers/constants.py b/abodepy/helpers/constants.py index 2b45fa1..4bb6d30 100644 --- a/abodepy/helpers/constants.py +++ b/abodepy/helpers/constants.py @@ -53,6 +53,8 @@ OAUTH_TOKEN_URL = BASE_URL + 'api/auth2/claims' +PARAMS_URL = BASE_URL + 'api/v1/devices_beta/' + PANEL_URL = BASE_URL + 'api/v1/panel' INTEGRATIONS_URL = BASE_URL + 'integrations/v1/devices/' diff --git a/abodepy/helpers/errors.py b/abodepy/helpers/errors.py index 70cfbc1..7816122 100644 --- a/abodepy/helpers/errors.py +++ b/abodepy/helpers/errors.py @@ -40,6 +40,7 @@ INVALID_AUTOMATION_EDIT_RESPONSE = ( 16, "Automation edit response did not match expected values.") +# DEPRECATED # TRIGGER_NON_QUICKACTION = ( # 17, "Can not trigger an automation that is not a manual quick-action.") @@ -81,3 +82,6 @@ MISSING_CONTROL_URL = ( 30, "Control URL does not exist in device JSON.") + +SET_PRIVACY_MODE = ( + 31, "Device privacy mode value does not match request value.") diff --git a/tests/mock/devices/ipcam.py b/tests/mock/devices/ipcam.py index acd3dde..4ede256 100644 --- a/tests/mock/devices/ipcam.py +++ b/tests/mock/devices/ipcam.py @@ -7,7 +7,7 @@ def device(devid=DEVICE_ID, status=CONST.STATUS_ONLINE, - low_battery=False, no_response=False): + low_battery=False, no_response=False, privacy=1): """IP camera mock device.""" return ''' { @@ -88,7 +88,7 @@ def device(devid=DEVICE_ID, status=CONST.STATUS_ONLINE, "is_new_camera": 1, "stream_quality": 3, "camera_mac": "AB:CD:EF:GF:HI", - "privacy": "1", + "privacy":"''' + str(privacy) + '''", "enable_audio": "1", "alarm_video": "25", "pre_alarm_video": "5", diff --git a/tests/test_camera.py b/tests/test_camera.py index e7b22a0..a0a7766 100644 --- a/tests/test_camera.py +++ b/tests/test_camera.py @@ -5,6 +5,7 @@ import requests_mock import abodepy +from abodepy.exceptions import AbodeException import abodepy.helpers.constants as CONST import abodepy.helpers.errors as ERROR import tests.mock as MOCK @@ -14,7 +15,6 @@ import tests.mock.logout as LOGOUT import tests.mock.oauth_claims as OAUTH_CLAIMS import tests.mock.panel as PANEL -from abodepy.exceptions import AbodeException USERNAME = "foobar" PASSWORD = "deadbeef" @@ -343,3 +343,34 @@ def tests_camera_image_write(self, m): # Test that the image fails to update returns False m.get(url, text="[]") self.assertFalse(device.image_to_file(path, get_image=True)) + + def tests_camera_privacy_mode(self, m): + """Tests camera privacy mode.""" + # Set up mock URLs + m.post(CONST.LOGIN_URL, text=LOGIN.post_response_ok()) + m.get(CONST.OAUTH_TOKEN_URL, text=OAUTH_CLAIMS.get_response_ok()) + m.post(CONST.LOGOUT_URL, text=LOGOUT.post_response_ok()) + m.get(CONST.PANEL_URL, + text=PANEL.get_response_ok(mode=CONST.MODE_STANDBY)) + m.get(CONST.DEVICES_URL, text=self.all_devices) + + # Get the IP camera and test we have it + device = self.abode.get_device(IPCAM.DEVICE_ID) + self.assertIsNotNone(device) + self.assertEqual(device.status, CONST.STATUS_ONLINE) + + # Set up params URL response for privacy mode on + m.put(CONST.PARAMS_URL + device.device_id, text=IPCAM.device(privacy=0)) + + # Set privacy mode on + self.assertTrue(device.privacy_mode(True)) + + # Set up params URL response for privacy mode off + m.put(CONST.PARAMS_URL + device.device_id, text=IPCAM.device(privacy=1)) + + # Set privacy mode off + self.assertTrue(device.privacy_mode(False)) + + # Test that an invalid privacy response throws exception + with self.assertRaises(abodepy.AbodeException): + device.privacy_mode(True)