Help With value_template

Tell me how you wish to re-map the sensors. Is it simply putting them in reverse-order (like I’ve done in the example above) or is there no pattern to it?

If it’s reverse-order then there may be a way to do it elegantly with a for-loop (and I may be able to help you). If there’s no pattern, then the for-loop will have a long chain of if-else tests to perform the re-mapping. The end-result will be no more elegant than the simplistic approach used in my example.

However, if you wish to pursue the for-loop approach as an exercise in improving your Jinja2 skills, I encourage you to continue! There are several community members who are very skilled with Jinja2 (I exclude myself from that short-list) and they may stop by to help you.

So… you have a pain in the ass template here. This should work every time though:

- platform: mqtt
  name: "01159038DEFF Temperature"
  state_topic: "th10_02/tele/SENSOR"
  unit_of_measurement: "°C"
  value_template: >
    {% set serial_number = '01159038DEFF' %}
    {{ ((d.values() | list)[1:-1] | selectattr('Id', 'eq', serial_number) | list)[0].Temperature }}
  payload_available: "Online"
  payload_not_available: "Offline"

so what it does is it turns the output into a list of dictionaries that only contain your id’s and temperatures. Next it selects the correct item that contains the serial number you are looking for (That returns a list). So then, the list should only be 1 item, so we take the first item, then return the temperature.

Super pain in the ass, but it should work.

1 Like

Always something to learn from your examples!

I’m stumped by the d in d.values, where’s that defined?

No pattern, I’m afraid. These represent sensor in a chain up the side of a hot water tank. I didn’t know what order TASMOTA was going to put them in, since I knew it was going to have to “find” them. I have remapped them manually using the config: I’m happy with sensor 6 being called TankTemp1, etc. The problem arose last night when I added a sensor to the bottom of the chain and it appeared in the middle of TASMOTA’s list. I figured since I know the order of the sensors by Id, I may as well use that information.

I’d hope there would only be 6 if-else statements in a for loop. Since I’ve already manually mapped them and I don’t plan on adding any more sensors, it’s as much a programming exercise for me as anything else. I am a software engineer, as it happens; I’ve just never done anything with this type of architecture before.

That is exactly what I wanted to hear!

No, it’s … almost elegant. I can work with this. It’s a bit like Python except for the one unfamiliar jinja function call.

Thank you! A whole new world literally just opened up.

I don’t suppose the config supports a “global” variable type? Somewhere I could store

{ "01159038DEFF":"TankSensor1", "0115903BCEFF":"TankSensor2",
"011377AADEFF":"TankSensor3", "0113772384AA":"TankSensor4", ...  }

I could then traverse and nest your functionality within?

@KDM @123

That’s a typo on my part. I forgot to replace d w/ the trigger.payload_json

- platform: mqtt
  name: "01159038DEFF Temperature"
  state_topic: "th10_02/tele/SENSOR"
  unit_of_measurement: "°C"
  value_template: >
    {% set serial_number = '01159038DEFF' %}
    {{ ((trigger.payload_json.values() | list)[1:-1] | selectattr('Id', 'eq', serial_number) | list)[0].Temperature }}
  payload_available: "Online"
  payload_not_available: "Offline"

So anyways, you shouldn’t need to map anything with this. Just change the serial number and you’ll get the serial numbers temperature.

1 Like

Thank! I guessed that might be the case … but wasn’t 100% that you weren’t doing something extra tricky!

I put the relevant bits into the Template Editor to poke at it and learn how it works. I have to hand it to you, that first part that converts the data into a list, then lops off the leading and trailing elements, is pretty slick. I bookmarked your post for future reference (one of many of your Jinja2 posts).

1 Like

I couldn’t think of any way to do it so that I could use selectattr! I’m just hoping that his dictionary is somewhat ordered. Otherwise, some other finagling would need to happen.

Bother. I get state: Unknown in the HA states screen for each of the sensors.
Do you suppose that’s because they’re not monotonic?

Actually, that’ll be irrelevant. They’re monotonic in TASMOTA as it finds them.

So the template is failing somehow. Errors could be in the log.

Do you have resolve your case? I have a similar problem, I need identify the temperature with serial number. Thanks

With apologies for taking so long to reply. Particular apologies to petro, because despite his best efforts, I didn’t try any further with this.
I still find the YAML and JSON (or whatever this mixture is) syntax utterly stupefying. I found my solution by writing post processor scripts in Python and publishing the results in a format which was more useful. In this case, I don’t actually WANT to display the sensors data, I just want to know what order they’re in and which of them is above a certain setpoint, so I can calculate my hot water tank level.
Now, I use my Python postprocessor to handle all my 433MHz traffic and have coded up quite a functional zoned burglar alarm.
I really wish I could grasp the YAML thing. I’m a software engineer, believe it or not, but I just have some kind of block its paradigms. It’s irritating, because I feel I’m close: the brackety dictionaries and things look exactly like Python, but just with none of the flexability.

