Need help extracting values from XML rest sensor for Plusnet Hub 2 router stats

Hi - I hope someone can help me - I expect if you know how to do this it’s simple but I’m stretching the boundaries of my knowledge.

I have successfully created a rest sensor to retireve XML status information from my Plusnet Hub 2 router:

sensor:
  - platform: rest
    resource: http://192.168.1.254/nonAuth/wan_conn.xml
    method: GET
    headers:
      Referer: http://192.168.1.254/basic_-_status.htm
    name: Wan Linestatus Rate List
    scan_interval: 60
    value_template: "{{ value_json.status.wan_linestatus_rate_list }}"
    json_attributes:
      - status

This populates the sensor with the following value:

{’@type’: ‘array’, ‘@value’: “[[‘UP’,‘VDSL2’,‘Profile%2017a’,‘156’,‘118’,‘161’,‘78’,‘192’,‘78’,‘138’,‘70’,‘40000’,‘9999’,‘74652000’,‘17731000’,‘fast’], null]”}

I would like to be able to extract the 12th, 13th, 14th and 15th values in this array e.g. ‘40000’,‘9999’,‘74652000’,‘17731000’ into individual sensor values for sync speed down, sync speed up, max sync down, max sync up

I think I probably need to put this in a section something like this:

rest:
  - resource: http://192.168.1.254/nonAuth/wan_conn.xml
    method: GET
    headers:
      Referer: http://192.168.1.254/basic_-_status.htm
    sensor:
      - name: "sync_down"
        value_template: ????
      - name: "sync_up"
        value_template: ????
      - name: "max_sync_down"
        value_template: ????
      - name: "max_sync_down"
        value_template: ????

I have put question marks for the value_template because that’s what I need help with.

The complete XML that comes back from the rest call is like this:

HTTP/1.0 200 Ok
Cache-Control: no-cache,no-store,must-revalidate, post-check=0,pre-check=0
Connection: close
Content-Language: en
Content-Type: text/xml
Expires: 0
Pragma: no-cache
Server: httpd
Set-Cookie: urn=3ba14b51c20b5837; Path=/; HttpOnly
X-Frame-Options: DENY

<status>
	<!-- REAL -->
		<wan_conn_status_list type="array" value="[['disconnected%3B0%3Bpass'],
['connecting%3B0%3Bpass'],
['disconnected%3B0%3Bpass'],
null]" />
		<wan_conn_volume_list type="array" value="[['0%3B0%3B0'],
['0%3B0%3B0'],
['0%3B0%3B0'],
null]" />
		<wan_linestatus_rate_list type="array" value="[['UP','VDSL2','Profile%2017a','157','120','161','78','192','78','138','70','40000','9999','74667000','18018000','fast'],
null]" />
		<wlan_channel_list type="array" value="[['1','0','1'],
['1','0','1'],
['1','0','1'],
['1','0','1'],
['1','0','1'],
['36','0','36'],
['36','0','36'],
['36','0','36'],
['36','0','36'],
['36','0','36'],
null]" />
		<curlinkstatus type="array" value="[['disconnected%3B0'],
['connected%3B59'],
['disconnected%3B0'],
null]" />
		<sysuptime value="3839" />
		<status_rate type="array" value="[['0%3B0%3B0%3B0'],
['9999000%3B40000000%3B0%3B0'],
['0%3B0%3B0%3B0'],
null]" />
		<wan_active_idx value="" />
		<link_status value="connected%3Bvdsl%3B59" />
		<ip4_info_list type="array" value="[['0%2E0%2E0%2E0%3B0%2E0%2E0%2E0%3B0%2E0%2E0%2E0%3B0%2E0%2E0%2E0%3B0%2E0%2E0%2E0'],
['0%2E0%2E0%2E0%3B0%2E0%2E0%2E0%3B0%2E0%2E0%2E0%3B0%2E0%2E0%2E0%3B0%2E0%2E0%2E0'],
['0%2E0%2E0%2E0%3B0%2E0%2E0%2E0%3B0%2E0%2E0%2E0%3B0%2E0%2E0%2E0%3B0%2E0%2E0%2E0'],
null]" />
		<ip6_lla_list type="array" value="[['%3A%3A%2F0'],
['%3A%3A%2F0'],
['%3A%3A%2F0'],
null]" />
		<ip6_gua_list type="array" value="[['%3A%3A%2F0%3B%3A%3A'],
