REST sensor polling does not work from the second scan

Hello Everyone,

I am trying to use the RESTful platform to fetch data from a Hikvision Access Control Terminal DS-K1T805MBFWX (a fingerprint reader and keypad). Data is collected fine the first time it is polled (upon restart or after “rest entities” reload is performed). However, from the moment the scan_interval is reached the first time and until it is reloaded manually again, attributes dissapear and do not load again unless I reload REST.

Should I do anything to fix this or isn’t the rest platform the right choice for this kind of sensor data fetching?

rest:
  - authentication: digest
    username: "admin"
    password: "xxxxxx"
    scan_interval: 10
    resource: http://192.168.0.75/ISAPI/AccessControl/AcsEvent?format=json
    method: POST
    headers:
      Content-Type: "application/json"
    payload: >-
        {"AcsEventCond": {"searchID": "1","searchResultPosition": 0,"maxResults": 10,"major": 0,"minor": 0,"startTime": "2025-04-17T00:00:00+02:00","endTime": "2035-04-18T23:59:59+02:00","timeReverseOrder": true}}
    sensor:
      - name: "HikReader"
        json_attributes_path: "$.AcsEvent.InfoList[0]"
        value_template: "HikReader"
        json_attributes:
          - "major"
          - "minor"
          - "time"
          - "type"
          - "serialNo"
          - "netUser"
          - "remoteHostAddr"
          - "cardType"
          - "name"
          - "cardReaderNo"
          - "doorNo"
          - "employeeNoString"
          - "userType"
          - "currentVerifyMode"

sensor data upon first polling:

sensor data after second scan:

Error in core logs:

Logger: homeassistant.components.rest.util
Source: components/rest/util.py:33
integration: RESTful (documentation, issues)
First occurred: 8:23:38 PM (430 occurrences)
Last logged: 9:36:34 PM
JSON result was not a dictionary or list with 0th element a dictionary

If I use a command_line sensor instead for one of the JSON values, sensor data stays fine as it should:

command_line:
   - sensor:
        command: !secret HikReader_Events
        name: "HikReader Time"
        scan_interval: 5
        value_template: >
            {{ value_json.AcsEvent.InfoList[0].time if value_json.AcsEvent.InfoList | length > 2 and 'time' in value_json.AcsEvent.InfoList[0] else 'Desconocido' }}

Secret:

curl --digest -k -u admin:xxxxxx --location 'http://192.168.0.75/ISAPI/AccessControl/AcsEvent?format=json' --header 'Content-Type: application/json' --data '{"AcsEventCond": {"searchID": "1","searchResultPosition": 0,"maxResults": 10,"major": 0,"minor": 0,"startTime": "2025-04-17T00:00:00+02:00","endTime": "2035-04-18T23:59:59+02:00","timeReverseOrder": true}}'

But, I’d rather use the REST platform because I can collect several JSON values as attributes in one single sensor easily, so happy to get some advice if possible. Thanks!

Are you sure method: POST should be used and not method: GET?

You’re right. The curl does a GET, but the REST sensor does a POST.

So, if the curl works, then make the sensor a GET.

Thanks. You are right: cURL is GET and REST is POST. I did it by mistake. However, after trying REST with GET, it does not work at all (I alse expected it to work after your suggestion becuase it made sense). Attributes are not loaded, something that it works with POST at the first scan at least.

Strange that with cURL works both with POST and GET…

Not sure how to move forward on this then. Happy to GET further advice if any. :wink:

What happens when you call the HA update action under the dev tools with the sensor as target? Do you get valid data or errors?

Let’s enable debug logging and see if we can get more info. I think you can do it from the UI nowadays.

What if you try basic instead of digest?

No errors:

Attaching Google Drive file with full logs. Logs created after a HASS restart. you will see some sensor.hikreader entries in the log where it is stated the “old” good “state” and the “new” bad (no attributes except the friendly_name one). Be advised that there is a similar sensor called sensor.hikreader_ultimo_evento which it is not related with the problem, so better to search for sensor.hikreader,(with a comman at the end) so you can find the relevant sensor.

Pasting below a cleaner version containing what I understand that is related with the relevant sensor:

2025-04-20 14:58:40.726 DEBUG (MainThread) [homeassistant.core] Bus:Handling <Event state_changed[L]: entity_id=sensor.hikreader, old_state=None, new_state=<state sensor.hikreader=HikReader; major=3, minor=1029, time=2025-04-20T14:02:01+02:00, type=0, serialNo=690, friendly_name=HikReader @ 2025-04-20T14:58:40.726450+02:00>>
2025-04-20 14:58:40.726 DEBUG (MainThread) [homeassistant.core] Bus:Handling <Event state_reported[L]: entity_id=sensor.hikreader, old_last_reported=2025-04-20T14:58:40.726450+02:00, new_state=<state sensor.hikreader=HikReader; major=3, minor=1029, time=2025-04-20T14:02:01+02:00, type=0, serialNo=690, friendly_name=HikReader @ 2025-04-20T14:58:40.726450+02:00>>
2025-04-20 14:58:50.746 WARNING (MainThread) [homeassistant.components.rest.util] JSON result was not a dictionary or list with 0th element a dictionary
2025-04-20 14:58:50.747 DEBUG (MainThread) [homeassistant.core] Bus:Handling <Event state_changed[L]: entity_id=sensor.hikreader, old_state=<state sensor.hikreader=HikReader; major=3, minor=1029, time=2025-04-20T14:02:01+02:00, type=0, serialNo=690, friendly_name=HikReader @ 2025-04-20T14:58:40.726450+02:00>, new_state=<state sensor.hikreader=HikReader; friendly_name=HikReader @ 2025-04-20T14:58:40.726450+02:00>>
2025-04-20 14:58:50.747 DEBUG (MainThread) [homeassistant.core] Bus:Handling <Event state_reported[L]: entity_id=sensor.hikreader, old_last_reported=2025-04-20T14:58:50.746978+02:00, new_state=<state sensor.hikreader=HikReader; friendly_name=HikReader @ 2025-04-20T14:58:40.726450+02:00>>
2025-04-20 14:58:50.747 DEBUG (MainThread) [homeassistant.core] Bus:Handling <Event system_log_event[L]: name=homeassistant.components.rest.util, message=['JSON result was not a dictionary or list with 0th element a dictionary'], level=WARNING, source=('components/rest/util.py', 33), timestamp=1745153930.7465448, exception=, count=1, first_occurred=1745153930.7465448>
2025-04-20 14:59:00.802 WARNING (MainThread) [homeassistant.components.rest.util] JSON result was not a dictionary or list with 0th element a dictionary
2025-04-20 14:59:00.802 DEBUG (MainThread) [homeassistant.core] Bus:Handling <Event state_reported[L]: entity_id=sensor.hikreader, old_last_reported=2025-04-20T14:58:50.747333+02:00, new_state=<state sensor.hikreader=HikReader; friendly_name=HikReader @ 2025-04-20T14:58:40.726450+02:00>>
2025-04-20 14:59:00.802 DEBUG (MainThread) [homeassistant.core] Bus:Handling <Event state_reported[L]: entity_id=sensor.hikreader, old_last_reported=2025-04-20T14:59:00.802623+02:00, new_state=<state sensor.hikreader=HikReader; friendly_name=HikReader @ 2025-04-20T14:58:40.726450+02:00>>
2025-04-20 14:59:00.802 DEBUG (MainThread) [homeassistant.core] Bus:Handling <Event system_log_event[L]: name=homeassistant.components.rest.util, message=['JSON result was not a dictionary or list with 0th element a dictionary'], level=WARNING, source=('components/rest/util.py', 33), timestamp=1745153940.8023636, exception=, count=1, first_occurred=1745153940.8023636>
2025-04-20 14:59:10.767 WARNING (MainThread) [homeassistant.components.rest.util] JSON result was not a dictionary or list with 0th element a dictionary
2025-04-20 14:59:10.768 DEBUG (MainThread) [homeassistant.core] Bus:Handling <Event state_reported[L]: entity_id=sensor.hikreader, old_last_reported=2025-04-20T14:59:00.802762+02:00, new_state=<state sensor.hikreader=HikReader; friendly_name=HikReader @ 2025-04-20T14:58:40.726450+02:00>>
2025-04-20 14:59:10.768 DEBUG (MainThread) [homeassistant.core] Bus:Handling <Event state_reported[L]: entity_id=sensor.hikreader, old_last_reported=2025-04-20T14:59:10.767811+02:00, new_state=<state sensor.hikreader=HikReader; friendly_name=HikReader @ 2025-04-20T14:58:40.726450+02:00>>
2025-04-20 14:59:10.768 DEBUG (MainThread) [homeassistant.core] Bus:Handling <Event system_log_event[L]: name=homeassistant.components.rest.util, message=['JSON result was not a dictionary or list with 0th element a dictionary'], level=WARNING, source=('components/rest/util.py', 33), timestamp=1745153950.7672608, exception=, count=1, first_occurred=1745153950.7672608>
2025-04-20 14:59:20.814 WARNING (MainThread) [homeassistant.components.rest.util] JSON result was not a dictionary or list with 0th element a dictionary
2025-04-20 14:59:20.815 DEBUG (MainThread) [homeassistant.core] Bus:Handling <Event state_reported[L]: entity_id=sensor.hikreader, old_last_reported=2025-04-20T14:59:10.768349+02:00, new_state=<state sensor.hikreader=HikReader; friendly_name=HikReader @ 2025-04-20T14:58:40.726450+02:00>>
2025-04-20 14:59:20.815 DEBUG (MainThread) [homeassistant.core] Bus:Handling <Event state_reported[L]: entity_id=sensor.hikreader, old_last_reported=2025-04-20T14:59:20.814981+02:00, new_state=<state sensor.hikreader=HikReader; friendly_name=HikReader @ 2025-04-20T14:58:40.726450+02:00>>
2025-04-20 14:59:20.816 DEBUG (MainThread) [homeassistant.core] Bus:Handling <Event system_log_event[L]: name=homeassistant.components.rest.util, message=['JSON result was not a dictionary or list with 0th element a dictionary'], level=WARNING, source=('components/rest/util.py', 33), timestamp=1745153960.8147094, exception=, count=1, first_occurred=1745153960.8147094>

