maciej-or / hikvision_next

Home Assistant integration for Hikvision NVRs and IP cameras
115 stars 23 forks source link

Add support for cameras with multiple channels (thermal cameras, for example) #241

Closed sebastian-enz closed 2 days ago

sebastian-enz commented 2 weeks ago

This pull request adds support for Hikvision thermal cameras with multiple channels that are not NVRs. The implementation simplifies the handling of these devices by treating their channels similarly to standard camera streams.

This is a simplified version of https://github.com/maciej-or/hikvision_next/pull/239

Key Changes:

The integration now:

Note: I'm unsure how to write tests for HA addons, but the changes are pretty simple and straightforward to review.

maciej-or commented 2 weeks ago

Thanks for this contribution. Now it is clearer. Many existing tests failed because of introducing new request <Request('GET', 'http://1.0.0.255/ISAPI/Streaming/channels')> not mocked! all existing fixtures have no that, I'll try to think of something. Question: why did you map thermal event to motion instead of creating a new one? So far any event has switch to enable/disable particular detection. Because of this mapping we will lost toggling thermal detection.

sebastian-enz commented 2 weeks ago

First of all, thanks a lot for all your work creating this addon.

If you need the output of the Streaming/channels request, I will be happy to share it.

About your question: Apologies, probably what you say would be the better solution. I'd say a thermometry event in its simplest form is simply motion detection, but if you prefer you could also split it to be a separate event in const.py.

maciej-or commented 2 weeks ago

yes, please send the Streaming/channels response and diagnostic data from your device. It contains all responses needed to create a test environment. Let's leave mapping for now.

maciej-or commented 2 weeks ago

I added missing request to the existing fixtures and added your multichannel camera fixture. I added a small test and modified obtaining channel id as well. FYI in test environment can emulate any device from fixtures folder, I recommend to use vscode after opening integration project all you need is to run in terminal
pip install -r requirements.test.txt Are you going to add binary sensor for thermal detection or can I merge this?

sebastian-enz commented 2 weeks ago

Perfect, thanks! I added a separate event for thermometry now. This should be sufficient to create the separate binary sensor, right? I would appreciate if you can compare to the diagnostic data I sent.

maciej-or commented 2 weeks ago

yes, binary sensor and switch are created, please confirm if sensor is properly triggered and if switch works. Diagnostic data does not include these things.

sebastian-enz commented 1 week ago

I thought it works fine, but I didn't delete and re-add the device. Then it didn't work anymore with the "thermometry" binary sensor when I tried again today. The 2 channels are shown fine, but no binary sensor or switch is created for the device anymore at all then:

2024-11-13 20:20:28.617 INFO (MainThread) [homeassistant.components.camera] Setting up hikvision_next.camera
2024-11-13 20:20:28.618 INFO (MainThread) [homeassistant.helpers.entity_registry] Registered new camera.hikvision_next entity: camera.ds_2td1228_2_xxxxxxxxxx_101
2024-11-13 20:20:28.619 INFO (MainThread) [homeassistant.helpers.entity_registry] Registered new camera.hikvision_next entity: camera.ds_2td1228_2_xxxxxxxxxx_102
2024-11-13 20:20:28.619 INFO (MainThread) [homeassistant.helpers.entity_registry] Registered new camera.hikvision_next entity: camera.ds_2td1228_2_xxxxxxxxxx_103
2024-11-13 20:20:28.619 INFO (MainThread) [homeassistant.helpers.entity_registry] Registered new camera.hikvision_next entity: camera.ds_2td1228_2_xxxxxxxxxx_104
2024-11-13 20:20:28.619 INFO (MainThread) [homeassistant.helpers.entity_registry] Registered new camera.hikvision_next entity: camera.ds_2td1228_2_xxxxxxxxxx_201
2024-11-13 20:20:28.619 INFO (MainThread) [homeassistant.helpers.entity_registry] Registered new camera.hikvision_next entity: camera.ds_2td1228_2_xxxxxxxxxx_202
2024-11-13 20:20:28.620 INFO (MainThread) [homeassistant.helpers.entity_registry] Registered new camera.hikvision_next entity: camera.ds_2td1228_2_xxxxxxxxxx_203
2024-11-13 20:20:28.620 INFO (MainThread) [homeassistant.helpers.entity_registry] Registered new camera.hikvision_next entity: camera.ds_2td1228_2_xxxxxxxxxx_204
2024-11-13 20:20:28.620 INFO (MainThread) [homeassistant.components.sensor] Setting up hikvision_next.sensor
2024-11-13 20:20:28.623 INFO (MainThread) [homeassistant.helpers.entity_registry] Registered new sensor.hikvision_next entity: sensor.ds_2td1228_2_xxxxxxxxxx_alarm_server_ipaddress
2024-11-13 20:20:28.623 INFO (MainThread) [homeassistant.helpers.entity_registry] Registered new sensor.hikvision_next entity: sensor.ds_2td1228_2_xxxxxxxxxx_alarm_server_portno
2024-11-13 20:20:28.624 INFO (MainThread) [homeassistant.helpers.entity_registry] Registered new sensor.hikvision_next entity: sensor.ds_2td1228_2_xxxxxxxxxx_alarm_server_url
2024-11-13 20:20:28.624 INFO (MainThread) [homeassistant.helpers.entity_registry] Registered new sensor.hikvision_next entity: sensor.ds_2td1228_2_xxxxxxxxxx_1_hdde
2024-11-13 20:20:28.624 INFO (MainThread) [homeassistant.components.switch] Setting up hikvision_next.switch
2024-11-13 20:20:28.624 INFO (MainThread) [homeassistant.helpers.entity_registry] Registered new switch.hikvision_next entity: switch.ds_2td1228_2_xxxxxxxxxx_1_alarm_output
2024-11-13 20:20:28.625 INFO (MainThread) [homeassistant.components.image] Setting up hikvision_next.image
2024-11-13 20:20:28.625 INFO (MainThread) [homeassistant.helpers.entity_registry] Registered new image.hikvision_next entity: image.ds_2td1228_2_xxxxxxxxxx_101_snapshot
2024-11-13 20:20:28.625 INFO (MainThread) [homeassistant.helpers.entity_registry] Registered new image.hikvision_next entity: image.ds_2td1228_2_xxxxxxxxxx_201_snapshot