['%3A%3A%2F0%3B%3A%3A'],
['%3A%3A%2F0%3B%3A%3A'],
null]" />
		<ip6_rdns_list type="array" value="[[null],[null],[null]]" />
	<!-- END_REAL -->
	<!--for home page, login lock-->
		<locktime value="1" />
	<!--END for home page, login lock-->
</status>

Very grateful for any help.

OK, so after a long conversation with ChatGPT I’ve worked out a method of doing this. Am leaving it here for reference in case anyone else want to get data from their Plusnet Hub 2.

The XML data was in an awkward format, so resorted to regex to extract what I needed.

The original rest sensor above remains, and then I added the following template sensors:

template:
  - sensor:
    - name: PlusNet_Up_or_Down
      unique_id: PlusNet_Up_or_Down
      state: >-
        {% set temp = (states('sensor.wan_linestatus_rate_list') | regex_findall_index('(?<=,)[^,]*', 0))  %}
        {{ temp[14:] }}
      
  - sensor:
    - name: PlusNet_Sync_Down
      unique_id: PlusNet_Sync_Down
      state_class: measurement
      unit_of_measurement: bps
      state: >-
        {% set temp = (states('sensor.wan_linestatus_rate_list') | regex_findall_index('(?<=,)[^,]*', 11))  %}
        {{ temp | trim("'") | int}}
        
  - sensor:
    - name: PlusNet_Sync_Up
      unique_id: PlusNet_Sync_Up
      state_class: measurement
      unit_of_measurement: bps
      state: >-
        {% set temp = (states('sensor.wan_linestatus_rate_list') | regex_findall_index('(?<=,)[^,]*', 12))  %}
        {{ temp | trim("'") | int}}
        
  - sensor:
    - name: PlusNet_Max_Sync_Down
      unique_id: PlusNet_Max_Sync_Down
      state_class: measurement
      unit_of_measurement: bps
      state: >-
        {% set temp = (states('sensor.wan_linestatus_rate_list') | regex_findall_index('(?<=,)[^,]*', 13))  %}
        {{ temp | trim("'") | int}}
        
  - sensor:
    - name: PlusNet_Max_Sync_Up
      unique_id: PlusNet_Max_Sync_Up
      state_class: measurement
      unit_of_measurement: bps
      state: >-
        {% set temp = (states('sensor.wan_linestatus_rate_list') | regex_findall_index('(?<=,)[^,]*', 14))  %}
        {{ temp | trim("'") | int}}

The info from this link also helped work out what data was what:

How do I add this to my HomeAssistant?

(I’ve tried using the BT_SmartHub and gotten nowhere)

I’ve created a script plusnet.yaml which failed

ERROR (MainThread) [homeassistant.components.script] Script with object id ‘script’ could not be validated and has been disabled: extra keys not allowed @ data[‘sensor’]. Got [{‘platform’: ‘rest’, ‘resource’: ‘http://192.168.1.254/nonAuth/wan_conn.xml’, ‘method’: ‘GET’, ‘headers’: {‘Referer’: ‘http://192.168.1.254/basic_-_status.htm’}, ‘name’: ‘Wan Linestatus Rate List’, ‘scan_interval’: 60,

I have the code in the main configuration.yaml

Remember if you have other sensor or template code you have to put this code within those sections.

It isn’t really a script, it’s just defining sensors and template sensors.

Hope that helps

Triggers activated. Please try this instead of the robot sick.

rest:
  - resource: http://192.168.1.254/nonAuth/wan_conn.xml
    method: GET
    headers:
      Referer: http://192.168.1.254/basic_-_status.htm
    sensor:
      - name: "sync_down"
        value_template: "{{ value_json['status']['wan_linestatus_rate_list']['@value'][0][11] }}"
      - name: "sync_up"
        value_template: "{{ value_json['status']['wan_linestatus_rate_list']['@value'][0][12] }}"
      - name: "max_sync_down"
        value_template: "{{ value_json['status']['wan_linestatus_rate_list']['@value'][0][13] }}"
      - name: "max_sync_up"
        value_template: "{{ value_json['status']['wan_linestatus_rate_list']['@value'][0][14] }}"

Thanks @Troon - that looks a lot neater and is how I thought it should be done.

I was in a rush to get it working because I had a visit from Openreach scheduled to fix problems on my line.

I’ll give that a try when I have time.

1 Like