Fetch multiple JSON values and present them as attributes UBIBOT

Hi,

I am trying to fetch the various last_values from fields in one API call. Right now I have each field number it in separate API call.

sensor 5:
  - platform: rest
    scan_interval: 120
    resource: https://api.ubibot.io/channels/17577?account_key=XXXXX
    name: Temperature_Kitchen_ubibot
    value_template: '{{ (value_json.channel.last_values|from_json).field1.value|float }}'
    unit_of_measurement: "°C"
sensor 6:
  - platform: rest
    scan_interval: 120
    resource: https://api.ubibot.io/channels/17577?account_key=XXXX
    name: Humidty_Kitchen_ubibot
    value_template: '{{ (value_json.channel.last_values|from_json).field2.value|round()|float }}'

Thanks for any help

You can create a sensor that stores the data into an attribute. You can’t store it all in the sensor’s state because it can only hold a 255 character string value. In contrast, an entity’s attribute can store far more and the data’s type is not limited to string.

Explore using the RESTful Sensor’s json_attributes option.

For example, create a master UbiBot RESTful Sensor that periodically retrieves all data.

  - platform: rest
    scan_interval: 120
    resource: https://api.ubibot.io/channels/17577?account_key=XXXXX
    name: Master UbiBot
    value_template: '{{ now() }}'
    json_attributes:
      - channel

All that remains is to create Template Sensors (temperature and humidity) that access the channel attribute in sensor.master_ubibot. They will be updated whenever Master UbiBot gets new data. Let me know if you need help creating the Template Sensors.


NOTE

I’m not sure why you are creating multiple sensor domains using sensor 5:, sensor 6:, etc. All sensors can be defined within one sensor: domain. What’s the reason for creating a separate domain for each individual sensor?

Thank you for your help. I am still new to configurating in yaml. I have got all my generic devices in fine, just this one has been a bit of a learning curve for me.

If you could help with creating a template sensor for me that would be great.

Also, I have two separate UBIBOT channels for two separate sensors, so not sure if that would change the API call? To call both in one call?
Channel 22692 and 17577. Then each one has separate field1-field10s
Thanks again.

Trying to follow directions here:

I came up with this but its not working…

  - platform: rest
    scan_interval: 5
    resource: https://api.ubibot.io/channels/17577?account_key=XXXX
    name: Master UbiBot
    value_template: '{{ now() }}'
    json_attributes:
      - channel
  - platform: template
    sensors:
      kitchen_temp:
        value_template: '{{ states.sensor.master_ubibot.attributes["channel"]["last_values"]["field1"]["value"] }}'
        device_class: temperature
        unit_of_measurement: "°C"
      kitchen_humidity:
        value_template: '{{ states.sensor.master_ubibot.attributes["channel"]["last_values"]["field2"]["value"] }}'

And I cleaned up my config file, I had it like that when I just started with HA…

Figured it out finally…

value_template: '{{ (states.sensor.master_ubibot.attributes.channel.last_values|from_json).field1.value|float }}'

Glad you figured it out. You can also get an attribute’s value like this:

{{ state_attr('sensor.master_ubibot', 'channel') }}

Can you provide an example of the value in the channel attribute? I’m trying to understand why you are using the from_json filter. The easiest way is by pasting the template I posted into Developer Tools > Template Editor. Whatever appears in the Template Editor’s results pane is what I would need to see (either paste a screenshot of it or copy-paste the text in your reply).

You can see an example here of how it comes out…

But here is the data for the sensor state…

channel: 
channel_id: '17577'
name: Kitchen
field1: Temperature
field2: Humidity
field3: Light
field4: Voltage
field5: WIFI RSSI
field6: GSM RSSI
field7: EXT1 Temperature
field8: EXT2 Temperature
field9: RS485 Temperature
field10: RS485 Humidity

elevation: null
created_at: '2020-08-19T11:41:18Z'
updated_at: '2020-12-21T03:45:26Z'
metadata: >-
  {"fn_th":60,"fn_light":60,"fn_ext_t":60,"fn_battery":10800,"fn_485_th":0,"fn_485_sth":0,"fn_dp":300,"net_mode":0,"no_net_fn":1,"cg_data_led":1,"wifi_mode":1,"thres_acc_min":0}
tags: null
public_flag: 'false'
url: null
description: null


usage: '15518504'
device_id: xxx
status: >-
  XXXX
