Sensor from XML using RESTful

Have a device that puts out climate measurements as an XML file. I’m trying to extract the Temperature (C) value only. So far, I have not been able to correctly parse this using the RESTful sensor.

Original XML

<devices>
<device id="XXXXXXXX" name="Climate Monitor" type="server" available="1" index="0">
<field key="TempC" value="30.88" niceName="Temperature (C)" min="-20" max="50" type="2"/>
<field key="TempF" value="87.58" niceName="Temperature (F)" min="-4" max="122" type="2"/>
<field key="Humidity" value="40.00" niceName="Relative Humidity" min="0" max="99" type="2"/>
<field key="Airflow" value="2.20" niceName="Air Flow" min="0" max="100" type="2"/>
<field key="Light" value="1.00" niceName="Light Level" min="1" max="99" type="2"/>
<field key="Sound" value="1.00" niceName="Sound Level" min="0" max="99" type="2"/>
<field key="IO1" value="99.00" niceName="IO-1" min="0" max="99" type="2"/>
<field key="IO2" value="99.00" niceName="IO-2" min="0" max="99" type="2"/>
<field key="IO3" value="99.00" niceName="IO-3" min="0" max="99" type="2"/>
</device>
</devices>  

XML Converted to JSON

{
	"devices": {
		"device": {
			"field": [
				{
					"_key": "TempC",
					"_value": "30.88",
					"_niceName": "Temperature (C)",
					"_min": "-20",
					"_max": "50",
					"_type": "2"
				},
				{
					"_key": "TempF",
					"_value": "87.58",
					"_niceName": "Temperature (F)",
					"_min": "-4",
					"_max": "122",
					"_type": "2"
				},
				{
					"_key": "Humidity",
					"_value": "40.00",
					"_niceName": "Relative Humidity",
					"_min": "0",
					"_max": "99",
					"_type": "2"
				},
				{
					"_key": "Airflow",
					"_value": "2.20",
					"_niceName": "Air Flow",
					"_min": "0",
					"_max": "100",
					"_type": "2"
				},
				{
					"_key": "Light",
					"_value": "1.00",
					"_niceName": "Light Level",
					"_min": "1",
					"_max": "99",
					"_type": "2"
				},
				{
					"_key": "Sound",
					"_value": "1.00",
					"_niceName": "Sound Level",
					"_min": "0",
					"_max": "99",
					"_type": "2"
				},
				{
					"_key": "IO1",
					"_value": "99.00",
					"_niceName": "IO-1",
					"_min": "0",
					"_max": "99",
					"_type": "2"
				},
				{
					"_key": "IO2",
					"_value": "99.00",
					"_niceName": "IO-2",
					"_min": "0",
					"_max": "99",
					"_type": "2"
				},
				{
					"_key": "IO3",
					"_value": "99.00",
					"_niceName": "IO-3",
					"_min": "0",
					"_max": "99",
					"_type": "2"
				}
			],
			"_id": "XXXXXXXXXXXXXX",
			"_name": "Climate Monitor",
			"_type": "Server",
			"_available": "1",
			"_index": "0"
		}
	}
}

REST API config

rest:
  - scan_interval: 20
    resource: "http://xxx.xxx.xxx.xxx/data.xml"
    sensor:
      - name: "Temperature"
        unique_id: "Server Temperature"
        state_class: measurement
        unit_of_measurement: "°C"
        value_template: "{{ value_json.devices.device.field[0]._value }}"
        json_attributes:
        - Value

Have also tried using value_template: “{{ value_json[‘devices’][‘device’][‘field0’][‘_value’] }}” without success.

Edit: HomeAssistant and the device have connectivity. HomeAssistant can retrieve the XML file from terminal using curl without issue.

Can you pass a content type of JSON to that API to get JSON and not XML? The XML data won’t work with the REST integration when using value_json. You’ll need to use just value and use templating and regexes to extract the value.

Otherwise, make a command line sensor using curl and use a utility such as yq to extract what you need from XML.

Also note that json_attributes must be the keys that exist for what was extracted by what’s defined by value_template. Value isn’t in your data and this isn’t a name for what you want the result to be named as.

This post: How to scrape data from an xml? , with solution looks like it’s doing something very similar. It might be helpful!

Tried everything in this thread without success.

That “Value” should not be capitalised.

The device updates that XML file every 15 seconds. There is no API. It will not output anything other than that XML file. The only configurable setting on the device is how frequently it writes new values to the XML file.

Made no difference.

This is the conversion format HA uses: Converting Between XML and JSON

There will be some @ symbols in your json. There is a converter for this format. I’m trying to find it.

Yes it will.

@trenchcoatjedi — I think you’ve converted the XML to JSON incorrectly. Unfortunately the link to the tool on the restful sensor docs doesn’t work any more.

Try @value instead of _value — I’ll have a proper look tomorrow on a real computer. And remove the nonsensical json_attributes line.

2 Likes

This tool should do it:

Then using the output in https://jsonpathfinder.com/ gives:

value_template: "{{ value_json.device.field[0]["@value"] }}"

Thank you @tom_l That was the solution. Here’s the working YAML:

rest:
  - scan_interval: 20
    resource: "http://ip.address/data.xml"
    sensor:
      - name: "Temperature"
        unique_id: "Server Temperature"
        state_class: measurement
        unit_of_measurement: "°C"
        value_template: "{{ value_json.devices.device.field[0]['@value'] }}"
1 Like

Created a PR to replace it: Replace broken XML to json conversion tool link by tomlut · Pull Request #39716 · home-assistant/home-assistant.io · GitHub

I stand corrected. Apologies.

I see the RESTful docs make no mention of XML, except using it in examples, but the RESTful sensor docs do. I checked the former (incorrectly) when I posted and not the latter. I suppose either will then convert automatically.

That’s assuming the °C temperature is always first in the list, which relies on both the order in the XML and that order being retained by the JSON conversion.

I’d suggest:

{{ (value_json['devices']['device']['field']|selectattr('@key','eq','TempC')|first)['@value'] }}
1 Like

Can confirm this works however the order in the XML output on this device never changes (and will never change since it’s no longer being supported).