From c2c744ce5b74bbe5b4665dd65edd8179104f1421 Mon Sep 17 00:00:00 2001 From: Marcus Noble Date: Sat, 15 Oct 2022 13:11:45 +0100 Subject: [PATCH] Support multiple motion entites per camera (#50) * Support multiple motion entites per camera Signed-off-by: Marcus Noble * Added some safety checks around missing entities. * fix for no motion entity * fix check Signed-off-by: Marcus Noble Co-authored-by: Blake Niemyjski --- README.md | 26 ++++++++++++++++++++++++-- surveillance-card.js | 25 ++++++++++++++----------- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index ec31731..0ebd24e 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Each entry in the camera list takes the following options | Name | Type | Description | Default | ---- | ---- | ----------- | ------- -| entity | string | Camera entity_id | **Required** +| entity | string or array | Camera entity_id | **Required** | motion_entity | string | entity_id of a binary sensor to use for motion detection (_uses state=='on' as motion detected_) | none --- @@ -81,7 +81,29 @@ Clicking the _record button_ will grab as many images as it can (based on the up Note: This functionality is not available in native app versions (iOS & Android) and depends on the browser/device's ability to download image files. ---- +## Motion entities + +Cameras can automatically be set to foccussed when motion is detected from the associated motion entities. + +`motion_entity` can either be a single entity ID or a list of multiple entity IDs. + +Note: The entities don't necessarily need to be motion sensors, they just need to be a binary sensor that is triggered when in the "on" state. E.g. a door sensor could also be used. + +```yaml +views: + - title: Surveillance + icon: mdi:cctv + cards: + - type: custom:surveillance-card + cameras: + - entity: camera.front_porch + motion_entity: binary_sensor.front_porch_motion + - entity: camera.back_yard + motion_entity: + - binary_sensor.back_yard_motion + - binary_sensor.back_yard_gate + +``` ## Thanks diff --git a/surveillance-card.js b/surveillance-card.js index d47b8c0..78c2081 100644 --- a/surveillance-card.js +++ b/surveillance-card.js @@ -114,18 +114,21 @@ class SurveillanceCard extends LitElement { const now = Date.now(); this.cameras = config.cameras.map((camera) => { - const entity = this.hass && hass.states[camera.entity]; - const attributes = entity && entity.attributes; + const { states } = this.hass || {}; + const entity = states[camera.entity]; + const attributes = entity?.attributes; + const motionEntities = Array.isArray(camera.motion_entity) ? camera.motion_entity : [camera.motion_entity].filter(entityId => !!entityId); + return { - access_token: attributes && attributes.access_token, + access_token: attributes?.access_token, entity: camera.entity, - motion_entity: camera.motion_entity, - name: attributes && attributes.friendly_name, - has_motion: this.hass && this.hass.states[camera.motion_entity].state === "on", + motion_entities: motionEntities, + name: attributes?.friendly_name, + has_motion: motionEntities.some(entityId => states[entityId]?.state === "on"), last_motion: now, last_update: now, stream_url: "", - url: attributes && attributes.entity_picture, + url: attributes?.entity_picture, }; }); this.updateCameras = this.throttle(() => this._updateCameras(), this.thumbInterval); @@ -134,13 +137,13 @@ class SurveillanceCard extends LitElement { _updateCameras() { const now = Date.now(); - const { states } = this.hass; + const { states } = this.hass || {}; const activatedCameras = []; for (const camera of this.cameras) { const hadMotion = camera.has_motion === true; - const { motion_entity } = camera; - camera.has_motion = motion_entity in states && states[motion_entity].state === "on"; + const { motion_entities } = camera; + camera.has_motion = motion_entities.some(entityId => states[entityId]?.state === "on"); if (camera.has_motion) { camera.last_motion = now; } @@ -155,7 +158,7 @@ class SurveillanceCard extends LitElement { camera.last_update = now; } - const attributes = camera.entity in states ? states[camera.entity].attributes || {} : {}; + const attributes = states[camera.entity]?.attributes || {}; camera.access_token = attributes.access_token; camera.name = attributes.friendly_name; camera.url = `${attributes.entity_picture}&last_update=${camera.last_update}`;