Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
705205b
Added camera service calls to arm/disarm the cameras. Entity id is op…
viswa-swami Jun 8, 2017
1ef7055
Added camera service calls to arm/disarm the cameras. Entity id is op…
viswa-swami Jun 8, 2017
8669c7f
Added camera service calls to arm/disarm the cameras. Entity id is op…
viswa-swami Jun 8, 2017
e6deae2
Fixed the spaces and indentation related issues that houndci found
viswa-swami Jun 8, 2017
eb11fd8
Fixed the spaces and indentation related issues that houndci found
viswa-swami Jun 8, 2017
70808e5
Missed the const file which has the macros defined.
viswa-swami Jun 8, 2017
c4a91c9
Fixed the CI build error
viswa-swami Jun 8, 2017
e2c0113
Fixed the CI build error because of unused variable in exception case
viswa-swami Jun 8, 2017
c1a8382
Updating the arlo code based on comment from @balloob. Changed the ar…
viswa-swami Jun 16, 2017
2775c0e
Fixed the comments posted by houndci-bot
viswa-swami Jun 16, 2017
4b1f36f
Fixed the comments posted by houndci-bot
viswa-swami Jun 16, 2017
49438bb
Fixed the comments posted by houndci-bot
viswa-swami Jun 16, 2017
7f8e914
Fixed the comments posted by travis-ci integration bot
viswa-swami Jun 16, 2017
53dc772
Fixed the comments posted by travis-ci integration bot
viswa-swami Jun 16, 2017
890d7f1
Fixed the comments posted by travis-ci integration bot for demo.py: e…
viswa-swami Jun 16, 2017
7e477a2
Updated code in camera __init__.py to use the get function instead of…
viswa-swami Jun 16, 2017
285d9b4
Updated code in camera __init__.py
viswa-swami Jun 16, 2017
2e1208b
Posting the updated code for PR based on @balloob's suggestions/recom…
viswa-swami Jun 22, 2017
fe2d68e
Removed the arlo reference from demo code. Copy-paste error
viswa-swami Jun 22, 2017
282487d
Removed the unused import found by hound bot
viswa-swami Jun 22, 2017
a4e5cc1
Expected 2 lines before function, but found only 1.
viswa-swami Jun 23, 2017
60aaa52
Based on @balloob's comments, moved these constants to the camera/arl…
viswa-swami Jun 24, 2017
07b941c
Added test_demo.py to test the motion enabled and motion disabled in …
viswa-swami Jun 26, 2017
96f0ee7
Fixing issues found by houndci-bot
viswa-swami Jun 26, 2017
d304f2b
Fixing issues found by houndci-bot
viswa-swami Jun 26, 2017
baab606
Fixing the code as per @balloob's suggestions
viswa-swami Jun 27, 2017
27d9c28
Fixing the code as per @balloob's suggestions
viswa-swami Jun 27, 2017
5c95020
Fixing the test_demo failure. Tried to rewrite a base function to ena…
viswa-swami Jun 27, 2017
33362c9
Fixing the hound bot comment
viswa-swami Jun 27, 2017
6c97791
Merge branch 'dev' into arlo_services_arm_disarm
balloob Jun 30, 2017
488a71e
Update arlo.py
balloob Jun 30, 2017
19c3d62
Update arlo.py
balloob Jun 30, 2017
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
86 changes: 86 additions & 0 deletions homeassistant/components/camera/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,25 @@
import logging
import hashlib
from random import SystemRandom
import os

import aiohttp
from aiohttp import web
import async_timeout
import voluptuous as vol

from homeassistant.core import callback
from homeassistant.const import ATTR_ENTITY_PICTURE
from homeassistant.config import load_yaml_config_file
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.config_validation import PLATFORM_SCHEMA # noqa
from homeassistant.components.http import HomeAssistantView, KEY_AUTHENTICATED
from homeassistant.helpers.event import async_track_time_interval
import homeassistant.helpers.config_validation as cv
from homeassistant.const import (SERVICE_ARM, SERVICE_DISARM, ATTR_ENTITY_ID)

_LOGGER = logging.getLogger(__name__)

Expand All @@ -43,6 +48,33 @@
TOKEN_CHANGE_INTERVAL = timedelta(minutes=5)
_RND = SystemRandom()

CAMERA_SERVICE_SCHEMA = vol.Schema({
vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
})


def arm(hass, entity_id=None):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expected 2 blank lines, found 1

"""Arm all"""
hass.add_job(async_arm, hass, entity_id)


@callback

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expected 2 blank lines, found 1

def async_arm(hass, entity_id=None):
"""Arm all the cameras"""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
hass.async_add_job(hass.services.async_call(DOMAIN, SERVICE_ARM, data))

def disarm(hass, entity_id=None):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expected 2 blank lines, found 1

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expected 2 blank lines, found 1

"""Disarm all"""
hass.add_job(async_disarm, hass, entity_id)


@callback

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expected 2 blank lines, found 1

def async_disarm(hass, entity_id=None):
"""Disarm all the cameras"""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
hass.async_add_job(hass.services.async_call(DOMAIN, SERVICE_DISARM, data))


