snarky-snark / home-assistant-variables

A custom Home Assistant component for declaring and setting generic variable entities dynamically.
Apache License 2.0
274 stars 16 forks source link

Attributes as Objects #88

Closed maforshaw closed 1 year ago

maforshaw commented 1 year ago

It would be nice if var attributes could be optionally stored as objects instead of strings. For example, I use a var SQL query to return multiple records as a JSON array which is then stored in an attribute.

To then use this attribute later I need to deserialise every time with "from_json" which is not ideal.

I know this is possible because I was previously using the component ha-sql_json which says this:

"It is already possible to access data elements within a JSON result with the core SQL integration in templates using the from_json filter, however doing this causes the JSON string to be deserialised every time that the template is evaluated which is exponentially inefficient for large query results."

To overcome this, if you look at the source code, it works out the object type as follows:

                    if isinstance(value, decimal.Decimal):
                        value = float(value)
                    if isinstance(value, datetime.date):
                        value = str(value)
                    try:
                        value_json = json.loads(value)
                        if isinstance(value_json, dict) or isinstance(value_json, list):
                            value = value_json
                    except (ValueError, TypeError):
                        pass
                    self._attributes[key] = value

This means a JSON string that is output from the SQL query is then stored in the attribute as a list (or dictionary, depending on content) with no need to deserialise later.

To maintain backwards compatibility, I guess you could either add a boolean property whether to automatically work it out as above or a property to specify the data type.

jb1228 commented 1 year ago

You can actually do this already via templates (also works with the built-in sensor/binary_sensor templates).

Example:

var:
  my_var:
    friendly_name: Var with Attributes as Object and Array
    initial_value: 100
    attributes:
      my_object: >-
        {{ {
          'aaaa': 'value_aaaa',
          'bbbb': 'value_bbbb',
          'cccc': 'value_cccc'
        } }}
      my_array: >-
        {{ [
          'item1',
          'item2',
          'item3'
        ] }}

You can then access the values as normal:

maforshaw commented 1 year ago

Perfect, thank you @jb1228