The Event/Trigger call returns more events, but it seems for some reason the integration does not create the sensors for thos events:

2024-11-13 20:20:28.299 DEBUG (MainThread) [custom_components.hikvision_next.isapi.isapi] --- [GET] http://1.2.3.4/ISAPI/Event/triggers
2024-11-13 20:20:28.299 DEBUG (MainThread) [custom_components.hikvision_next.isapi.isapi] 
{'EventNotification': {'@version': '2.0', '@xmlns': 'http://www.isapi.org/ver20/XMLSchema', 'EventTriggerList': {'@version': '2.0', '@xmlns': 'http://www.isapi.org/ver20/XMLSchema', 'EventTrigger': [{'id': 'IO-1', 'eventType': 'IO', 'eventDescription': 'IO Event trigger Information', 'inputIOPortID': '1', 'EventTriggerNotificationList': None}, {'id': 'VMD-1', 'eventType': 'VMD', 'eventDescription': 'VMD Event trigger Information', 'EventTriggerNotificationList': {'EventTriggerNotification': [{'id': 'record-1', 'notificationMethod': 'record', 'notificationRecurrence': 'beginning', 'videoInputID': '1'}, {'id': 'beep', 'notificationMethod': 'beep', 'notificationRecurrence': 'beginning'}, {'id': 'center', 'notificationMethod': 'center', 'notificationRecurrence': 'beginning'}]}}, {'id': 'tamper-1', 'eventType': 'tamperdetection', 'eventDescription': 'shelteralarm Event trigger Information', 'EventTriggerNotificationList': None}, {'id': 'diskfull', 'eventType': 'diskfull', 'eventDescription': 'exception Information', 'EventTriggerNotificationList': None}, {'id': 'diskerror', 'eventType': 'diskerror', 'eventDescription': 'exception Information', 'EventTriggerNotificationList': {'EventTriggerNotification': {'id': 'beep', 'notificationMethod': 'beep', 'notificationRecurrence': 'beginning'}}}, {'id': 'nicbroken', 'eventType': 'nicbroken', 'eventDescription': 'exception Information', 'EventTriggerNotificationList': None}, {'id': 'ipconflict', 'eventType': 'ipconflict', 'eventDescription': 'exception Information', 'EventTriggerNotificationList': None}, {'id': 'illaccess', 'eventType': 'illaccess', 'eventDescription': 'exception Information', 'EventTriggerNotificationList': None}, {'id': 'badvideo', 'eventType': 'badvideo', 'eventDescription': 'exception Information', 'EventTriggerNotificationList': None}, {'id': 'audioexception-1', 'eventType': 'audioexception', 'eventDescription': 'audioexception Event trigger Information', 'EventTriggerNotificationList': None}, {'id': 'thermometry-2', 'eventType': 'thermometry', 'eventDescription': 'thermometry Event trigger Information', 'videoInputChannelID': '2', 'dynVideoInputChannelID': '2', 'EventTriggerNotificationList': {'EventTriggerNotification': {'id': 'center', 'notificationMethod': 'center', 'notificationRecurrence': 'beginning'}}}]}}}
2024-11-13 20:20:28.317 DEBUG (MainThread) [custom_components.hikvision_next.isapi.isapi] --- [GET] http://1.2.3.4/ISAPI/Event/triggers/scenechangedetection-1
2024-11-13 20:20:28.317 DEBUG (MainThread) [custom_components.hikvision_next.isapi.isapi] 
{'EventTrigger': {'@version': '2.0', '@xmlns': 'http://www.isapi.org/ver20/XMLSchema', 'id': 'scenechangedetection-1', 'eventType': 'scenechangedetection', 'eventDescription': 'scenechangedetection Event trigger Information', 'EventTriggerNotificationList': None}}