@asyncio.coroutine
def async_get_image(hass, entity_id, timeout=10):
Expand Down Expand Up @@ -92,6 +124,47 @@ def update_tokens(time):
hass.async_add_job(entity.async_update_ha_state())

async_track_time_interval(hass, update_tokens, TOKEN_CHANGE_INTERVAL)

@asyncio.coroutine
def async_handle_camera_service(service):
"""Handle calls to the camera services."""
target_cameras = component.async_extract_from_service(service)

for camera in target_cameras:
try:
if service.service == SERVICE_ARM:
yield from camera.async_arm()
elif service.service == SERVICE_DISARM:
yield from camera.async_disarm()
except AttributeError as e:
pass

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not just let this pass. We should also not try to update a camera that didn't had an attribute.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can check if the camera has that attribute using hasattr() and then call that if it has that attribute.


update_tasks = []
for camera in target_cameras:
if not camera.should_poll:
continue

update_coro = hass.async_add_job(
camera.async_update_ha_state(True))
if hasattr(camera, 'async_update'):
update_tasks.append(update_coro)
else:
yield from update_coro

if update_tasks:
yield from asyncio.wait(update_tasks, loop=hass.loop)

descriptions = yield from hass.async_add_job(
load_yaml_config_file, os.path.join(
os.path.dirname(__file__), 'services.yaml'))

hass.services.async_register(
DOMAIN, SERVICE_ARM, async_handle_camera_service,
descriptions.get(SERVICE_ARM), schema=CAMERA_SERVICE_SCHEMA)
hass.services.async_register(
DOMAIN, SERVICE_DISARM, async_handle_camera_service,
descriptions.get(SERVICE_DISARM), schema=CAMERA_SERVICE_SCHEMA)

return True


Expand Down Expand Up @@ -124,6 +197,16 @@ def brand(self):
"""Return the camera brand."""
return None

@property
def status(self):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why add something new if we already have state that does something similar?

"""Return the camera status."""
try:
status = self._status
except AttributeError as e:
status = None

return status

@property
def model(self):
"""Return the camera model."""
Expand Down Expand Up @@ -212,6 +295,9 @@ def state_attributes(self):
if self.brand:
attr['brand'] = self.brand

if self.status:
attr['status'] = self.status

return attr

@callback
Expand Down
25 changes: 23 additions & 2 deletions homeassistant/components/camera/arlo.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
cv.string,
})


@asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
"""Set up an Arlo IP Camera."""
Expand All @@ -40,6 +39,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
cameras.append(ArloCam(hass, camera, config))

async_add_devices(cameras, True)

return True


Expand All @@ -49,9 +49,11 @@ class ArloCam(Camera):
def __init__(self, hass, camera, device_info):
"""Initialize an Arlo camera."""
super().__init__()

self._parent = hass
self._camera = camera
self._base_stn = hass.data['arlo'].base_stations[0]
self._name = self._camera.name
self._status = "Disarmed"
self._ffmpeg = hass.data[DATA_FFMPEG]
self._ffmpeg_arguments = device_info.get(CONF_FFMPEG_ARGUMENTS)

Expand Down Expand Up @@ -90,3 +92,22 @@ def model(self):
def brand(self):
"""Camera brand."""
return DEFAULT_BRAND

@property
def status(self):
"""Camera Status."""
return self._status

@asyncio.coroutine
def async_arm(self):
"""Camera arm."""
self._base_stn.mode = "armed"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are not allowed to do I/O inside async methods.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any example as to how to handle I/O, if we cannot do it inside the async methods ?

self._status = "Armed"
self.hass.async_add_job(self.async_update_ha_state())

@asyncio.coroutine
def async_disarm(self):
"""Camera disarm."""
self._base_stn.mode = "disarmed"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any example as to how to handle I/O, if we cannot do it inside the async methods ?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

def set_mode(mode):
    self._base_stn.mode = mode

yield from hass.async_add_job(set_mode, "disarmed")

self._status = "Disarmed"
self.hass.async_add_job(self.async_update_ha_state())

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same, remove this.

17 changes: 17 additions & 0 deletions homeassistant/components/camera/services.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Describes the format for available camera services

arm:
description: Arm a camera with motion detection

fields:
entity_id:
description: Name(s) of entities to arm.
example: 'camera.living_room_camera'

disarm:
description: Disarm a camera disabling motion detection

fields:
entity_id:
description: Name(s) of entities to turn off
example: 'camera.living_room_camera'
15 changes: 15 additions & 0 deletions homeassistant/components/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -402,3 +402,18 @@ eight_sleep:
duration:
description: Duration to heat at the target level in seconds.
example: 3600

camera:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove these, as they are already present in camera/services.yaml.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

arm:
description: Arm a camera with motion detection
fields:
entity_id:
description: Name(s) of entities to arm.
example: 'camera.living_room_camera'

disarm:
description: Disarm a camera disabling motion detection
fields:
entity_id:
description: Name(s) of entities to turn off
example: 'camera.living_room_camera'