MQTT Discovery Config - Include a timestamp attribute

Hi all, so far I’ve successfully been able to use MQTT Discovery to discover some custom sensors I’ve created. One battery optimization I’m trying to do for my custom sensor is to cache multiple readings over time, each with its own timestamp, and then periodically publish all of the cached readings via MQTT (this allows for less time with the wifi radio enabled, reducing power consumption).

What I’m trying to figure out is how to update my MQTT Discovery configuration to include a timestamp as part of the sensor data payload so that Home Assistant can use that timestamp for plotting the data instead of the publish timestamp.

My first thought was to potentially add a timestamp attribute to each Sensor, does anyone know if that will work? If so, I’d love some input on how to write the json_attr_tpl template as I’m having a hard time figuring out how to form it.

My first attempt at adding an attribute to the config topic hasn’t worked:

Config topic:
homeassistant/sensor/Magtag-c7fd1a54a342_Magtag_CO2_SCD41_SCD41_CO2/config


{
  "device_class": "carbon_dioxide",
  "stat_t": "~/state",
  "obj_id": "Magtag_CO2_SCD41_SCD41_CO2",
  "~": "homeassistant/sensor/Magtag-c7fd1a54a342",
  "unit_of_meas": "ppm",
  "uniq_id": "Magtag-c7fd1a54a342_Magtag_CO2_SCD41_SCD41_CO2",
  "stat_cla": "measurement",
  "dev": {
    "mdl": "Adafruit MagTag with ESP32S2",
    "ids": "c7fd1a54a342",
    "name": "Magtag_CO2_SCD41",
    "sw": "7.3.3 on 2022-08-29",
    "mf": "Espressif"
  },
  "name": "SCD41 CO2",
  "json_attr_t": "~/state",
  "val_tpl": "{{ value_json.SCD41_CO2 | round(0) }}",
  "json_attr_tpl": "{{ value_json.Timestamp | timestamp_local }}"
}

The State topic payload looks like this:

{
  "SCD41_Humidity": 36.0413,
  "Batt_Voltage": 4.08397,
  "SCD41_Temperature": 22.7425,
  "Timestamp": 1672327760,
  "SCD41_CO2": 579
}

You need to put the timestamp into following format:
2023-02-08T11:15:04+01:00

At least this works for me.

Here’s a Jacascript snippet that does the conversion.

function formatTimestamp(timestamp) {
    const date = new Date(timestamp);
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, "0");
    const day = String(date.getDate()).padStart(2, "0");
    const hours = String(date.getHours()).padStart(2, "0");
    const minutes = String(date.getMinutes()).padStart(2, "0");
    const seconds = String(date.getSeconds()).padStart(2, "0");
    const offset = -date.getTimezoneOffset();
    const offsetHours = String(Math.floor(offset / 60)).padStart(2, "0");
    const offsetMinutes = String(offset % 60).padStart(2, "0");
    const offsetStr = `${offset >= 0 ? "+" : "-"}${offsetHours}:${offsetMinutes}`;
    return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}${offsetStr}`;
}

msg.payload = formatTimestamp(d);

@ingoM Thanks! However, I’m not clear where to apply this formatted timestamp? Did you add a key/value pair to the state topic, config topic, and/or something else?

@rdlaner - I am using Node Red to push this information to my mqtt server.

I think you may succeed if you bring your timestamp value into following format

2023-02-08T11:15:04+01:00

This means you need to transform the val_tpl and do some formatting there
"val_tpl": "{{ FORMAT_THIS_VALUE | round(0) }}",

Not sure how you do this with standard functionality in YAML. Maybe this helps

Ah, ok, I think I have an idea of what to do. Reading between the lines, I think you are suggesting that I could publish a separate MQTT Discovery config message specifically for a formatted timestamp that is part of the same state topic as the rest of my data. Cool! Ok, let me give that a shot.

Are you using MQTT Discovery with your Node Red setup, btw?

eh, the problem I’m running into with this approach is that in order to use MQTT Discovery, I need to define each discoverable element as one of the components defined here:

Looking at that list of components, I don’t see any option for timestamp.

Try this version:

  "json_attr_tpl": { "timestamp": {% raw %}"{{ value_json.Timestamp | timestamp_local }}"{% endraw %} }

in the payload you are using for MQTT Discovery:

{
  "device_class": "carbon_dioxide",
  "stat_t": "~/state",
  "obj_id": "Magtag_CO2_SCD41_SCD41_CO2",
  "~": "homeassistant/sensor/Magtag-c7fd1a54a342",
  "unit_of_meas": "ppm",
  "uniq_id": "Magtag-c7fd1a54a342_Magtag_CO2_SCD41_SCD41_CO2",
  "stat_cla": "measurement",
  "dev": {
    "mdl": "Adafruit MagTag with ESP32S2",
    "ids": "c7fd1a54a342",
    "name": "Magtag_CO2_SCD41",
    "sw": "7.3.3 on 2022-08-29",
    "mf": "Espressif"
  },
  "name": "SCD41 CO2",
  "json_attr_t": "~/state",
  "val_tpl": "{{ value_json.SCD41_CO2 | round(0) }}",
  "json_attr_tpl": { "timestamp": {% raw %}"{{ value_json.Timestamp | timestamp_local }}"{% endraw %} }
}

It’s untested and, because of the added complexity of nested JSON and Jinja2, it may have incorrect quotes. Anyway, give a try whenever you have the time.

Did you ever get this working? I want to build a very similar device but I’m extremely novice at Home Assistant’s data formats and the whole tempting system is pretty opaque to me to begin with. I’m not so much concerned with setting up auto discovery just yet, but there don’t seem to be many examples even just making a sensor that pulls in values with a payload timestamp instead of time of arrival.

Unfortunately, I was not able to find a way to get this to work as I originally wanted to. What I did instead was create a “log” MQTT topic where I send my device’s short log strings. These strings include the timestamp for when the log entry was made. That’s been a good enough work-around for me for now.