Skip to content
Merged
Show file tree
Hide file tree
Changes from 31 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
88 changes: 87 additions & 1 deletion homeassistant/components/camera/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,29 @@
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.const import (ATTR_ENTITY_ID, 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

_LOGGER = logging.getLogger(__name__)

SERVICE_EN_MOTION = 'enable_motion_detection'
SERVICE_DISEN_MOTION = 'disable_motion_detection'
DOMAIN = 'camera'
DEPENDENCIES = ['http']
SCAN_INTERVAL = timedelta(seconds=30)
Expand All @@ -44,6 +50,24 @@
TOKEN_CHANGE_INTERVAL = timedelta(minutes=5)
_RND = SystemRandom()

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


def enable_motion_detection(hass, entity_id=None):
"""Enable Motion Detection."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
hass.async_add_job(hass.services.async_call(
DOMAIN, SERVICE_EN_MOTION, data))


def disable_motion_detection(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

"""Disable Motion Detection."""
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
hass.async_add_job(hass.services.async_call(
DOMAIN, SERVICE_DISEN_MOTION, data))


@asyncio.coroutine
def async_get_image(hass, entity_id, timeout=10):
Expand Down Expand Up @@ -93,6 +117,44 @@ 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:
if service.service == SERVICE_EN_MOTION:
yield from camera.async_enable_motion_detection()
elif service.service == SERVICE_DISEN_MOTION:
yield from camera.async_disable_motion_detection()

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_EN_MOTION, async_handle_camera_service,
descriptions.get(SERVICE_EN_MOTION), schema=CAMERA_SERVICE_SCHEMA)
hass.services.async_register(
DOMAIN, SERVICE_DISEN_MOTION, async_handle_camera_service,
descriptions.get(SERVICE_DISEN_MOTION), schema=CAMERA_SERVICE_SCHEMA)

return True


Expand Down Expand Up @@ -126,6 +188,11 @@ def brand(self):
"""Return the camera brand."""
return None

@property
def motion_detection_enabled(self):
"""Return the camera motion detection status."""
return None

@property
def model(self):
"""Return the camera model."""
Expand Down Expand Up @@ -202,6 +269,22 @@ def state(self):
else:
return STATE_IDLE

def enable_motion_detection(self):
"""Enable motion detection in the camera."""
raise NotImplementedError()

def async_enable_motion_detection(self):
"""Call the job and enable motion detection."""
return self.hass.async_add_job(self.enable_motion_detection)

def disable_motion_detection(self):
"""Disable motion detection in camera."""
raise NotImplementedError()

def async_disable_motion_detection(self):
"""Call the job and disable motion detection."""
return self.hass.async_add_job(self.disable_motion_detection)

@property
def state_attributes(self):
"""Return the camera state attributes."""
Expand All @@ -215,6 +298,9 @@ def state_attributes(self):
if self.brand:
attr['brand'] = self.brand

if self.motion_detection_enabled:
attr['motion_detection'] = self.motion_detection_enabled

return attr

@callback
Expand Down
35 changes: 31 additions & 4 deletions homeassistant/components/camera/arlo.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,19 @@

import voluptuous as vol

from homeassistant.components.arlo import DEFAULT_BRAND, DATA_ARLO
from homeassistant.components.camera import Camera, PLATFORM_SCHEMA
from homeassistant.components.ffmpeg import DATA_FFMPEG
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.aiohttp_client import async_aiohttp_proxy_stream
from homeassistant.components.arlo import DEFAULT_BRAND
from homeassistant.components.camera import Camera, PLATFORM_SCHEMA
from homeassistant.components.ffmpeg import DATA_FFMPEG

DEPENDENCIES = ['arlo', 'ffmpeg']

_LOGGER = logging.getLogger(__name__)

CONF_FFMPEG_ARGUMENTS = 'ffmpeg_arguments'
ARLO_MODE_ARMED = 'armed'
ARLO_MODE_DISARMED = 'disarmed'

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_FFMPEG_ARGUMENTS): cv.string,
Expand All @@ -46,9 +48,10 @@ class ArloCam(Camera):
def __init__(self, hass, camera, device_info):
"""Initialize an Arlo camera."""
super().__init__()

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

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

@property
def should_poll(self):
"""Camera should poll periodically."""
return True

@property
def motion_detection_enabled(self):
"""Camera Motion Detection Status."""
return self._motion_status

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.

This should return a boolean.

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.

ok, i will change this code to return a boolean and post for PR


def set_base_station_mode(self, mode):
"""Set the mode in the base station."""
self._base_stn.mode = mode

def enable_motion_detection(self):
"""Enable the Motion detection in base station (Arm)."""
self._motion_status = True
self.set_base_station_mode(ARLO_MODE_ARMED)

def disable_motion_detection(self):
"""Disable the motion detection in base station (Disarm)."""
self._motion_status = False
self.set_base_station_mode(ARLO_MODE_DISARMED)
28 changes: 25 additions & 3 deletions homeassistant/components/camera/demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,29 @@
https://home-assistant.io/components/demo/
"""
import os

import logging
import homeassistant.util.dt as dt_util
from homeassistant.components.camera import Camera

_LOGGER = logging.getLogger(__name__)


def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the Demo camera platform."""
add_devices([
DemoCamera('Demo camera')
DemoCamera(hass, config, 'Demo camera')
])


class DemoCamera(Camera):
"""The representation of a Demo camera."""

def __init__(self, name):
def __init__(self, hass, config, name):
"""Initialize demo camera component."""
super().__init__()
self._parent = hass
self._name = name
self._motion_status = False

def camera_image(self):
"""Return a faked still image response."""
Expand All @@ -38,3 +42,21 @@ def camera_image(self):
def name(self):
"""Return the name of this camera."""
return self._name

@property
def should_poll(self):
"""Camera should poll periodically."""
return True

@property
def motion_detection_enabled(self):
"""Camera Motion Detection Status."""
return self._motion_status

def enable_motion_detection(self):
"""Enable the Motion detection in base station (Arm)."""
self._motion_status = True

def disable_motion_detection(self):
"""Disable the motion detection in base station (Disarm)."""
self._motion_status = False
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

enable_motion_detection:
description: Enable the motion detection in a camera

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

disable_motion_detection:
description: Disable the motion detection in a camera

fields:
entity_id:
description: Name(s) of entities to disable motion detection
example: 'camera.living_room_camera'
27 changes: 27 additions & 0 deletions tests/components/camera/test_demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"""The tests for local file camera component."""
import asyncio
from homeassistant.components import camera
from homeassistant.setup import async_setup_component


@asyncio.coroutine

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 test_motion_detection(hass):
"""Test motion detection services."""
# Setup platform
yield from async_setup_component(hass, 'camera', {
'camera': {
'platform': 'demo'
}
})

# Fetch state and check motion detection attribute
state = hass.states.get('camera.demo_camera')
assert not state.attributes.get('motion_detection')

# Call service to turn on motion detection
camera.enable_motion_detection(hass, 'camera.demo_camera')
yield from hass.async_block_till_done()

# Check if state has been updated.
state = hass.states.get('camera.demo_camera')
assert state.attributes.get('motion_detection')