Skip to content

Commit

Permalink
entities translation support (#184)
Browse files Browse the repository at this point in the history
* entities translation support

* hassfest fix

* title case for english entities
  • Loading branch information
maciej-or authored Jul 11, 2024
1 parent 4cf4791 commit 49529a1
Show file tree
Hide file tree
Showing 9 changed files with 271 additions and 35 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ The Home Assistant integration for Hikvision NVRs and IP cameras. Receives and s
- Switches for NVR Outputs
- Holiday mode switch (allows to switch continuous recording with appropriate NVR setup)
- Tracking HDD and NAS status
- Tracking Alarm Server settings for diagnostic purposes
- Tracking Notifications Host settings for diagnostic purposes
- Basic and digest authentication support

### Supported events
Expand Down Expand Up @@ -66,7 +66,7 @@ The scope supported features depends on device model, setup and firmware version
- Regions if needed
- Arming Schedule
- Storage Schedule Settings - set continuous recording in Holiday mode for desired cameras
- Alarm Server - IP address of Home Assistant instance for event notifications. Can be set manually or by this integration if checked `Set alarm server` checkbox in the configuration dialog. It will be reverted to `http://0.0.0.0:80/` on integration unload.
- Notifications Host - IP address of Home Assistant instance for event notifications. Can be set manually or by this integration if checked `Set Notifications Host` checkbox in the configuration dialog. It will be reverted to `http://0.0.0.0:80/` on integration unload.

## Reporting issues

Expand Down Expand Up @@ -99,6 +99,7 @@ Download logs from `Settings / System / Logs`
- DS-7608NXI-K1/8P
- DS-7616NI-E2/16P
- DS-7616NI-I2/16P
- DS-7616NI-Q2/16P
- DS-7616NXI-I2/16P/S
- DS-7716NI-I4/16P
- ERI-K104-P4
Expand Down
6 changes: 4 additions & 2 deletions custom_components/hikvision_next/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from .const import DATA_ISAPI, DOMAIN, EVENTS
from .const import DATA_ISAPI, DOMAIN, EVENTS, EVENT_IO
from .isapi import EventInfo


Expand Down Expand Up @@ -42,6 +42,8 @@ def __init__(self, isapi, device_id: int, event: EventInfo) -> None:
"""Initialize."""
self.entity_id = ENTITY_ID_FORMAT.format(event.unique_id)
self._attr_unique_id = self.entity_id
self._attr_name = f"{EVENTS[event.id]['label']}{' ' + str(event.io_port_id) if event.io_port_id != 0 else ''}"
self._attr_translation_key = event.id
if event.id == EVENT_IO:
self._attr_translation_placeholders = {"io_port_id": event.io_port_id}
self._attr_device_class = EVENTS[event.id]["device_class"]
self._attr_device_info = isapi.hass_device_info(device_id)
12 changes: 10 additions & 2 deletions custom_components/hikvision_next/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,16 @@ def __init__(
Camera.__init__(self)

self._attr_device_info = isapi.hass_device_info(camera.id)
self._attr_name = f"{camera.name} {stream_info.type}"
self._attr_unique_id = slugify(f"{isapi.device_info.serial_no.lower()}_{stream_info.id}")
self._attr_unique_id = slugify(
f"{isapi.device_info.serial_no.lower()}_{stream_info.id}"
)
if stream_info.type_id > 1:
self._attr_has_entity_name = True
self._attr_translation_key = f"stream{stream_info.type_id}"
self._attr_entity_registry_enabled_default = False
else:
# for the main stream use just its name
self._attr_name = camera.name
self.entity_id = f"camera.{self.unique_id}"
self.isapi = isapi
self.stream_info = stream_info
Expand Down
8 changes: 2 additions & 6 deletions custom_components/hikvision_next/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@
SECONDARY_COORDINATOR: Final = "secondary"
HOLIDAY_MODE = "holiday_mode"

EVENT_SWITCH_LABEL_FORMAT = "{} Detection"
HOLIDAY_MODE_SWITCH_LABEL = "Holiday mode"
ALARM_SERVER_SENSOR_LABEL_FORMAT = "Alarm Server {}"

CONNECTION_TYPE_DIRECT = "Direct"
CONNECTION_TYPE_PROXIED = "Proxied"

Expand Down Expand Up @@ -85,8 +81,8 @@
"slug": "inputs",
"direct_node": "IOInputPort",
"proxied_node": "IOProxyInputPort",
"device_class": BinarySensorDeviceClass.MOTION
}
"device_class": BinarySensorDeviceClass.MOTION,
},
}

