Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
wants to merge 7 commits into
base: dev
Choose a base branch
from

Conversation

sebastian-enz
Copy link

@sebastian-enz sebastian-enz commented Nov 9, 2024

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 #239

Key Changes:

  • Modified camera detection to handle multiple channels on non-NVR devices
  • Remapped thermometry events to motion detection for simplified event handling

The integration now:

  • Detects all available channels on thermal cameras
  • Creates separate entities for each channel
  • Maps thermometry events to standard motion detection events
  • This simplification makes the code more maintainable while preserving full functionality for thermal cameras with multiple channels

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

@maciej-or
Copy link
Owner

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
Copy link
Author

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
Copy link
Owner

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
Copy link
Owner

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
Copy link
Author

sebastian-enz commented Nov 11, 2024

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
Copy link
Owner

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
Copy link
Author

sebastian-enz commented Nov 13, 2024

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
Copy link
Owner

did you pull my latest update e081136
?

@maciej-or
Copy link
Owner

maciej-or commented Nov 13, 2024

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
Copy link
Author

sebastian-enz commented Nov 13, 2024

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
Copy link
Owner

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
Copy link
Author

To summarize, I think the current state of works:

  • Properly adds multiple channels for such cameras
  • However, something in the code which I don't understand fails to create the sensors for other events such as motion detection

Thanks, I will try your fix next week.

@sebastian-enz
Copy link
Author

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

@maciej-or
Copy link
Owner

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants