Skip to content

Commit

Permalink
image entities for snapshots
Browse files Browse the repository at this point in the history
  • Loading branch information
maciej-or committed Aug 9, 2024
1 parent 3e22da8 commit fe79c5c
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 7 deletions.
17 changes: 14 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ The Home Assistant integration for Hikvision NVRs and IP cameras. Receives and s
- Camera entities for main and sub streams
- Real-time Acusense events notifications through binary sensors and HA events (hikvision_next_event)
- Switches for Acusense events detection
- Switches for NVR Outputs
- Switches for NVR Outputs and PIR sensor
- Holiday mode switch (allows to switch continuous recording with appropriate NVR setup)
- Image entities for the latest snapshots
- Tracking HDD and NAS status
- Tracking Notifications Host settings for diagnostic purposes
- Basic and digest authentication support
Expand All @@ -26,10 +27,16 @@ The Home Assistant integration for Hikvision NVRs and IP cameras. Receives and s
- Region Entrance
- Region Exiting
- NVR Input Triggers
- PIR

**NOTE**
Events must be set to alert the surveillance center in Linkage Action for Home Assistant to be notified. Otherwise related binary sensors and switches will appear as disabled entities.

### Blueprints

Take Multiple Snapshots On Detection Event

[<img src="https://my.home-assistant.io/badges/blueprint_import.svg">](https://my.home-assistant.io/redirect/blueprint_import/?blueprint_url=https://github.com/maciej-or/hikvision_next/blob/main/blueprints/take_pictures_on_motion_detection.yaml)
## Preview

### IP Camera device view
Expand All @@ -42,6 +49,8 @@ The scope supported features depends on device model, setup and firmware version

## Installation

[<img src="https://my.home-assistant.io/badges/hacs_repository.svg">](https://my.home-assistant.io/redirect/hacs_repository/?owner=maciej-or&repository=hikvision_next&category=integration)

### With HACS

1. This integration you will find in the default HACS store. Search for `Hikvision NVR / IP Camera` on `HACS / Integrations` page and press `Download` button
Expand Down Expand Up @@ -93,17 +102,18 @@ Download logs from `Settings / System / Logs`

### NVR

- Annke N46PCK
- DS-7108NI-Q1/8P
- DS-7608NI-I2
- DS-7608NI-I2/8P
- DS-7608NXI-I2/8P/S
- DS-7608NXI-K1/8P
- DS-7616NI-E2/16P
- DS-7616NI-I2/16P
- DS-7616NI-Q2
- DS-7616NI-Q2/16P
- DS-7616NXI-I2/16P/S
- DS-7716NI-I4/16P
- Annke N46PCK
- ERI-K104-P4

### DVR
Expand All @@ -113,8 +123,10 @@ Download logs from `Settings / System / Logs`

### IP Camera

- Annke C800 (I91BM)
- DS-2CD2047G2-LU/SL
- DS-2CD2087G2-LU
- DS-2CD2146G2-ISU
- DS-2CD2155FWD-I
- DS-2CD2346G2-IU
- DS-2CD2386G2-IU
Expand All @@ -127,4 +139,3 @@ Download logs from `Settings / System / Logs`
- DS-2CD2T87G2-L
- DS-2CD2T87G2P-LSU/SL
- DS-2DE4425IW-DE (PTZ)
- Annke C800 (I91BM)
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,15 @@ action:
sequence:
- variables:
camera_entity: "{{ camera_entities[repeat.index - 1] }}"
snapshot_entity: "{{ camera_entities[repeat.index - 1] |regex_replace(find='camera', replace='image') }}_snapshot"
camera_name: "{{ states[camera_entity].name }}"
- service: camera.snapshot
data:
filename: /media/hikvision_next/snapshots/{{month}}/{{day}}/{{timestamp}}__{{camera_name}}.jpg
target:
entity_id: "{{ camera_entity }}"
- service: hikvision_next.update_snapshot
data:
filename: /media/hikvision_next/snapshots/{{month}}/{{day}}/{{timestamp}}__{{camera_name}}.jpg
target:
entity_id: "{{ snapshot_entity }}"
10 changes: 6 additions & 4 deletions custom_components/hikvision_next/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@

from httpx import TimeoutException

from homeassistant.components.binary_sensor import (
ENTITY_ID_FORMAT as BINARY_SENSOR_ENTITY_ID_FORMAT,
)
from homeassistant.components.switch import ENTITY_ID_FORMAT as SWITCH_ENTITY_ID_FORMAT
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers import entity_registry as er
from homeassistant.components.switch import ENTITY_ID_FORMAT as SWITCH_ENTITY_ID_FORMAT
from homeassistant.components.binary_sensor import ENTITY_ID_FORMAT as BINARY_SENSOR_ENTITY_ID_FORMAT
from homeassistant.helpers import device_registry as dr, entity_registry as er

from .const import (
ALARM_SERVER_PATH,
Expand All @@ -37,6 +38,7 @@
Platform.CAMERA,
Platform.SENSOR,
Platform.SWITCH,
Platform.IMAGE,
]


Expand Down
89 changes: 89 additions & 0 deletions custom_components/hikvision_next/image.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
"""Image entities with camera snapshots."""

from datetime import datetime
import logging

import voluptuous as vol

from homeassistant.components.camera import Camera
from homeassistant.components.image import ImageEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_ENTITY_ID, CONF_FILENAME
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_validation as cv, entity_platform
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.template import Template
from homeassistant.util import slugify

from .const import DATA_ISAPI, DOMAIN
from .isapi import ISAPI, CameraStreamInfo

_LOGGER = logging.getLogger(__name__)


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback) -> None:
"""Add images with snapshots."""

config = hass.data[DOMAIN][entry.entry_id]
isapi: ISAPI = config[DATA_ISAPI]

entities = []
for camera in isapi.cameras:
for stream in camera.streams:
if stream.type_id == 1:
entities.append(SnapshotFile(hass, isapi, camera, stream))

async_add_entities(entities)

platform = entity_platform.async_get_current_platform()
platform.async_register_entity_service(
"update_snapshot",
{vol.Required(CONF_FILENAME): cv.template},
"update_snapshot_filename",
)


class SnapshotFile(ImageEntity):
"""An entity for displaying snapshot files."""

_attr_has_entity_name = True
file_path = None

def __init__(
self,
hass: HomeAssistant,
isapi: ISAPI,
camera: Camera,
stream_info: CameraStreamInfo,
) -> None:
"""Initialize the snapshot file."""

ImageEntity.__init__(self, hass)

self._attr_unique_id = slugify(f"{isapi.device_info.serial_no.lower()}_{stream_info.id}_snapshot")
self.entity_id = f"camera.{self.unique_id}"
self._attr_translation_key = "snapshot"
self._attr_translation_placeholders = {"camera": camera.name}

def image(self) -> bytes | None:
"""Return bytes of image."""
try:
if self.file_path:
with open(self.file_path, "rb") as file:
return file.read()
except FileNotFoundError:
_LOGGER.warning(
"Could not read camera %s image from file: %s",
self.name,
self.file_path,
)
return None

async def update_snapshot_filename(
self,
filename: Template,
) -> None:
"""Update the file_path."""
self.file_path = filename.async_render(variables={ATTR_ENTITY_ID: self.entity_id})
self._attr_image_last_updated = datetime.now()
self.schedule_update_ha_state()
14 changes: 14 additions & 0 deletions custom_components/hikvision_next/services.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
update_snapshot:
name: Update snapshot
target:
entity:
domain: image
integration: hikvision_next
fields:
filename:
required: true
name: Filename
description: The filename of the snapshot to display.
example: "/media/hikvision_next/snapshots/2024-08/07/2024-08-07__11-54-19__camera01.jpg"
selector:
text:
5 changes: 5 additions & 0 deletions custom_components/hikvision_next/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@
"notifications_host_url": {
"name": "Notifications Host Path"
}
},
"image": {
"snapshot": {
"name": "{camera} Snapshot"
}
}
}
}
5 changes: 5 additions & 0 deletions custom_components/hikvision_next/translations/pl.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@
"notifications_host_url": {
"name": "Host powiadomień ścieżka"
}
},
"image": {
"snapshot": {
"name": "{camera} zdjęcie"
}
}
}
}

0 comments on commit fe79c5c

Please sign in to comment.