EVENTS_ALTERNATE_ID = {
Expand Down
19 changes: 10 additions & 9 deletions custom_components/hikvision_next/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,18 @@
from homeassistant.helpers.update_coordinator import CoordinatorEntity

from .const import (
ALARM_SERVER_SENSOR_LABEL_FORMAT,
DATA_ALARM_SERVER_HOST,
DOMAIN,
EVENTS_COORDINATOR,
SECONDARY_COORDINATOR,
)
from .isapi import StorageInfo

ALARM_SERVER_SETTINGS = {
"protocolType": "Protocol",
"ipAddress": "IP",
"portNo": "Port",
"url": "Path",
NOTIFICATION_HOST_KEYS = {
"protocolType": "protocol_type",
"ipAddress": "ip_address",
"portNo": "port_no",
"url": "url",
}


Expand All @@ -38,7 +37,7 @@ async def async_setup_entry(

entities = []
if coordinator:
for key in ALARM_SERVER_SETTINGS:
for key in NOTIFICATION_HOST_KEYS:
entities.append(AlarmServerSensor(coordinator, key))

events_coordinator = config.get(EVENTS_COORDINATOR)
Expand All @@ -60,10 +59,12 @@ def __init__(self, coordinator, key: str) -> None:
"""Initialize."""
super().__init__(coordinator)
isapi = coordinator.isapi
self._attr_unique_id = f"{isapi.device_info.serial_no}_{DATA_ALARM_SERVER_HOST}_{key}"
self._attr_unique_id = (
f"{isapi.device_info.serial_no}_{DATA_ALARM_SERVER_HOST}_{key}"
)
self.entity_id = ENTITY_ID_FORMAT.format(self.unique_id)
self._attr_device_info = isapi.hass_device_info()
self._attr_name = ALARM_SERVER_SENSOR_LABEL_FORMAT.format(ALARM_SERVER_SETTINGS[key])
self._attr_translation_key = f"notifications_host_{NOTIFICATION_HOST_KEYS[key]}"
self.key = key

@property
Expand Down
19 changes: 10 additions & 9 deletions custom_components/hikvision_next/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,10 @@

from .const import (
DOMAIN,
EVENT_SWITCH_LABEL_FORMAT,
EVENTS,
EVENTS_COORDINATOR,
HOLIDAY_MODE,
HOLIDAY_MODE_SWITCH_LABEL,
SECONDARY_COORDINATOR,
EVENT_IO,
)
from .isapi import EventInfo

Expand Down Expand Up @@ -65,9 +63,9 @@ def __init__(self, device_id: int, event: EventInfo, coordinator) -> None:
self.entity_id = ENTITY_ID_FORMAT.format(event.unique_id)
self._attr_unique_id = self.entity_id
self._attr_device_info = coordinator.isapi.hass_device_info(device_id)
self._attr_name = EVENT_SWITCH_LABEL_FORMAT.format(
f"{EVENTS[event.id]['label']}{' ' + str(event.io_port_id) if event.io_port_id != 0 else ''}"
)
self._attr_translation_key = event.id
if event.id == EVENT_IO:
self._attr_translation_placeholders = {"io_port_id": event.io_port_id}
self.device_id = device_id
self.event = event

Expand Down Expand Up @@ -107,6 +105,7 @@ class NVROutputSwitch(CoordinatorEntity, SwitchEntity):

_attr_has_entity_name = True
_attr_icon = "mdi:eye-outline"
_attr_translation_key = "alarm_output"

def __init__(self, coordinator, port_no: int) -> None:
"""Initialize."""
Expand All @@ -116,7 +115,7 @@ def __init__(self, coordinator, port_no: int) -> None:
)
self._attr_unique_id = self.entity_id
self._attr_device_info = coordinator.isapi.hass_device_info(0)
self._attr_name = f"Alarm Output {port_no}"
self._attr_translation_placeholders = {"port_no": port_no}
self._port_no = port_no

@property
Expand Down Expand Up @@ -147,14 +146,16 @@ class HolidaySwitch(CoordinatorEntity, SwitchEntity):

_attr_has_entity_name = True
_attr_icon = "mdi:palm-tree"
_attr_translation_key = HOLIDAY_MODE

def __init__(self, coordinator) -> None:
"""Initialize."""
super().__init__(coordinator)
self._attr_unique_id = f"{slugify(coordinator.isapi.device_info.serial_no.lower())}_{HOLIDAY_MODE}"
self._attr_unique_id = (
f"{slugify(coordinator.isapi.device_info.serial_no.lower())}_{HOLIDAY_MODE}"
)
self.entity_id = ENTITY_ID_FORMAT.format(self.unique_id)
self._attr_device_info = coordinator.isapi.hass_device_info()
self._attr_name = HOLIDAY_MODE_SWITCH_LABEL

@property
def is_on(self) -> bool | None:
Expand Down
96 changes: 95 additions & 1 deletion custom_components/hikvision_next/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"host": "URL",
"password": "Password",
"username": "Username",
"set_alarm_server": "Set alarm server using following address:",
"set_alarm_server": "Set notifications host using following address:",
"alarm_server": "Home Assistant address accessible by Hikvison device"
}
}
Expand All @@ -21,5 +21,99 @@
"insufficient_permission": "Access forbidden, check user permissions",
"unknown": "Unexpected error"
}
},
"entity": {
"binary_sensor": {
"motiondetection": {
"name": "Motion"
},
"tamperdetection": {
"name": "Video Tampering"
},
"videoloss": {
"name": "Video Loss"
},
"scenechangedetection": {
"name": "Scene Change"
},
"fielddetection": {
"name": "Intrusion"
},
"linedetection": {
"name": "Line Crossing"
},
"regionentrance": {
"name": "Region Entrance"
},
"regionexiting": {
"name": "Region Exiting"
},
"io": {
"name": "Alarm Input {io_port_id}"
}
},
"switch": {
"alarm_output": {
"name": "Alarm Output {port_no}"
},
"holiday_mode": {
"name": "Holiday Mode"
},
"motiondetection": {
"name": "Motion Detection"
},
"tamperdetection": {
"name": "Video Tampering Detection"
},
"videoloss": {
"name": "Video Loss Detection"
},
"scenechangedetection": {
"name": "Scene Change Detection"
},
"fielddetection": {
"name": "Intrusion Detection"
},
"linedetection": {
"name": "Line Crossing Detection"
},
"regionentrance": {
"name": "Region Entrance Detection"
},
"regionexiting": {
"name": "Region Exiting Detection"
},
"io": {
"name": "Alarm Input {io_port_id}"
}
},
"camera": {
"stream1": {
"name": "Main Stream"
},
"stream2": {
"name": "Sub-Stream"
},
"stream3": {
"name": "Main Stream (Event)"
},
"stream4": {
"name": "Transcoded Stream"
}
},
"sensor": {
"notifications_host_protocol_type": {
"name": "Notifications Host Protocol"
},
"notifications_host_ip_address": {
"name": "Notifications Host IP"
},
"notifications_host_port_no": {
"name": "Notifications Host Port"
},
"notifications_host_url": {
"name": "Notifications Host Path"
}
}
}
}
Loading

0 comments on commit 49529a1

Please sign in to comment.