Thanks!

It doesn’t even load attributes once.

But also no updated attributes, like after restarting?

Yes. I see the friendly_name only. No other attributes displayed. It is not about being empty. They are not displayed at all:

Post the result of the endpoint. Rest does not see it as JSON, therefore all the json oriented functionality won’t work. I.e. json_attributes.

As a sidebar, the command_line integration is more mature than rest at the moment as it has active code-owners where rest does not.

I already have a workflow based on cURL shell_commands and it works fine. However, I am keen on knowing why the REST option behaves like it is doing. Besides, the workflow would be cleaner if I could do this with REST sensors instead, although I am happy to keep it as it is.

This is the output I get with the cURL command containing the same data included in the REST sensor:

curl --digest -k -u admin:xxxxx --location 'http://192.168.0.75/ISAPI/AccessControl/AcsEvent?format=json' --header 'Content-Type: application/json' --data '{"AcsEventCond": {"searchID": "1","searchResultPosition": 0,"maxResults": 10,"major": 0,"minor": 0,"startTime": "2025-04-17T00:00:00+02:00","endTime": "2035-04-18T23:59:59+02:00","timeReverseOrder": true}}'
{
	"AcsEvent":	{
		"searchID":	"1",
		"responseStatusStrg":	"MORE",
		"numOfMatches":	10,
		"totalMatches":	606,
		"InfoList":	[{
				"major":	3,
				"minor":	1029,
				"time":	"2025-04-21T13:05:35+02:00",
				"type":	0,
				"serialNo":	944
			}, {
				"major":	5,
				"minor":	22,
				"time":	"2025-04-21T13:03:59+02:00",
				"doorNo":	1,
				"type":	0,
				"serialNo":	943
			}, {
				"major":	5,
				"minor":	179,
				"time":	"2025-04-21T13:03:55+02:00",
				"cardType":	1,
				"name":	"My Name",
				"cardReaderNo":	1,
				"doorNo":	1,
				"employeeNoString":	"001",
				"type":	0,
				"serialNo":	941,
				"userType":	"normal",
				"currentVerifyMode":	"fpOrPw"
			}, {
				"major":	5,
				"minor":	21,
				"time":	"2025-04-21T13:03:55+02:00",
				"doorNo":	1,
				"type":	0,
				"serialNo":	942
			}, {
				"major":	5,
				"minor":	22,
				"time":	"2025-04-21T12:50:24+02:00",
				"doorNo":	1,
				"type":	0,
				"serialNo":	940
			}, {
				"major":	5,
				"minor":	38,
				"time":	"2025-04-21T12:50:20+02:00",
				"cardType":	1,
				"name":	"My Name",
				"cardReaderNo":	1,
				"doorNo":	1,
				"employeeNoString":	"001",
				"type":	0,
				"serialNo":	938,
				"userType":	"normal",
				"currentVerifyMode":	"fpOrPw"
			}, {
				"major":	5,
				"minor":	21,
				"time":	"2025-04-21T12:50:20+02:00",
				"doorNo":	1,
				"type":	0,
				"serialNo":	939
			}, {
				"major":	5,
				"minor":	49,
				"time":	"2025-04-21T12:41:21+02:00",
				"cardType":	1,
				"cardReaderNo":	1,
				"doorNo":	1,
				"type":	0,
				"serialNo":	937,
				"currentVerifyMode":	"fpOrPw"
			}, {
				"major":	5,
				"minor":	22,
				"time":	"2025-04-21T12:41:18+02:00",
				"doorNo":	1,
				"type":	0,
				"serialNo":	936
			}, {
				"major":	5,
				"minor":	21,
				"time":	"2025-04-21T12:41:15+02:00",
				"doorNo":	1,
				"type":	0,
				"serialNo":	935
			}]
	}
}

