Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions abodepy/devices/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
2 changes: 2 additions & 0 deletions abodepy/helpers/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -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/'
Expand Down
4 changes: 4 additions & 0 deletions abodepy/helpers/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.")

Expand Down Expand Up @@ -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.")
4 changes: 2 additions & 2 deletions tests/mock/devices/ipcam.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 '''
{
Expand Down Expand Up @@ -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",
Expand Down
33 changes: 32 additions & 1 deletion tests/test_camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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"
Expand Down Expand Up @@ -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)