Skip to content

Commit

Permalink
Add support for cameras with multiple channels (thermal cameras, for …
Browse files Browse the repository at this point in the history
…example) (#241)

* Add support for multiple channels for single camera, for example thermal cameras

* Minor bug fix for channel name

* Map thermometry event to motiondetection

* fixed fixtures for Streaming/channels request

* Add separte thermometry event

* integration constants update

* back to mapping thermometry to motion event and test for notification

* test fix

---------

Co-authored-by: maciej-or <maciej.orlowski@scalac.io>
Co-authored-by: Maciej <38075949+maciej-or@users.noreply.github.com>
  • Loading branch information
3 people authored Nov 24, 2024
1 parent 366d114 commit c83426e
Show file tree
Hide file tree
Showing 16 changed files with 2,931 additions and 27 deletions.
2 changes: 1 addition & 1 deletion custom_components/hikvision_next/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: HikvisionConfigEntry) ->
except ISAPIUnauthorizedError as ex:
raise ConfigEntryAuthFailed from ex
except Exception as ex: # pylint: disable=broad-except
msg = f"Cannot initialize {DOMAIN} {device.host}. Error: {ex.message}\n"
msg = f"Cannot initialize {DOMAIN} {device.host}. Error: {ex}\n"
_LOGGER.error(msg + traceback.format_exc())
raise ConfigEntryNotReady(msg) from ex

Expand Down
1 change: 1 addition & 0 deletions custom_components/hikvision_next/diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ async def _async_get_diagnostics(
"Event/triggers",
"Event/triggers/scenechangedetection-1",
"Event/notification/httpHosts",
"Streaming/channels",
]

for endpoint in endpoints:
Expand Down
1 change: 1 addition & 0 deletions custom_components/hikvision_next/isapi/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@

EVENTS_ALTERNATE_ID = {
"vmd": "motiondetection",
"thermometry": "motiondetection",
"shelteralarm": "tamperdetection",
"VMDHumanVehicle": "motiondetection",
}
Expand Down
30 changes: 22 additions & 8 deletions custom_components/hikvision_next/isapi/isapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,20 +130,34 @@ async def get_cameras(self):
"""Get camera objects for all connected cameras."""