Could you check the log please? https://pastebin.com/Bn9dyAHM

You can even see the events coming in from the camera, but they are not parsed as the sensors weren't created when I added the device.

I would appreciate your help to finalize this.

maciej-or commented 1 week ago

did you pull my latest update https://github.com/maciej-or/hikvision_next/pull/241/commits/e08113689aa1d338b07353fccddd5492159d22cd ?

maciej-or commented 1 week ago

I see that the camera sends alert as motion detection (VMD)

<EventNotificationAlert>
<ipAddress>1.2.3.4</ipAddress>
<portNo>8123</portNo>
<protocol>HTTP</protocol>
<macAddress>xxxxxxxxxx</macAddress>
<dynChannelID>2</dynChannelID>
<channelID>2</channelID>
<dateTime>2024-11-13T20:20:48+01:00</dateTime>
<activePostCount>1</activePostCount>
<eventType>VMD</eventType>
<eventState>active</eventState>
<eventDescription>Motion alarm</eventDescription>
<channelName>Camera 02</channelName>
</EventNotificationAlert>

so binary_sensor.xxxxxxxxxxxxxxxxxxx_2_thermometry wont be triggered, it looks like we have to go back to mapping and you will have 2 binary sensors for the cam binary_sensor.ds_2td1228_2_xxxxxxxxxx_1_motiondetection - for video motion binary_sensor.ds_2td1228_2_xxxxxxxxxx_2_motiondetection - for thermometry motion I will fix that, add a test for this alert and back to you for test on the device

sebastian-enz commented 1 week ago

Nope, I missed that latest update. Just tried it, and yes, the thermometry binary sensor shows up, but no other sensors (such as motion detection). However, HASS doesn't even receive thermometry events anymore according to the logs.

2024-11-13 21:30:52.281 DEBUG (MainThread) [custom_components.hikvision_next.coordinator] Finished fetching hikvision_next data in 0.108 seconds (success: True)
2024-11-13 21:30:52.309 INFO (MainThread) [custom_components.hikvision_next.isapi.isapi] --- [GET] http://1.2.3.4/ISAPI/System/Video/inputs/channels/2/thermometry
Client error '403 Forbidden' for url 'http://1.2.3.4/ISAPI/System/Video/inputs/channels/2/thermometry'
For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/403
2024-11-13 21:30:52.309 ERROR (MainThread) [custom_components.hikvision_next.coordinator] Unexpected error fetching hikvision_next data
Traceback (most recent call last):
  File "/config/custom_components/hikvision_next/isapi/isapi.py", line 735, in request
    response.raise_for_status()
  File "/usr/local/lib/python3.12/site-packages/httpx/_models.py", line 763, in raise_for_status
    raise HTTPStatusError(message, request=request, response=self)
httpx.HTTPStatusError: Client error '403 Forbidden' for url 'http://1.2.3.4/ISAPI/System/Video/inputs/channels/2/thermometry'
For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/403

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/config/custom_components/hikvision_next/coordinator.py", line 48, in _async_update_data
    data[_id] = await self.device.get_event_enabled_state(event)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/hikvision_next/isapi/isapi.py", line 446, in get_event_enabled_state
    state = await self.request(GET, event.url)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/hikvision_next/isapi/isapi.py", line 746, in request
    raise ISAPIForbiddenError(full_url)
custom_components.hikvision_next.isapi.isapi.ISAPIForbiddenError: http://1.2.3.4/ISAPI/System/Video/inputs/channels/2/thermometry

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/update_coordinator.py", line 382, in _async_refresh
    self.data = await self._async_update_data()
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/hikvision_next/coordinator.py", line 50, in _async_update_data
    self.device.handle_exception(ex, f"Cannot fetch state for {event.id}")
  File "/config/custom_components/hikvision_next/hikvision_device.py", line 153, in handle_exception
    raise HomeAssistantError(f"{ex.message} {details}")
homeassistant.exceptions.HomeAssistantError: Forbidden request http://1.2.3.4/ISAPI/System/Video/inputs/channels/2/thermometry, check user permissions. Cannot fetch state for thermometry

Yes, you are correct about VMD, it sends those events, also fielddetection. But the sensors for motion detection etc. aren't created by the integration.

With the changes in my earlier pull request (mapping thermometry to motion detection simply), at least I was able to get a motion detection sensor showing up, which apparently (then) received the thermometry events, and worked for that.

maciej-or commented 1 week ago

yea, it looks like we have to go back to mapping and you will have 2 binary sensors for the cam binary_sensor.ds_2td1228_2_xxxxxxxxxx_1_motiondetection - for video motion binary_sensor.ds_2td1228_2_xxxxxxxxxx_2_motiondetection - for thermometry motion I will fix that, add a test for this alert and back to you for test on the device

sebastian-enz commented 1 week ago

To summarize, I think the current state of works:

Thanks, I will try your fix next week.

sebastian-enz commented 1 week ago

@maciej-or Do you want me to test your latest changes? Or are they still under development?

maciej-or commented 1 week ago

yes, it is ready to test, pls check if binary sensor is triggered and switch