That looks like valid json, so if it’s not showing up as valid json for rest, there is likely extra characters in the output that rest is collecting and causing it to be invalid json.

To figure this out, make the 2 following rest sensors:

rest:
  - authentication: digest
    username: "admin"
    password: "xxxxxx"
    scan_interval: 10
    resource: http://192.168.0.75/ISAPI/AccessControl/AcsEvent?format=json
    method: POST
    headers:
      Content-Type: "application/json"
    payload: >-
        {"AcsEventCond": {"searchID": "1","searchResultPosition": 0,"maxResults": 10,"major": 0,"minor": 0,"startTime": "2025-04-17T00:00:00+02:00","endTime": "2035-04-18T23:59:59+02:00","timeReverseOrder": true}}
    sensor:
      - name: "HikReader Start"
        value_template: "{{ value[:254] }}"

      - name: "HikReader End"
        value_template: "{{ value[-254:] }}"

Post the states of the sensors here.

The sensors return de following states upon reloading the REST entities:

HikReader Start

{	"AcsEvent":	{		"searchID":	"1",		"responseStatusStrg":	"MORE",		"numOfMatches":	10,		"totalMatches":	618,		"InfoList":	[{				"major":	3,				"minor":	1029,				"time":	"2025-04-21T16:06:04+02:00",				"type":	0,				"serialNo":	956			}, {				"

HikReader End

"minor":	21,				"time":	"2025-04-21T13:51:42+02:00",				"doorNo":	1,				"type":	0,				"serialNo":	949			}, {				"major":	5,				"minor":	22,				"time":	"2025-04-21T13:51:29+02:00",				"doorNo":	1,				"type":	0,				"serialNo":	947			}]	}}

However, after the sensors poll the endpoint the second time (and following ones) the states become the following:

HikReader Start

{	"statusCode":	4,	"statusString":	"Invalid Operation",	"subStatusCode":	"badAuthorization",	"errorCode":	1073741827,	"errorMsg":	"badAuthorization"}

HikReader End

{	"statusCode":	4,	"statusString":	"Invalid Operation",	"subStatusCode":	"badAuthorization",	"errorCode":	1073741827,	"errorMsg":	"badAuthorization"}

Well, that’s your problem. The error in the logs stating it’s not json is referring to the resulting JSON path which is invalid when the auth fails.

And why does it not fail the first time and then fail from the second time onwards? That is not happening with cURL. I also can send several queries in a row from Postman and no error is ever returned.

The rest integration uses the same information every poll, i.e. the first auth information that is received is used from that point forward. I’m not sure how the curl command works under the hood, but if it’s getting a new auth info each poll, that would explain the differences.

As a test, try the alternative RESTful Sensor - Home Assistant.

I did a quick check on GitHub and didn’t find issues with the RESTful integration and auth.

All my own sensors are calling public endpoints, except one where the API token is passed in the headers, so I haven’t experienced this issue myself. What other auth options are available for your device/API?

They both use the same auth (and follow the same instantiation). FYI I plan to take over the integration at some point.

2 Likes

Thanks, then no need to test that…

The OP’s only real options are to stay with the command line one or use a different auth method (if possible) that uses the headers instead.

Kudos