Well, the issue was the fact we were using trigger.payoad_json. It should be replaced with value_json.
Part of the issue was that I had never used MQTT at the time and I wasn’t aware of the available variables. And the resulting template would be:

- platform: mqtt
  name: "01159038DEFF Temperature"
  state_topic: "th10_02/tele/SENSOR"
  unit_of_measurement: "°C"
  value_template: >
    {% set serial_number = '01159038DEFF' %}
    {% set selection = value_json.values() | list | selectattr('Id', 'eq', serial_number) | map(attribute='Temperature') | list %}
    {{ selection[0] if selection | count > 0 else 0.0 }}
  payload_available: "Online"
  payload_not_available: "Offline"
2 Likes

I believe there’s a typo in the template’s last line. The test should check selection[0]

    {{ selection[0] if selection[0] > 0 else 0.0 }}

(The template generates an error without the addition of the [0])

Or is this the intended logic?

    {{ selection[0] if selection | count > 0 else 0.0 }}

Yah total typo. Brain fart.

EDIT: Made edit, intention was | count

1 Like

Thanks for this @petro, I don’t fully understand how it works, but it does :slight_smile:
I’m trying to expand on this and also add the id as an attribute. I’ve tried to use the same style template for the json_attributes_template as for the value_template, but no success.

So how do I tweek this to add the id number, and maybe also the sensor name as given by tasmoto (DS18B20-x), as attributes?

- platform: mqtt
  name: "01159038DEFF Temperature"
  state_topic: "th10_02/tele/SENSOR"
  unit_of_measurement: "°C"
  value_template: >
    {% set serial_number = '01159038DEFF' %}
    {% set selection = value_json.values() | list | selectattr('Id', 'eq', serial_number) | map(attribute='Temperature') | list %}
    {{ selection[0] if selection | count > 0 else 0.0 }}
  payload_available: "Online"
  payload_not_available: "Offline"
json_attributes_template
  id: >
    {% set serial_number = '01159038DEFF' %}
    {% set selection = value_json.values() | list | selectattr('Id', 'eq', serial_number) | map(attribute='Id') | list %}
    {{ selection[0] if selection | count > 0 else 0.0 }}
  name: >
    {% set serial_number = '01159038DEFF' %}
    {% set selection = value_json.items() | list | selectattr('[-1].Id', 'eq', serial_number) | map(attribute='[0]') | list %}
    {{ selection[0] if selection | count > 0 else 0.0 }}

Hm, this doesn’t work…
Had to add a colon after json_attributes_template, after that I get this error when checking the config.

Invalid config for [sensor.mqtt]: extra keys not allowed @ data[‘id’]. Got “{% set serial_number = ‘01159038DEFF’ %} {% set selection = value_json.values() | list | selectattr(‘Id’, ‘eq’, serial_number) | map(attribute=‘Id’) | list %} {{ selection[0] if selection | count > 0 else 0.0 }}\n”
template value is None for dictionary value @ data[‘json_attributes_template’]. Got None. (See ?, line ?).

Edit: I played around with it some more to see if I could extract the name and the ID separately. The below snippet successfully puts the Id as an attribute:

json_attributes_template: >
    {% set serial_number = '0114580048AA' %}
    {% set selection = value_json.values() | list | selectattr('Id', 'eq', serial_number) | map(attribute='Id') | list %}
    {% set serial =  selection[0] if selection | count > 0 else 0.0 %}
    {{ {'Id' : serial} | tojson}}

But the below version does not work for the name, it seems to return the whole json structure from the sensor:

json_attributes_template: >
    {% set serial_number = '0114580048AA' %}
    {% set selection = value_json.items() | list | selectattr('[-1].Id', 'eq', serial_number) | map(attribute='[0]') | list %}
    {% set name =  selection[0] if selection | count > 0 else 0.0 %}
    {{ {'Name' : name} | tojson}}

Resulting attributes:

Time: 2020-02-22T15:05:28
Switch1: ON
DS18B20-1: {
“Id”: “0114580048AA”,
“Temperature”: 20.6
}
DS18B20-2: {
“Id”: “01145800E7AA”,
“Temperature”: 20.2
}
DS18B20-3: {
“Id”: “011458072EAA”,
“Temperature”: 20.3
}
DS18B20-4: {
“Id”: “011458078CAA”,
“Temperature”: 20.3
}
DS18B20-5: {
“Id”: “0114580868AA”,
“Temperature”: 20.4
}
DS18B20-6: {
“Id”: “0114580936AA”,
“Temperature”: 20.3
}
DS18B20-7: {
“Id”: “0114581138AA”,
“Temperature”: 20.3
}
DS18B20-8: {
“Id”: “011927495402”,
“Temperature”: 20.3
}
TempUnit: C

try this for the name:

    {% set serial_number = '01159038DEFF' %}
    {% set selection = value_json.items() | list | selectattr('1.Id', 'eq', serial_number) | map(attribute='0') | first %}
    {{ selection if selection else 'NA' }}