Here’s Mark II of this automated sensor config. I have automatically-generated sensors like this for each of my tasmota devices:
First, clear out the sensor’s information if we detect a tasmota device has just come online:
automation:
- alias: tasmota_reboot
trigger:
- platform: mqtt
topic: 'tele/+/INFO1'
action:
- service: python_script.set_state
data_template:
overwrite: true
entity_id: >
{%- set sensor_name = 'tasmota_' + (trigger.topic.split('/')[1] | lower) -%}
{{ states.sensor[sensor_name].entity_id }}
state: 'unknown'
attributes:
startup_time: >
{{ as_timestamp(now()) | timestamp_local }}
Next is basically the automation from before which is triggered by the STATE topic, but with some new conditions, and firing an event at the end:
- alias: tasmota_rssi
trigger:
- platform: mqtt
topic: 'tele/+/STATE'
# Don't update an RSSI sensor more than once every 5 minutes
# unless we need to collect other information
condition:
- condition: template
value_template: >
{%- set device_name = trigger.topic.split('/')[1] -%}
{%- set sensor = states.sensor['tasmota_' + (device_name | lower)] -%}
{%- if (not sensor)
or ('rssi' not in sensor.attributes)
or ('tasmota_version' not in sensor.attributes)
or ('ip_address' not in sensor.attributes)
or ('mqtt_topic' not in sensor.attributes)
or ('group_topic' not in sensor.attributes)
-%}
True
{%- else -%}
{%- set range = 5 * 60 - 1 -%}
{%- set since_last_update = as_timestamp(now()) - as_timestamp(sensor.last_updated) -%}
{{ since_last_update >= range }}
{%- endif -%}
action:
- service: python_script.set_state
data_template:
overwrite: false
entity_id: >
{%- set device_name = trigger.topic.split('/')[1] -%}
sensor.tasmota_{{ device_name | lower }}
state: >
{{ trigger.payload_json.Wifi.RSSI }}
attributes:
unit_of_measurement: '%'
updated: >
{{ as_timestamp(now()) | timestamp_local }}
access_point: >
{%- set access_points = {
"[MAC_ADDRESS_HALLWAY]": "hallway",
"[MAC_ADDRESS_KITCHEN]": "kitchen",
"[MAC_ADDRESS_RECROOM]": "recroom"
} -%}
{{ access_points[trigger.payload_json.Wifi.BSSId] }}
rssi: >
{{ trigger.payload_json.Wifi.RSSI | int }}
channel: >
{{ trigger.payload_json.Wifi.Channel }}
- event: gather_tasmota_info
event_data_template:
mqtt_topic: >
{%- set device_name = trigger.topic.split('/')[1] -%}
{{ device_name }}
Originally, instead of this event, I just published an MQTT message asking for all the statuses that TASMOTA can send out (i.e., the STATUS 0 command), but the responses came too fast and the respective automations tried to update the state of the sensors too quickly, and some information didn’t make it in. I split it up into multiple automations and this seems to work. Each automation has a condition so that it only fires if we need to collect its particular status information.
The friendly name and MQTT topic:
- alias: tasmota_status_trigger
trigger:
- platform: event
event_type: gather_tasmota_info
condition:
- condition: template
value_template: >
{%- set device_name = trigger.event.data.mqtt_topic -%}
{%- set sensor = states.sensor['tasmota_' + (device_name | lower)] -%}
{{ 'mqtt_topic' not in sensor.attributes }}
action:
- service: mqtt.publish
data_template:
topic: >
{%- set device_name = trigger.event.data.mqtt_topic -%}
cmnd/{{ device_name }}/Status
- alias: tasmota_status
trigger:
- platform: mqtt
topic: 'stat/+/STATUS'
action:
- service: python_script.set_state
data_template:
overwrite: false
entity_id: >
{%- set device_name = trigger.topic.split('/')[1] -%}
sensor.tasmota_{{ device_name | lower }}
attributes:
friendly_name: >
{{ trigger.payload_json.Status.FriendlyName[0] }}
mqtt_topic: >
{{ trigger.payload_json.Status.Topic }}
The group topic, OTA URL and startup time
- alias: tasmota_status1_trigger
trigger:
- platform: event
event_type: gather_tasmota_info
condition:
- condition: template
value_template: >
{%- set device_name = trigger.event.data.mqtt_topic -%}
{%- set sensor = states.sensor['tasmota_' + (device_name | lower)] -%}
{{ 'group_topic' not in sensor.attributes }}
action:
- service: mqtt.publish
data_template:
topic: >
{%- set device_name = trigger.event.data.mqtt_topic -%}
cmnd/{{ device_name }}/Status
payload: 1
- alias: tasmota_status1
trigger:
- platform: mqtt
topic: 'stat/+/STATUS1'
action:
- service: python_script.set_state
data_template:
overwrite: false
entity_id: >
{%- set device_name = trigger.topic.split('/')[1] -%}
sensor.tasmota_{{ device_name | lower }}
attributes:
group_topic: "{{ trigger.payload_json.StatusPRM.GroupTopic }}"
ota_url: "{{ trigger.payload_json.StatusPRM.OtaUrl }}"
startup_time: "{{ as_timestamp(trigger.payload_json.StatusPRM.StartupUTC + '-00:00') | timestamp_local }}"
The tasmota and library versions:
- alias: tasmota_status2_trigger
trigger:
- platform: event
event_type: gather_tasmota_info
condition:
- condition: template
value_template: >
{%- set device_name = trigger.event.data.mqtt_topic -%}
{%- set sensor = states.sensor['tasmota_' + (device_name | lower)] -%}
{{ 'tasmota_version' not in sensor.attributes }}
action:
- service: mqtt.publish
data_template:
topic: >
{%- set device_name = trigger.event.data.mqtt_topic -%}
cmnd/{{ device_name }}/Status
payload: 2
- alias: tasmota_status2
trigger:
- platform: mqtt
topic: 'stat/+/STATUS2'
action:
- service: python_script.set_state
data_template:
overwrite: false
entity_id: >
{%- set device_name = trigger.topic.split('/')[1] -%}
sensor.tasmota_{{ device_name | lower }}
attributes:
tasmota_version: "{{ trigger.payload_json.StatusFWR.Version }}"
tasmota_core: "{{ trigger.payload_json.StatusFWR.Core }}"
tasmota_sdk: "{{ trigger.payload_json.StatusFWR.SDK }}"
And finally, the IP and MAC addresses:
- alias: tasmota_status5_trigger
trigger:
- platform: event
event_type: gather_tasmota_info
condition:
- condition: template
value_template: >
{%- set device_name = trigger.event.data.mqtt_topic -%}
{%- set sensor = states.sensor['tasmota_' + (device_name | lower)] -%}
{{ 'mac_address' not in sensor.attributes }}
action:
- service: mqtt.publish
data_template:
topic: >
{%- set device_name = trigger.event.data.mqtt_topic -%}
cmnd/{{ device_name }}/Status
payload: 5
- alias: tasmota_status5
trigger:
- platform: mqtt
topic: 'stat/+/STATUS5'
action:
- service: python_script.set_state
data_template:
overwrite: false
entity_id: >
{%- set device_name = trigger.topic.split('/')[1] -%}
sensor.tasmota_{{ device_name | lower }}
attributes:
ip_address: "{{ trigger.payload_json.StatusNET.IPAddress }}"
mac_address: "{{ trigger.payload_json.StatusNET.Mac }}"
I also found a small bug in my set_state script where specifying overwrite: false
didn’t work because it was treating false
as a string and not a boolean value.
#==================================================================================================
# python_scripts/set_state.py
#==================================================================================================
entityId = data.get('entity_id')
if entityId is None:
logger.warning("set_state.py: entity_id not specified.")
else:
overwrite = data.get('overwrite')
if (overwrite is None) or (overwrite.lower() == 'false'):
overwrite = False
# logger.debug("overwrite = False")
else:
overwrite = True
# logger.debug("overwrite = True")
entityState = hass.states.get(entityId)
newState = data.get('state')
if newState is None:
newState = 'unknown' if (overwrite or (not entityState.state)) else entityState.state
newAttributes = {} if (overwrite or (not entityState.attributes)) else entityState.attributes.copy()
dataAttributes = data.get('attributes')
if dataAttributes is None:
dataAttributes = {}
for item in dataAttributes:
newAttributes[item] = dataAttributes[item]
hass.states.set(entityId, newState, newAttributes)