if not self.device_info.is_nvr:
# Get single IP camera
self.cameras.append(
IPCamera(
id=1,
name=self.device_info.name,
# Fetch the list of streaming channels (cameras), can be multiple for thermal cameras for example
streaming_channels = await self.request(GET, "Streaming/channels")
streaming_channel_list = deep_get(streaming_channels, "StreamingChannelList.StreamingChannel", [])

channel_ids = set()
for streaming_channel in streaming_channel_list:
channel_id = int(deep_get(streaming_channel, "Video.videoInputChannelID", 1))
channel_ids.add(channel_id)

for channel_id in sorted(channel_ids):
# Determine camera name
if len(channel_ids) > 1:
camera_name = f"{self.device_info.name} - Channel {channel_id}"
else:
camera_name = self.device_info.name

camera = IPCamera(
id=channel_id,
name=camera_name,
model=self.device_info.model,
serial_no=self.device_info.serial_no,
firmware=self.device_info.firmware,
input_port=1,
input_port=channel_id,
connection_type=CONNECTION_TYPE_DIRECT,
ip_addr=self.device_info.ip_address,
streams=await self.get_camera_streams(1),
streams=await self.get_camera_streams(channel_id),
)
)
self.cameras.append(camera)
else:
# Get analog and digital cameras attached to NVR
if self.capabilities.support_digital_cameras > 0:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<EventNotificationAlert>
<ipAddress>1.0.0.255</ipAddress>
<portNo>8123</portNo>
<protocol>HTTP</protocol>
<macAddress>a6:60:9e:f8:01:09</macAddress>
<dynChannelID>2</dynChannelID>
<channelID>2</channelID>
<dateTime>2024-11-13T20:20:52+01:00</dateTime>
<activePostCount>1</activePostCount>
<eventType>VMD</eventType>
<eventState>active</eventState>
<eventDescription>Motion alarm</eventDescription>
<channelName>Camera 02</channelName>
</EventNotificationAlert>
161 changes: 161 additions & 0 deletions tests/fixtures/devices/DS-2CD2146G2-ISU.json
Original file line number Diff line number Diff line change
Expand Up @@ -1767,6 +1767,167 @@
"isSupportTargetMultiSelect": "true"
}
}
},
"Streaming/channels": {
"response": {
"StreamingChannelList": {
"@version": "2.0",
"@xmlns": "http://www.hikvision.com/ver20/XMLSchema",
"StreamingChannel": [
{
"@version": "2.0",
"@xmlns": "http://www.hikvision.com/ver20/XMLSchema",
"id": "101",
"channelName": "yard",
"enabled": "true",
"Transport": {
"maxPacketSize": "1000",
"ControlProtocolList": {
"ControlProtocol": [
{
"streamingTransport": "RTSP"
},
{
"streamingTransport": "HTTP"
},
{
"streamingTransport": "SHTTP"
},
{
"streamingTransport": "SRTP"
}
]
},
"Unicast": {
"enabled": "true",
"rtpTransportType": "RTP/TCP"
},
"Multicast": {
"enabled": "true",
"destIPAddress": "0.0.0.0",
"videoDestPortNo": "8860"
},
"Security": {
"enabled": "true",
"certificateType": "digest",
"SecurityAlgorithm": {
"algorithmType": "MD5"
}
},
"SRTPMulticast": {
"SRTPVideoDestPortNo": "18860"
}
},
"Video": {
"enabled": "true",
"videoInputChannelID": "1",
"videoCodecType": "H.264",
"videoScanType": "progressive",
"videoResolutionWidth": "3840",
"videoResolutionHeight": "2160",
"videoQualityControlType": "VBR",
"constantBitRate": "12288",
"fixedQuality": "100",
"vbrUpperCap": "12288",
"vbrLowerCap": "32",
"maxFrameRate": "2500",
"keyFrameInterval": "2000",
"snapShotImageType": "JPEG",
"H264Profile": "Main",
"GovLength": "50",
"SVC": {
"enabled": "false"
},
"PacketType": ["PS", "RTP"],
"smoothing": "50",
"H265Profile": "Main",
"SmartCodec": {
"enabled": "false"
}
},
"Audio": {
"enabled": "false",
"audioInputChannelID": "1",
"audioCompressionType": "G.711ulaw"
}
},
{
"@version": "2.0",
"@xmlns": "http://www.hikvision.com/ver20/XMLSchema",
"id": "102",
"channelName": "yard",
"enabled": "true",
"Transport": {
"maxPacketSize": "1000",
"ControlProtocolList": {
"ControlProtocol": [
{
"streamingTransport": "RTSP"
},
{
"streamingTransport": "HTTP"
},
{
"streamingTransport": "SHTTP"
},
{
"streamingTransport": "SRTP"
}
]
},
"Unicast": {
"enabled": "true",
"rtpTransportType": "RTP/TCP"
},
"Multicast": {
"enabled": "true",
"destIPAddress": "0.0.0.0",
"videoDestPortNo": "8866"
},
"Security": {
"enabled": "true",
"certificateType": "digest",
"SecurityAlgorithm": {
"algorithmType": "MD5"
}
},
"SRTPMulticast": {
"SRTPVideoDestPortNo": "18866"
}
},
"Video": {
"enabled": "true",
"videoInputChannelID": "1",
"videoCodecType": "H.264",
"videoScanType": "progressive",
"videoResolutionWidth": "640",
"videoResolutionHeight": "360",
"videoQualityControlType": "VBR",
"constantBitRate": "256",
"fixedQuality": "60",
"vbrUpperCap": "256",
"vbrLowerCap": "32",
"maxFrameRate": "1000",
"keyFrameInterval": "4000",
"snapShotImageType": "JPEG",
"H264Profile": "Baseline",
"GovLength": "40",
"SVC": {
"enabled": "false"
},
"PacketType": ["PS", "RTP"],
"smoothing": "50",
"H265Profile": "Main"
},
"Audio": {
"enabled": "false",
"audioInputChannelID": "1",
"audioCompressionType": "G.711ulaw"
}
}
]
}
}
}
}
}
Expand Down
Loading

0 comments on commit c83426e

Please sign in to comment.