status_date: '1612741275'
last_ip: xxxx
channel_icon: null
product_id: ubibot-ws1p
plan_code: ubibot_free
plan_start: '2020-08-19T11:41:18Z'
plan_end: null
bill_start: '2021-01-16T11:41:18Z'
bill_end: '2021-02-15T11:41:18Z'
traffic_out: '323675'
traffic_in: '7467993'
full_dump: '0'
renew: null
last_values: >-
  {"field3":{"value":0,"created_at":"2021-02-07T23:40:21Z","net":"1"},"field1":{"value":10.390633,"created_at":"2021-02-07T23:40:21Z","net":"1"},"field2":{"value":32,"created_at":"2021-02-07T23:40:21Z","net":"1"},"field4":{"value":5,"created_at":"2021-02-07T20:45:53Z"},"field5":{"value":-55,"created_at":"2021-02-07T23:35:24Z"},"field8":{"value":23.4375,"created_at":"2021-02-03T18:38:11Z","net":"0"},"field7":{"value":41.875,"created_at":"2020-12-19T00:42:48Z","net":"0"}}
vconfig: >-
  {"field1":{"h":"0","u":"1"},"field2":{"h":"0","u":"3"},"field3":{"h":"0","u":"4"},"field4":{"h":"0","u":"5"},"field5":{"h":"0","u":"6"},"field6":{"h":"0","u":"11"},"field7":{"h":"0","u":"14"},"field8":{"h":"0","u":"14"},"field9":{"h":"0","u":"12"},"field10":{"h":"0","u":"13"}}
sensors_mapping: null
sensors: null
firmware: ws1pro_v1.7.0
cali: null
timezone: null
vpref: null
vpref_from: owner
next_id: '22154'
size_out: '1073741824'
size_storage: '209715200'
full_dump_limit: '3'

After you deleted everything in the Template Editor and pasted the template from my previous post, what did the Template Editor report at the top of the (right hand) results pane?

Did it say:

Results type: string

Or was it something other than “string”?

It says “Result type: dict”

Good. It implies your template probably doesn’t need the from_json filter. The channel attribute is already understood to contain a dictionary object (dict). My guess is that last_values may also be understood to be a dictionary.

Try this template in the Template Editor and see if it reports the correct value.

value_template: '{{ states.sensor.master_ubibot.attributes.channel.last_values.field1.value|float }}'

Ok, I just tried to see what would happen.

I tried the way I had it and removed the from_json and it didn’t work. I just tried the way you had it and it also didn’t work.

I put that string in the template editor and it says “UndefinedError: ‘str object’ has no attribute ‘field1’”

Interesting. Oh well, it was worth trying. Anyway, the crux of the challenge (creating a “master sensor”) has been resolved.

Thanks for your help!

Is there a way to create a master sensor that encompass multiple channels? I have 2 right now (one for each physical sensor).

I have 2 master api calls now, one for channel 17577 and one for 22692.

The RESTful Sensor can accept only one URL, so that means only one per physical sensor.

They have an alternative way of formatting the API call, with just the account key and no channel number. Which brings in all channel numbers I have. Would I be able to define the attribute as the channel number?

OK, that sounds like a good way to consolidate all channels into one RESTful Sensor. However, I imagine the structure of the received data will be slightly different (to accommodate all channels). You will probably need to modify the json_attributes option and the Template Sensors to adapt to the new data structure.

Thats what I was thinking… Now I am lost how to format the value template… I have this…

  - platform: rest
    scan_interval: 5
    resource: https://api.ubibot.io/channels?account_key=XXXXX
    name: Master UbiBot test
    value_template: '{{ now() }}'
    json_attributes:
      - channels
      
  - platform: template
    scan_interval: 5
    sensors:
      test_temp:
        friendly_name: "Test Temperature"
        value_template: '{{ (states.sensor.master_ubibot_test.attributes.channels.channel_id["17577"].last_values|from_json).field1.value|float }}'
        device_class: temperature
        unit_of_measurement: "°C"   

I believe the problem is pulling the correct channel number into the value template.

The returned API call is virtaully idential except now the attribute is “channels” vs “channel”. It returns everything for the first channel then everything for the second.

I would post the result but it has a lot of user data I dont want posted publicly, I could PM it to you if you need to see it.

All I need to see is the top-level structure where you referenced it using this:

channels.channel_id["17577"]

That implies the dictionary looks something like this:

{"channels": {"channel_id": "17577": {"last_values": { etc

Is that more or less correct?

I did just notice this difference…

NEW

channels: 
- channel_id: '17577'

VS
Original API

channel: 
channel_id: '22692'

Here is the top level doing the API call in browser…

{"result":"success","server_time":"2021-02-08T02:56:15Z","channels":[{"channel_id":"17577",