diff --git a/tasmota/__init__.py b/tasmota/__init__.py
index fa5ba4b73..ce5a0545b 100644
--- a/tasmota/__init__.py
+++ b/tasmota/__init__.py
@@ -21,10 +21,10 @@
#
#########################################################################
+from __future__ import annotations
from datetime import datetime, timedelta
-from lib.model.mqttplugin import *
-# from lib.item import Items
+from lib.model.mqttplugin import MqttPlugin
from lib.item.item import Item
from .webif import WebInterface
@@ -34,7 +34,7 @@ class Tasmota(MqttPlugin):
Main class of the Plugin. Does all plugin specific stuff and provides the update functions for the items
"""
- PLUGIN_VERSION = '1.5.2'
+ PLUGIN_VERSION = '1.6.0'
LIGHT_MSG = ['HSBColor', 'Dimmer', 'Color', 'CT', 'Scheme', 'Fade', 'Speed', 'LedTable', 'White']
@@ -51,6 +51,8 @@ class Tasmota(MqttPlugin):
'SetOption125': 'ON',
}
+ ZIGBEE_BRIDGE_IDENTIFIER = ('zigbee_bridge', 'zb-gw03') # typical friendly names of zigbee bridges
+
TASMOTA_ATTR_R_W = ['relay', 'hsb', 'white', 'ct', 'rf_send', 'rf_key_send', 'zb_permit_join', 'zb_forget', 'zb_ping', 'rf_key']
TASMOTA_ZB_ATTR_R_W = ['power', 'hue', 'sat', 'ct', 'dimmer', 'ct_k']
@@ -105,6 +107,7 @@ def __init__(self, sh):
# Define properties
self.tasmota_devices = {} # to hold tasmota device information for web interface
+ self.tasmota_zb_bridge_topics = set() # to hold all defined topics representing a zigbee bridge
self.tasmota_zigbee_devices = {} # to hold tasmota zigbee device information for web interface
self.topics_of_retained_messages = [] # to hold all topics of retained messages
@@ -131,11 +134,11 @@ def run(self):
# start subscription to all defined topics
self.start_subscriptions()
- self.logger.debug(f"Scheduler: 'check_online_status' created")
+ self.logger.debug("Scheduler: 'check_online_status' created")
dt = self.shtime.now() + timedelta(seconds=(self.telemetry_period - 3))
self.scheduler_add('check_online_status', self.check_online_status, cycle=self.telemetry_period, next=dt)
- self.logger.debug(f"Scheduler: 'add_tasmota_subscriptions' created")
+ self.logger.debug("Scheduler: 'add_tasmota_subscriptions' created")
self.scheduler_add('add_tasmota_subscriptions', self.add_tasmota_subscriptions, cron='init+20')
self.alive = True
@@ -179,6 +182,11 @@ def parse_item(self, item):
tasmota_sml_device = self.get_iattr_value(item.conf, 'tasmota_sml_device')
tasmota_sml_attr = self.get_iattr_value(item.conf, 'tasmota_sml_attr')
+ # check for being Zigbee Bridge
+ if tasmota_zb_device == 'bridge':
+ self.logger.info(f"Tasmota Device with Topic {tasmota_topic} defined as Zigbee Bridge")
+ self.tasmota_zb_bridge_topics.add(tasmota_topic)
+
# handle tasmota
if tasmota_attr:
self.logger.info(f"Item={item.property.path} identified for Tasmota with tasmota_attr={tasmota_attr}")
@@ -187,7 +195,7 @@ def parse_item(self, item):
if tasmota_rf_details and '=' in tasmota_rf_details:
var = tasmota_rf_details.split('=')
if len(var) == 2:
- tasmota_rf_details, tasmota_rf_key_param = var
+ tasmota_rf_details, _ = var
if tasmota_attr == 'relay':
if not tasmota_relay:
@@ -266,7 +274,7 @@ def parse_item(self, item):
return self.update_item
- def update_item(self, item, caller: str = None, source: str = None, dest: str = None):
+ def update_item(self, item, caller: str|None = None, source: str|None = None, dest: str|None = None):
"""
Item has been updated
@@ -295,25 +303,24 @@ def update_item(self, item, caller: str = None, source: str = None, dest: str =
tasmota_zb_cluster = self.get_iattr_value(item.conf, 'tasmota_zb_cluster')
# handle tasmota_admin
- if tasmota_admin:
- if tasmota_admin == 'delete_retained_messages' and bool(item()):
- self.clear_retained_messages()
- item(False, self.get_shortname())
+ if tasmota_admin == 'delete_retained_messages' and bool(item()):
+ self.clear_retained_messages()
+ item(False, self.get_shortname())
# handle tasmota_attr
elif tasmota_attr and tasmota_attr in self.TASMOTA_ATTR_R_W:
- self.logger.info(f"update_item: {item.property.path}, item has been changed in SmartHomeNG outside of this plugin in {caller} with value {item()}")
+ self.logger.info(f"{item.property.path}, item has been changed in SmartHomeNG outside of this plugin in {caller} with value {item()}")
value = item()
link = {
# 'attribute': (detail, data_type, bool_values, min_value, max_value)
- 'relay': (f'Power', bool, ['OFF', 'ON'], None, None),
+ 'relay': ('Power', bool, ['OFF', 'ON'], None, None),
'hsb': ('HsbColor', list, None, None, None),
'white': ('White', int, None, 0, 120),
'ct': ('CT', int, None, 153, 500),
'rf_send': ('Backlog', dict, None, None, None),
- 'rf_key_send': (f'RfKey', int, None, 1, 16),
- 'rf_key': (f'RfKey', bool, None, None, None),
+ 'rf_key_send': ('RfKey', int, None, 1, 16),
+ 'rf_key': ('RfKey', bool, None, None, None),
'zb_permit_join': ('ZbPermitJoin', bool, ['0', '1'], None, None),
'zb_forget': ('ZbForget', bool, ['0', '1'], None, None),
'zb_ping': ('ZbPing', bool, ['0', '1'], None, None),
@@ -326,7 +333,7 @@ def update_item(self, item, caller: str = None, source: str = None, dest: str =
# check data type
if not isinstance(value, data_type):
- self.logger.warning(f"update_item: type of value {type(value)} for tasmota_attr={tasmota_attr} to be published, does not fit with expected type '{data_type}'. Abort publishing.")
+ self.logger.warning(f"type of value {type(value)} for tasmota_attr={tasmota_attr} to be published, does not fit with expected type '{data_type}'. Abort publishing.")
return
# check and correct if value is in allowed range
@@ -358,7 +365,7 @@ def update_item(self, item, caller: str = None, source: str = None, dest: str =
if all(k in rf_cmd for k in [x.lower() for x in self.RF_MSG]):
value = f"RfSync {value['rfsync']}; RfLow {value['rflow']}; RfHigh {value['rfhigh']}; RfCode #{value['rfcode']}"
else:
- self.logger.debug(f"update_item: rf_send received but not with correct content; expected content is: {'RfSync': 12220, 'RfLow': 440, 'RfHigh': 1210, 'RfCode':'#F06104'}")
+ self.logger.debug(f"rf_send received but not with correct content; expected content is: {'RfSync': 12220, 'RfLow': 440, 'RfHigh': 1210, 'RfCode':'#F06104'}")
return
elif tasmota_attr == 'rf_key_send':
@@ -374,13 +381,13 @@ def update_item(self, item, caller: str = None, source: str = None, dest: str =
elif tasmota_attr == 'rf_key':
if not tasmota_rf_details:
- self.logger.warning(f"tasmota_rf_details not specified, no action taken.")
+ self.logger.warning("tasmota_rf_details not specified, no action taken.")
return
if tasmota_rf_details and '=' in tasmota_rf_details:
var = tasmota_rf_details.split('=')
if len(var) == 2:
- tasmota_rf_details, tasmota_rf_key_param = var
+ tasmota_rf_details, _ = var
else:
return
@@ -398,7 +405,7 @@ def update_item(self, item, caller: str = None, source: str = None, dest: str =
return
if value is not None:
- self.publish_tasmota_topic('cmnd', tasmota_topic, detail, value, item, bool_values=bool_values)
+ return self.publish_tasmota_topic('cmnd', tasmota_topic, detail, value, item, bool_values=bool_values)
# handle tasmota_zb_attr
elif tasmota_zb_attr:
@@ -437,7 +444,7 @@ def update_item(self, item, caller: str = None, source: str = None, dest: str =
elif max_value and value > max_value:
self.logger.info(f'Commanded value for {tasmota_zb_attr} above max value; set to allowed max value.')
value = max_value
-
+
# Konvertiere Wert
if convert:
value = convert(value)
@@ -451,7 +458,7 @@ def update_item(self, item, caller: str = None, source: str = None, dest: str =
self.logger.debug(f"payload={payload}")
# publish command
- self.publish_tasmota_topic('cmnd', tasmota_topic, detail, payload, item, bool_values=bool_values)
+ return self.publish_tasmota_topic('cmnd', tasmota_topic, detail, payload, item, bool_values=bool_values)
else:
self.logger.warning(f"update_item: {item.property.path}, trying to change item in SmartHomeNG that is read only in tasmota device (by {caller})")
@@ -460,7 +467,7 @@ def update_item(self, item, caller: str = None, source: str = None, dest: str =
# Callbacks
############################################################
- def on_mqtt_discovery_message(self, topic: str, payload: dict, qos: int = None, retain: bool = None) -> None:
+ def on_mqtt_discovery_message(self, topic: str, payload: dict, qos:int, retain: bool) -> None:
"""
Callback function to handle received discovery messages
@@ -472,24 +479,24 @@ def on_mqtt_discovery_message(self, topic: str, payload: dict, qos: int = None,
"""
try:
- self.logger.dbgmed(f"on_mqtt_discovery_message: topic {topic} = {payload}")
+ self.logger.dbgmed(f"topic {topic} = {payload}")
self._handle_retained_message(topic, retain)
try:
(tasmota, discovery, device_id, msg_type) = topic.split('/')
- self.logger.info(f"on_mqtt_discovery_message: device_id={device_id}, type={msg_type}, payload={payload}")
+ self.logger.info(f"device_id={device_id}, type={msg_type}, payload={payload}")
except ValueError:
self.logger.error(f"received topic {topic} is not in correct format.")
return
if not isinstance(payload, dict):
- self.logger.debug(f'Payload not of type dict. Message will be discarded.')
+ self.logger.debug('Payload not of type dict. Message will be discarded.')
return
if msg_type == 'config':
"""
device_id = 2CF432CC2FC5
-
+
payload =
{
'ip': '192.168.2.33', // IP address
@@ -528,7 +535,7 @@ def on_mqtt_discovery_message(self, topic: str, payload: dict, qos: int = None,
# if device is unknown, add it to dict
if tasmota_topic not in self.tasmota_devices:
- self.logger.info(f"New device based on Discovery Message found.")
+ self.logger.info("New device based on Discovery Message found.")
self._add_new_device_to_tasmota_devices(tasmota_topic)
# process decoding message and set device to status 'discovered'
@@ -548,8 +555,8 @@ def on_mqtt_discovery_message(self, topic: str, payload: dict, qos: int = None,
self.logger.warning(f"Device {device_name} discovered, but FullTopic of device does not match plugin setting!")
# if zigbee bridge, process those
- if 'zigbee_bridge' in device_name.lower():
- self.logger.info(f"Zigbee_Bridge discovered")
+ if any(x in device_name.lower() for x in self.ZIGBEE_BRIDGE_IDENTIFIER) or tasmota_topic in self.tasmota_zb_bridge_topics:
+ self.logger.info(f"Zigbee Bridge discovered as device {device_name}")
self.tasmota_devices[tasmota_topic]['zigbee']['status'] = 'discovered'
self._configure_zigbee_bridge_settings(tasmota_topic)
self._discover_zigbee_bridge_devices(tasmota_topic)
@@ -557,7 +564,7 @@ def on_mqtt_discovery_message(self, topic: str, payload: dict, qos: int = None,
elif msg_type == 'sensors':
"""
device_id = 2CF432CC2FC5
-
+
payload = {'sn': {'Time': '2022-11-19T13:35:59',
'ENERGY': {'TotalStartTime': '2019-12-23T17:02:03', 'Total': 85.314, 'Yesterday': 0.0,
'Today': 0.0, 'Power': 0, 'ApparentPower': 0, 'ReactivePower': 0, 'Factor': 0.0,
@@ -571,7 +578,7 @@ def on_mqtt_discovery_message(self, topic: str, payload: dict, qos: int = None,
return
if 'Time' in sensor_payload:
- sensor_payload.pop('Time')
+ del sensor_payload['Time']
# find matching tasmota_topic
tasmota_topic = None
@@ -586,10 +593,10 @@ def on_mqtt_discovery_message(self, topic: str, payload: dict, qos: int = None,
self._handle_sensor(tasmota_topic, '', sensor_payload)
except Exception as e:
- self.logger.exception(f"on_mqtt_discovery_message: Exception {e.__class__.__name__}: {e}")
+ self.logger.exception(f"Exception {e.__class__.__name__}: {e}")
return
- def on_mqtt_lwt_message(self, topic: str, payload: bool, qos: int = None, retain: bool = None) -> None:
+ def on_mqtt_lwt_message(self, topic: str, payload: bool, qos: int, retain: bool) -> None:
"""
Callback function to handle received lwt messages
@@ -601,12 +608,12 @@ def on_mqtt_lwt_message(self, topic: str, payload: bool, qos: int = None, retain
"""
try:
- self.logger.dbgmed(f"on_mqtt_lwt_message: topic {topic} = {payload}")
+ self.logger.dbgmed(f"topic {topic} = {payload}")
self._handle_retained_message(topic, retain)
try:
(topic_type, tasmota_topic, info_topic) = topic.split('/')
- self.logger.info(f"on_mqtt_lwt_message: topic_type={topic_type}, tasmota_topic={tasmota_topic}, info_topic={info_topic}, payload={payload}")
+ self.logger.info(f"topic_type={topic_type}, tasmota_topic={tasmota_topic}, info_topic={info_topic}, payload={payload}")
except ValueError:
self.logger.error(f"received topic {topic} is not in correct format.")
return
@@ -614,7 +621,7 @@ def on_mqtt_lwt_message(self, topic: str, payload: bool, qos: int = None, retain
self.logger.info(f"Received LWT Message for {tasmota_topic} with value={payload} and retain={retain}")
if payload:
if tasmota_topic not in self.tasmota_devices:
- self.logger.debug(f"New online device based on LWT Message discovered.")
+ self.logger.debug("New online device based on LWT Message discovered.")
self._handle_new_discovered_device(tasmota_topic)
self.tasmota_devices[tasmota_topic]['online_timeout'] = datetime.now() + timedelta(seconds=self.telemetry_period + 5)
@@ -623,10 +630,10 @@ def on_mqtt_lwt_message(self, topic: str, payload: bool, qos: int = None, retain
self._set_item_value(tasmota_topic, 'online', payload, info_topic)
except Exception as e:
- self.logger.exception(f"on_mqtt_lwt_message: Exception {e.__class__.__name__}: {e}")
+ self.logger.exception(f"Exception {e.__class__.__name__}: {e}")
return
- def on_mqtt_status0_message(self, topic: str, payload: dict, qos: int = None, retain: bool = None) -> None:
+ def on_mqtt_status0_message(self, topic: str, payload: dict, qos: int, retain: bool) -> None:
"""
Callback function to handle received messages
@@ -637,9 +644,9 @@ def on_mqtt_status0_message(self, topic: str, payload: dict, qos: int = None, re
"""
- """
- Example payload
-
+ """
+ Example payload
+
payload = {'Status': {'Module': 75, 'DeviceName': 'ZIGBEE_Bridge01', 'FriendlyName': ['SONOFF_ZB1'],
'Topic': 'SONOFF_ZB1', 'ButtonTopic': '0', 'Power': 0, 'PowerOnState': 3, 'LedState': 1,
'LedMask': 'FFFF', 'SaveData': 1, 'SaveState': 1, 'SwitchTopic': '0',
@@ -678,22 +685,22 @@ def on_mqtt_status0_message(self, topic: str, payload: dict, qos: int = None, re
'Wifi': {'AP': 1, 'SSId': 'WLAN-Access', 'BSSId': '38:10:D5:15:87:69', 'Channel': 1,
'Mode': '11n', 'RSSI': 50, 'Signal': -75, 'LinkCount': 1,
'Downtime': '0T00:00:03'}}}
-
+
"""
try:
- self.logger.dbgmed(f"on_mqtt_status0_message: topic {topic} = {payload}")
+ self.logger.dbgmed(f"topic {topic} = {payload}")
self._handle_retained_message(topic, retain)
try:
(topic_type, tasmota_topic, info_topic) = topic.split('/')
- self.logger.info(f"on_mqtt_status0_message: topic_type={topic_type}, tasmota_topic={tasmota_topic}, info_topic={info_topic}, payload={payload}")
+ self.logger.info(f"topic_type={topic_type}, tasmota_topic={tasmota_topic}, info_topic={info_topic}, payload={payload}")
except ValueError:
self.logger.error(f"received topic {topic} is not in correct format.")
return
if not isinstance(payload, dict):
- self.logger.debug(f'Payload not of type dict. Message will be discarded.')
+ self.logger.debug('Payload not of type dict. Message will be discarded.')
return
self.logger.info(f"Received Status0 Message for {tasmota_topic} with value={payload} and retain={retain}")
@@ -715,42 +722,43 @@ def on_mqtt_status0_message(self, topic: str, payload: dict, qos: int = None, re
pass
# IP Address
- ip = None
- ip_eth = None
try:
ip = payload['StatusNET']['IPAddress']
except KeyError:
- pass
+ ip = None
+
try:
- ip_eth = payload['StatusNET'].get('Ethernet', {}).get('IPAddress')
+ ip_eth = payload['StatusNET']['Ethernet']['IPAddress']
except KeyError:
- pass
+ ip_eth = None
+
+ if ip == '0.0.0.0' and ip_eth:
+ ip = ip_eth
if ip:
- if ip_eth and ip == '0.0.0.0':
- ip = ip_eth
self.tasmota_devices[tasmota_topic]['ip'] = ip
# Firmware
try:
self.tasmota_devices[tasmota_topic]['fw_ver'] = payload['StatusFWR']['Version'].split('(')[0]
- except KeyError:
+ except (TypeError, KeyError):
pass
# MAC
try:
self.tasmota_devices[tasmota_topic]['mac'] = payload['StatusNET']['Mac']
- except KeyError:
+ except (TypeError, KeyError):
pass
# Module No
try:
self.tasmota_devices[tasmota_topic]['template'] = payload['Status']['Module']
- except KeyError:
+ except (TypeError, KeyError):
pass
# get detailed status using payload['StatusSTS']
status_sts = payload.get('StatusSTS')
+ # make sure, that dict is not empty
if not status_sts and not isinstance(status_sts, dict):
return
@@ -763,7 +771,7 @@ def on_mqtt_status0_message(self, topic: str, payload: dict, qos: int = None, re
self._handle_power(tasmota_topic, info_topic, status_sts)
# Handling of RF messages
- if any(item.startswith("Rf") for item in status_sts.keys()):
+ if any(item.startswith("R") for item in status_sts.keys()):
self._handle_rf(tasmota_topic, info_topic, status_sts)
# Handling of Wi-Fi
@@ -776,14 +784,14 @@ def on_mqtt_status0_message(self, topic: str, payload: dict, qos: int = None, re
# Handling of UptimeSec
if 'UptimeSec' in status_sts:
- self.logger.info(f"Received Message contains UptimeSec information.")
+ self.logger.info("Received Message contains UptimeSec information.")
self._handle_uptime_sec(tasmota_topic, status_sts['UptimeSec'])
except Exception as e:
- self.logger.exception(f"on_mqtt_status0_message: Exception {e.__class__.__name__}: {e}")
+ self.logger.exception(f"Exception {e.__class__.__name__}: {e}")
return
- def on_mqtt_info_message(self, topic: str, payload: dict, qos: int = None, retain: bool = None) -> None:
+ def on_mqtt_info_message(self, topic: str, payload: dict, qos: int, retain: bool) -> None:
"""
Callback function to handle received messages
@@ -795,23 +803,23 @@ def on_mqtt_info_message(self, topic: str, payload: dict, qos: int = None, retai
"""
try:
- self.logger.dbgmed(f"on_mqtt_info_message: topic {topic} = {payload}")
+ self.logger.dbgmed(f"topic {topic} = {payload}")
self._handle_retained_message(topic, retain)
try:
(topic_type, tasmota_topic, info_topic) = topic.split('/')
- self.logger.info(f"on_mqtt_info_message: topic_type={topic_type}, tasmota_topic={tasmota_topic}, info_topic={info_topic}, payload={payload}")
+ self.logger.info(f"topic_type={topic_type}, tasmota_topic={tasmota_topic}, info_topic={info_topic}, payload={payload}")
except ValueError:
self.logger.error(f"received topic {topic} is not in correct format.")
return
if not isinstance(payload, dict):
- self.logger.debug(f'Payload not of type dict. Message will be discarded.')
+ self.logger.debug('Payload not of type dict. Message will be discarded.')
return
if info_topic == 'INFO1':
# payload={'Info1': {'Module': 'Sonoff Basic', 'Version': '11.0.0(tasmota)', 'FallbackTopic': 'cmnd/DVES_2EB8AE_fb/', 'GroupTopic': 'cmnd/tasmotas/'}}
- self.logger.debug(f"Received Message decoded as INFO1 message.")
+ self.logger.debug("Received Message decoded as INFO1 message.")
try:
self.tasmota_devices[tasmota_topic]['fw_ver'] = payload['Info1']['Version'].split('(')[0]
except KeyError:
@@ -823,7 +831,7 @@ def on_mqtt_info_message(self, topic: str, payload: dict, qos: int = None, retai
elif info_topic == 'INFO2':
# payload={'Info2': {'WebServerMode': 'Admin', 'Hostname': 'SONOFF-B1-6318', 'IPAddress': '192.168.2.25'}}
- self.logger.debug(f"Received Message decoded as INFO2 message.")
+ self.logger.debug("Received Message decoded as INFO2 message.")
try:
self.tasmota_devices[tasmota_topic]['ip'] = payload['Info2']['IPAddress']
except KeyError:
@@ -831,7 +839,7 @@ def on_mqtt_info_message(self, topic: str, payload: dict, qos: int = None, retai
elif info_topic == 'INFO3':
# payload={'Info3': {'RestartReason': 'Software/System restart', 'BootCount': 1395}}
- self.logger.debug(f"Received Message decoded as INFO3 message.")
+ self.logger.debug("Received Message decoded as INFO3 message.")
try:
restart_reason = payload['Info3']['RestartReason']
self.logger.info(f"Device {tasmota_topic} (IP={self.tasmota_devices[tasmota_topic]['ip']}) just startet. Reason={restart_reason}")
@@ -839,10 +847,10 @@ def on_mqtt_info_message(self, topic: str, payload: dict, qos: int = None, retai
pass
except Exception as e:
- self.logger.exception(f"on_mqtt_info_message: Exception {e.__class__.__name__}: {e}")
+ self.logger.exception(f"Exception {e.__class__.__name__}: {e}")
return
- def on_mqtt_message(self, topic: str, payload: dict, qos: int = None, retain: bool = None) -> None:
+ def on_mqtt_message(self, topic: str, payload: dict, qos: int, retain: bool) -> None:
"""
Callback function to handle received messages
@@ -854,18 +862,18 @@ def on_mqtt_message(self, topic: str, payload: dict, qos: int = None, retain: bo
"""
try:
- self.logger.dbgmed(f"on_mqtt_message: topic {topic} = {payload}")
+ self.logger.dbgmed(f"topic {topic} = {payload}")
self._handle_retained_message(topic, retain)
try:
(topic_type, tasmota_topic, info_topic) = topic.split('/')
- self.logger.info(f"on_mqtt_message: topic_type={topic_type}, tasmota_topic={tasmota_topic}, info_topic={info_topic}, payload={payload}")
+ self.logger.info(f"topic_type={topic_type}, tasmota_topic={tasmota_topic}, info_topic={info_topic}, payload={payload}")
except ValueError:
self.logger.error(f"received topic {topic} is not in correct format.")
return
if not isinstance(payload, dict):
- self.logger.debug(f'Payload not of type dict. Message will be discarded.')
+ self.logger.debug('Payload not of type dict. Message will be discarded.')
return
# handle unknown device
@@ -877,66 +885,67 @@ def on_mqtt_message(self, topic: str, payload: dict, qos: int = None, retain: bo
# Handling of TelePeriod
if 'TelePeriod' in payload:
- self.logger.info(f"Received Message decoded as teleperiod message.")
+ self.logger.info("Received Message decoded as teleperiod message.")
self._handle_teleperiod(tasmota_topic, payload['TelePeriod'])
+ # Handling of Module
elif 'Module' in payload:
- self.logger.info(f"Received Message decoded as Module message.")
+ self.logger.info("Received Message decoded as Module message.")
self._handle_module(tasmota_topic, payload['Module'])
# Handling of Light messages
elif any([i in payload for i in self.LIGHT_MSG]):
- self.logger.info(f"Received Message decoded as light message.")
+ self.logger.info("Received Message decoded as light message.")
self._handle_lights(tasmota_topic, info_topic, payload)
# Handling of Power messages
elif any(item.startswith("POWER") for item in payload.keys()):
- self.logger.info(f"Received Message decoded as power message.")
+ self.logger.info("Received Message decoded as power message.")
self._handle_power(tasmota_topic, info_topic, payload)
# Handling of RF messages payload={'Time': '2022-11-21T11:22:55', 'RfReceived': {'Sync': 10120, 'Low': 330, 'High': 980, 'Data': '3602B8', 'RfKey': 'None'}}
elif 'RfReceived' in payload:
- self.logger.info(f"Received Message decoded as RF message.")
+ self.logger.info("Received Message decoded as RF message.")
self._handle_rf(tasmota_topic, info_topic, payload['RfReceived'])
# Handling of Setting messages
elif next(iter(payload)).startswith("SetOption"):
# elif any(item.startswith("SetOption") for item in payload.keys()):
- self.logger.info(f"Received Message decoded as Tasmota Setting message.")
+ self.logger.info("Received Message decoded as Tasmota Setting message.")
self._handle_setting(tasmota_topic, payload)
# Handling of Zigbee Bridge Config messages
elif 'ZbConfig' in payload:
- self.logger.info(f"Received Message decoded as Zigbee Config message.")
+ self.logger.info("Received Message decoded as Zigbee Config message.")
self._handle_zbconfig(tasmota_topic, payload['ZbConfig'])
# Handling of Zigbee Bridge Status messages
elif any(item.startswith("ZbStatus") for item in payload.keys()):
- self.logger.info(f"Received Message decoded as Zigbee ZbStatus message.")
+ self.logger.info("Received Message decoded as Zigbee ZbStatus message.")
self._handle_zbstatus(tasmota_topic, payload)
# Handling of Wi-Fi
if 'Wifi' in payload:
- self.logger.info(f"Received Message contains Wifi information.")
+ self.logger.info("Received Message contains Wifi information.")
self._handle_wifi(tasmota_topic, payload['Wifi'])
# Handling of Uptime
if 'Uptime' in payload:
- self.logger.info(f"Received Message contains Uptime information.")
+ self.logger.info("Received Message contains Uptime information.")
self._handle_uptime(tasmota_topic, payload['Uptime'])
# Handling of UptimeSec
if 'UptimeSec' in payload:
- self.logger.info(f"Received Message contains UptimeSec information.")
+ self.logger.info("Received Message contains UptimeSec information.")
self._handle_uptime_sec(tasmota_topic, payload['UptimeSec'])
# Handling of Button messages
if any(item.startswith("Button") for item in payload.keys()):
- self.logger.info(f"Received Message decoded as button message.")
+ self.logger.info("Received Message decoded as button message.")
self._handle_button(tasmota_topic, info_topic, payload)
elif info_topic == 'SENSOR':
- self.logger.info(f"Received Message contains sensor information.")
+ self.logger.info("Received Message contains sensor information.")
self._handle_sensor(tasmota_topic, info_topic, payload)
else:
@@ -949,10 +958,10 @@ def on_mqtt_message(self, topic: str, payload: dict, qos: int = None, retain: bo
self._set_item_value(tasmota_topic, 'online', True, info_topic)
except Exception as e:
- self.logger.exception(f"on_mqtt_message: Exception {e.__class__.__name__}: {e}")
+ self.logger.exception(f"Exception {e.__class__.__name__}: {e}")
return
- def on_mqtt_power_message(self, topic: str, payload: bool, qos: int = None, retain: bool = None) -> None:
+ def on_mqtt_power_message(self, topic: str, payload: bool, qos: int, retain: bool) -> None:
"""
Callback function to handle received power messages
@@ -964,12 +973,12 @@ def on_mqtt_power_message(self, topic: str, payload: bool, qos: int = None, ret
"""
try:
- self.logger.dbgmed(f"on_mqtt_power_message: topic {topic} = {payload}")
+ self.logger.dbgmed(f"topic {topic} = {payload}")
self._handle_retained_message(topic, retain)
try:
(topic_type, tasmota_topic, info_topic) = topic.split('/')
- self.logger.info(f"on_mqtt_power_message: topic_type={topic_type}, tasmota_topic={tasmota_topic}, info_topic={info_topic}, payload={payload}")
+ self.logger.info(f"topic_type={topic_type}, tasmota_topic={tasmota_topic}, info_topic={info_topic}, payload={payload}")
except ValueError:
self.logger.error(f"received topic {topic} is not in correct format.")
return
@@ -986,7 +995,7 @@ def on_mqtt_power_message(self, topic: str, payload: bool, qos: int = None, ret
self.tasmota_devices[tasmota_topic]['relais'][info_topic] = payload
except Exception as e:
- self.logger.exception(f"on_mqtt_power_message: Exception {e.__class__.__name__}: {e}")
+ self.logger.exception(f"Exception {e.__class__.__name__}: {e}")
return
############################################################
@@ -1003,12 +1012,12 @@ def _handle_sensor(self, device: str, function: str, payload: dict) -> None:
"""
# Handling of Zigbee Device Messages
if 'ZbReceived' in payload:
- self.logger.info(f"Received Message decoded as Zigbee Sensor message.")
+ self.logger.info("Received Message decoded as Zigbee Sensor message.")
self._handle_sensor_zigbee(device, function, payload['ZbReceived'])
# Handling of Energy Sensors
elif 'ENERGY' in payload:
- self.logger.info(f"Received Message decoded as Energy Sensor message.")
+ self.logger.info("Received Message decoded as Energy Sensor message.")
self._handle_sensor_energy(device, function, payload['ENERGY'])
# Handling of Environmental Sensors
@@ -1017,18 +1026,18 @@ def _handle_sensor(self, device: str, function: str, payload: dict) -> None:
# Handling of Analog Sensors
elif 'ANALOG' in payload:
- self.logger.info(f"Received Message decoded as ANALOG Sensor message.")
+ self.logger.info("Received Message decoded as ANALOG Sensor message.")
self._handle_sensor_analog(device, function, payload['ANALOG'])
# Handling of Sensors of ESP32
elif 'ESP32' in payload:
- self.logger.info(f"Received Message decoded as ESP32 Sensor message.")
+ self.logger.info("Received Message decoded as ESP32 Sensor message.")
self._handle_sensor_esp32(device, function, payload['ESP32'])
# Handling of any other Sensor e.g. all SML devices
else:
if len(payload) == 2 and isinstance(payload[list(payload.keys())[1]], dict): # wenn payload 2 Einträge und der zweite Eintrag vom Typ dict
- self.logger.info(f"Received Message decoded as other Sensor message (e.g. smartmeter).")
+ self.logger.info("Received Message decoded as other Sensor message (e.g. smartmeter).")
sensor = list(payload.keys())[1]
self._handle_sensor_other(device, sensor, function, payload[sensor])
@@ -1067,6 +1076,8 @@ def _handle_sensor_zigbee(self, device: str, function: str, payload: dict) -> No
# Korrektur des LastSeenEpoch von Timestamp zu datetime
if 'lastseenepoch' in zigbee_device_dict:
zigbee_device_dict.update({'lastseenepoch': datetime.fromtimestamp(zigbee_device_dict['lastseenepoch'])})
+ else:
+ zigbee_device_dict.update({'lastseenepoch': self.shtime.now()})
if 'batterylastseenepoch' in zigbee_device_dict:
zigbee_device_dict.update({'batterylastseenepoch': datetime.fromtimestamp(zigbee_device_dict['batterylastseenepoch'])})
@@ -1242,7 +1253,7 @@ def _handle_power(self, device: str, function: str, payload: dict) -> None:
:param payload: MQTT message payload
"""
- # payload = {"Time": "2022-11-21T12:56:34", "Uptime": "0T00:00:11", "UptimeSec": 11, "Heap": 27, "SleepMode": "Dynamic", "Sleep": 50, "LoadAvg": 19, "MqttCount": 0, "POWER1": "OFF", "POWER2": "OFF", "POWER3": "OFF", "POWER4": "OFF", "Wifi": {"AP": 1, "SSId": "WLAN-Access", "BSSId": "38:10:D5:15:87:69", "Channel": 1, "Mode": "11n", "RSSI": 82, "Signal": -59, "LinkCount": 1, "Downtime": "0T00:00:03"}}
+ # payload = {"Time": "2022-11-21T12:56:34", "Uptime": "0T00:00:11", "UptimeSec": 11, "Heap": 27, "SleepMode": "Dynamic", "Sleep": 50, "LoadAvg": 19, "MqttCount": 0, "POWER1": "OF", "POWER2": "OF", "POWER3": "OF", "POWER4": "OF", "Wifi": {"AP": 1, "SSId": "WLAN-Access", "BSSId": "38:10:D5:15:87:69", "Channel": 1, "Mode": "11n", "RSSI": 82, "Signal": -59, "LinkCount": 1, "Downtime": "0T00:00:03"}}
power_dict = {key: val for key, val in payload.items() if key.startswith('POWER')}
self.tasmota_devices[device]['relais'].update(power_dict)
@@ -1267,7 +1278,7 @@ def _handle_button(self, device: str, function: str, payload: dict) -> None:
for button in button_dict:
button_index = 1 if len(button) == 6 else str(button[6:])
item_button = f'button.{button_index}'
- self._set_item_value(device, item_button, button_dict[button].get('Action',None), function)
+ self._set_item_value(device, item_button, button_dict[button].get('Action'), function)
def _handle_module(self, device: str, payload: dict) -> None:
"""
@@ -1294,7 +1305,7 @@ def _handle_rf(self, device: str, function: str, payload: dict) -> None:
# payload = {'Sync': 10120, 'Low': 330, 'High': 980, 'Data': '3602B8', 'RfKey': 'None'}
- self.logger.info(f"Received Message decoded as RF message.")
+ self.logger.info("Received Message decoded as RF message.")
self.tasmota_devices[device]['rf']['rf_received'] = payload
self._set_item_value(device, 'rf_recv', payload['Data'], function)
@@ -1344,7 +1355,7 @@ def _handle_zbstatus1(self, device: str, zbstatus1: list) -> None:
"""
"""
- zbstatus1 = [{'Device': '0x676D', 'Name': 'SNZB-02_01'},
+ zbstatus1 = [{'Device': '0x676D', 'Name': 'SNZB-02_01'},
{'Device': '0xD4F3', 'Name': 'Fenster_01'}
]
"""
@@ -1357,9 +1368,8 @@ def _handle_zbstatus1(self, device: str, zbstatus1: list) -> None:
if zigbee_device != '0x0000' and zigbee_device not in self.tasmota_zigbee_devices:
self.logger.info(f"New Zigbee Device '{zigbee_device}'based on 'ZbStatus1'-Message from {device} discovered")
self.tasmota_zigbee_devices[zigbee_device] = {}
-
- # request detailed information of all discovered zigbee devices
- self._poll_zigbee_devices(device)
+ # request detailed information of all discovered zigbee devices
+ self._poll_zigbee_device(zigbee_device, device)
def _handle_zbstatus23(self, device: str, zbstatus23: dict) -> None:
"""
@@ -1376,10 +1386,10 @@ def _handle_zbstatus23(self, device: str, zbstatus23: dict) -> None:
'Config': ['A01'], 'ZoneStatus': 29697, 'Reachable': True, 'BatteryPercentage': 100,
'BatteryLastSeenEpoch': 1668953504, 'LastSeen': 238, 'LastSeenEpoch': 1668953504,
'LinkQuality': 81}]
-
+
zbstatus23 = [{'Device': '0x676D', 'Name': 'SNZB-02_01', 'IEEEAddr': '0x00124B00231E45B8',
- 'ModelId': 'TH01', 'Manufacturer': 'eWeLink', 'Endpoints': [1], 'Config': ['T01'],
- 'Temperature': 19.27, 'Humidity': 58.12, 'Reachable': True, 'BatteryPercentage': 73,
+ 'ModelId': 'TH01', 'Manufacturer': 'eWeLink', 'Endpoints': [1], 'Config': ['T01'],
+ 'Temperature': 19.27, 'Humidity': 58.12, 'Reachable': True, 'BatteryPercentage': 73,
'BatteryLastSeenEpoch': 1668953064, 'LastSeen': 610, 'LastSeenEpoch': 1668953064, 'LinkQuality': 66}]
zbstatus23 = [{'Device': '0x0A22', 'IEEEAddr': '0xF0D1B800001571C5', 'ModelId': 'CLA60 RGBW Z3',
@@ -1429,7 +1439,7 @@ def _handle_setting(self, device: str, payload: dict) -> None:
if self.tasmota_devices[device]['zigbee']['setting'] == self.ZIGBEE_BRIDGE_DEFAULT_OPTIONS:
self.tasmota_devices[device]['zigbee']['status'] = 'set'
- self.logger.info(f'_handle_setting: Setting of Tasmota Zigbee Bridge successful.')
+ self.logger.info('_handle_setting: Setting of Tasmota Zigbee Bridge successful.')
def _handle_teleperiod(self, tasmota_topic: str, teleperiod: dict) -> None:
@@ -1450,7 +1460,7 @@ def _handle_uptime_sec(self, tasmota_topic: str, uptime_sec: int) -> None:
############################################################
def add_tasmota_subscriptions(self):
- self.logger.info(f"Further tasmota_subscriptions for regular/cyclic messages will be added")
+ self.logger.info("Further tasmota_subscriptions for regular/cyclic messages will be added")
for detail in ('STATE', 'SENSOR', 'RESULT'):
self.add_tasmota_subscription('tele', '+', detail, 'dict', callback=self.on_mqtt_message)
@@ -1474,7 +1484,7 @@ def check_online_status(self):
else:
self.logger.debug(f'check_online_status: Checking online status of {tasmota_topic} successful')
- def add_tasmota_subscription(self, prefix: str, topic: str, detail: str, payload_type: str, bool_values: list = None, item: Item = None, callback=None) -> None:
+ def add_tasmota_subscription(self, prefix: str, topic: str, detail: str, payload_type: str, bool_values: list|None = None, item: Item|None = None, callback=None) -> None:
"""
build the topic in Tasmota style and add the subscription to mqtt
@@ -1493,7 +1503,7 @@ def add_tasmota_subscription(self, prefix: str, topic: str, detail: str, payload
tpc += detail
self.add_subscription(tpc, payload_type, bool_values=bool_values, callback=callback)
- def publish_tasmota_topic(self, prefix: str, topic: str, detail: str, payload, item: Item = None, qos: int = None, retain: bool = False, bool_values: list = None) -> None:
+ def publish_tasmota_topic(self, prefix: str, topic: str, detail: str, payload=None, item: Item|None = None, qos: int|None = None, retain: bool = False, bool_values: list|None = None) -> None:
"""
build the topic in Tasmota style and publish to mqtt
@@ -1519,9 +1529,9 @@ def interview_all_devices(self):
Interview known Tasmota Devices (defined in item.yaml and self discovered)
"""
- self.logger.info(f"Interview of all known tasmota devices started.")
+ self.logger.info("Interview of all known tasmota devices started.")
- for device in self.tasmota_device():
+ for device in self.get_tasmota_device_list():
self.logger.debug(f"Interview {device}.")
self._interview_device(device)
self.logger.debug(f"Set Telemetry period for {device}.")
@@ -1533,8 +1543,7 @@ def clear_retained_messages(self, retained_msg=None):
"""
if retained_msg:
- retained_msg_list = list()
- retained_msg_list.append(retained_msg)
+ retained_msg_list = [retained_msg]
else:
retained_msg_list = self.topics_of_retained_messages
@@ -1542,7 +1551,7 @@ def clear_retained_messages(self, retained_msg=None):
self.logger.info(f"Clearing retained message for topic={topic}")
self.publish_topic(topic=topic, payload="", retain=True)
- def _interview_device(self, topic: str) -> None:
+ def _interview_device(self, topic: str) -> bool:
"""
ask for status info of each known tasmota_topic
@@ -1551,6 +1560,7 @@ def _interview_device(self, topic: str) -> None:
# self.logger.debug(f"run: publishing 'cmnd/{topic}/Status0'")
self.publish_tasmota_topic('cmnd', topic, 'Status0', '')
+ return True
# self.logger.debug(f"run: publishing 'cmnd/{topic}/State'")
# self.publish_tasmota_topic('cmnd', topic, 'State', '')
@@ -1558,7 +1568,7 @@ def _interview_device(self, topic: str) -> None:
# self.logger.debug(f"run: publishing 'cmnd/{topic}/Module'")
# self.publish_tasmota_topic('cmnd', topic, 'Module', '')
- def _set_telemetry_period(self, topic: str) -> None:
+ def _set_telemetry_period(self, topic: str):
"""
sets telemetry period for given topic/device
@@ -1605,9 +1615,9 @@ def _set_item_value(self, tasmota_topic: str, item_type: str, value, info_topic:
elif tasmota_rf_key_param.lower() == 'false':
value = True
elif tasmota_rf_key_param.lower() == 'toggle':
- value = not(item())
+ value = not item()
else:
- self.logger.warning(f"Parameter of tasmota_rf_key unknown, Need to be 'True', 'False', 'Toggle'")
+ self.logger.warning("Parameter of tasmota_rf_key unknown, Need to be 'True', 'False', 'Toggle'")
return
# set item value
@@ -1695,17 +1705,66 @@ def _get_device_dict_2_template():
# Zigbee
############################################################
- def _poll_zigbee_devices(self, device: str) -> None:
+ def _poll_zigbee_devices(self, zb_bridge: str = '') -> bool:
"""
Polls information of all discovered zigbee devices from dedicated Zigbee bridge
- :param device: Zigbee bridge, where all Zigbee Devices shall be polled (equal to tasmota_topic)
+ :param zb_bridge: Zigbee bridge, where all Zigbee Devices shall be polled (equal to tasmota_topic)
+
+ """
+ if not zb_bridge:
+ zb_bridge = self.get_tasmota_device_w_zigbee()
+
+ if not zb_bridge:
+ return False
+
+ result = True
+ self.logger.info(f"Polling information of all discovered Zigbee devices for Zigbee-Bridge {zb_bridge}")
+ for zb_device in self.tasmota_zigbee_devices:
+ res = self._poll_zigbee_device(zb_device, zb_bridge)
+ self.logger.info(f"poll of {zb_device}: {res}")
+ if not res:
+ result = False
+
+ return result
+
+ def _poll_zigbee_device(self, zb_device: str, zb_bridge: str = '') -> bool:
+ """
+ Polls information of zigbee devices from dedicated Zigbee bridge
+
+ :param zb_bridge: Zigbee bridge, where Zigbee Devices is linked to
+ :param zb_device: Zigbee Device to be polled
"""
- self.logger.info(f"_poll_zigbee_devices: Polling information of all discovered Zigbee devices for zigbee_bridge {device}")
- for zigbee_device in self.tasmota_zigbee_devices:
- # self.logger.debug(f"_poll_zigbee_devices: publishing 'cmnd/{device}/ZbStatus3 {zigbee_device}'")
- self.publish_tasmota_topic('cmnd', device, 'ZbStatus3', zigbee_device)
+
+ if not zb_bridge:
+ zb_bridge = self.get_tasmota_device_w_zigbee()
+
+ if not zb_bridge:
+ return False
+
+ self.logger.info(f"_poll_zigbee_device: Polling information from {zb_device} via Zigbee-Bridge {zb_bridge}")
+ self.publish_tasmota_topic('cmnd', zb_bridge, 'ZbStatus3', zb_device)
+ return True
+
+ def _ping_zigbee_device(self, zb_device: str, zb_bridge: str = '') -> bool:
+ """
+ Ping zigbee devices from dedicated Zigbee bridge
+
+ :param zb_bridge: Zigbee bridge, where Zigbee Devices is linked to
+ :param zb_device: Zigbee Device to be polled
+
+ """
+
+ if not zb_bridge:
+ zb_bridge = self.get_tasmota_device_w_zigbee()
+
+ if not zb_bridge:
+ return False
+
+ self.logger.info(f"_ping_zigbee_device: Ping {zb_device} via Zigbee-Bridge {zb_bridge}")
+ self.publish_tasmota_topic('cmnd', zb_bridge, 'ZbPing', zb_device)
+ return True
def _configure_zigbee_bridge_settings(self, device: str) -> None:
"""
@@ -1762,78 +1821,112 @@ def _handle_retained_message(self, topic: str, retain: bool) -> None:
def log_level(self):
return self.logger.getEffectiveLevel()
+ @property
def retained_msg_count(self):
- return self._broker.retained_messages
+ return self._broker['retained_messages']
- def tasmota_device(self):
+ def get_tasmota_device_list(self):
return list(self.tasmota_devices.keys())
- def has_zigbee(self):
+ def get_tasmota_device_w_zigbee(self) -> str:
for tasmota_topic in self.tasmota_devices:
if self.tasmota_devices[tasmota_topic]['zigbee']:
- return True
- return False
+ return tasmota_topic
+ return ''
+ def _has_capability(self, func, tasmota_topic: str = ''):
+ """
+ Checks if any Tasmota device has a certain capability.
- def has_lights(self):
- for tasmota_topic in self.tasmota_devices:
- if self.tasmota_devices[tasmota_topic]['lights']:
- return True
- return False
+ Args:
+ tasmota_topic: Optional Tasmota topic to check specifically.
- def has_rf(self):
- for tasmota_topic in self.tasmota_devices:
- if self.tasmota_devices[tasmota_topic]['rf']:
- return True
- return False
+ Returns:
+ True if any Tasmota device has Zigbee capabilities, False otherwise.
+ """
- def has_relais(self):
- for tasmota_topic in self.tasmota_devices:
- if self.tasmota_devices[tasmota_topic]['relais']:
- return True
- return False
+ if tasmota_topic and self.tasmota_devices.get(tasmota_topic, {}).get(func, False):
+ return True
- def has_button(self):
- for tasmota_topic in self.tasmota_devices:
- if self.tasmota_devices[tasmota_topic]['button']:
- return True
- return False
+ return any(device.get(func, False) for device in self.tasmota_devices.values())
- def has_energy_sensor(self):
- for tasmota_topic in self.tasmota_devices:
- if 'ENERGY' in self.tasmota_devices[tasmota_topic]['sensors']:
- return True
- return False
+ def has_zigbee(self, tasmota_topic: str = ''):
+ return self._has_capability('zigbee', tasmota_topic)
- def has_env_sensor(self):
- for tasmota_topic in self.tasmota_devices:
- if any([i in self.tasmota_devices[tasmota_topic]['sensors'] for i in self.ENV_SENSOR]):
- return True
- return False
+ def has_lights(self, tasmota_topic: str = ''):
+ return self._has_capability('lights', tasmota_topic)
- def has_ds18b20_sensor(self):
- for tasmota_topic in self.tasmota_devices:
- if 'DS18B20' in self.tasmota_devices[tasmota_topic]['sensors']:
- return True
- return False
+ def has_rf(self, tasmota_topic: str = ''):
+ return self._has_capability('rf', tasmota_topic)
- def has_am2301_sensor(self):
- for tasmota_topic in self.tasmota_devices:
- if 'AM2301' in self.tasmota_devices[tasmota_topic]['sensors']:
- return True
- return False
+ def has_relais(self, tasmota_topic: str = ''):
+ return self._has_capability('relais', tasmota_topic)
- def has_sht3x_sensor(self):
- for tasmota_topic in self.tasmota_devices:
- if 'SHT3X' in self.tasmota_devices[tasmota_topic]['sensors']:
- return True
- return False
+ def has_button(self, tasmota_topic: str = ''):
+ return self._has_capability('button', tasmota_topic)
- def has_other_sensor(self):
- for tasmota_topic in self.tasmota_devices:
- for sensor in self.tasmota_devices[tasmota_topic]['sensors']:
+ def _has_sensor(self, sensor: str, tasmota_topic: str = ''):
+ """
+ Checks if any Tasmota device has a sensor.
+
+ Args:
+ tasmota_topic: Optional Tasmota topic to check specifically.
+
+ Returns:
+ True if any Tasmota device has a sensor, False otherwise.
+ """
+
+ if tasmota_topic:
+ return sensor in self.tasmota_devices.get(tasmota_topic, {}).get('sensors', {})
+
+ return any(sensor in device.get('sensors', {}) for device in self.tasmota_devices.values())
+
+ def has_energy_sensor(self, tasmota_topic: str = ''):
+ return self._has_sensor('ENERGY', tasmota_topic)
+
+ def has_env_sensor(self, tasmota_topic: str = ''):
+ """
+ Checks if any Tasmota device has an environmental sensor.
+
+ Args:
+ tasmota_topic: Optional Tasmota topic to check specifically.
+
+ Returns:
+ True if any Tasmota device has an environmental sensor, False otherwise.
+ """
+
+ if tasmota_topic:
+ return any(sensor in self.ENV_SENSOR for sensor in self.tasmota_devices.get(tasmota_topic, {}).get('sensors', []))
+
+ return any(any(sensor in self.ENV_SENSOR for sensor in device.get('sensors', [])) for device in self.tasmota_devices.values())
+
+ def has_ds18b20_sensor(self, tasmota_topic: str = ''):
+ return self._has_sensor('DS18B20', tasmota_topic)
+
+ def has_am2301_sensor(self, tasmota_topic: str = ''):
+ return self._has_sensor('AM2301', tasmota_topic)
+
+ def has_sht3x_sensor(self, tasmota_topic: str = ''):
+ return self._has_sensor('SHT3X', tasmota_topic)
+
+ def has_other_sensor(self, tasmota_topic: str = ''):
+ """
+ Checks if any Tasmota device has sensors other than those defined in self.SENSORS.
+
+ Args:
+ tasmota_topic: Optional Tasmota topic to check specifically.
+
+ Returns:
+ True if any device has sensors not in self.SENSORS, False otherwise.
+ """
+
+ if tasmota_topic:
+ for sensor in self.tasmota_devices.get(tasmota_topic, {}).get('sensors', []):
if sensor not in self.SENSORS:
return True
- return False
+
+ return any(any(sensor not in self.SENSORS for sensor in device.get('sensors', []))
+ for device in self.tasmota_devices.values())
+
##################################################################
# Utilities
diff --git a/tasmota/locale.yaml b/tasmota/locale.yaml
old mode 100755
new mode 100644
diff --git a/tasmota/plugin.yaml b/tasmota/plugin.yaml
index c154faea9..afb904f5a 100644
--- a/tasmota/plugin.yaml
+++ b/tasmota/plugin.yaml
@@ -12,8 +12,8 @@ plugin:
documentation: http://smarthomeng.de/user/plugins/tasmota/user_doc.html
support: https://knx-user-forum.de/forum/supportforen/smarthome-py/1520293-support-thread-für-das-tasmota-plugin
- version: 1.5.2 # Plugin version
- sh_minversion: '1.9.3' # minimum shNG version to use this plugin
+ version: 1.6.0 # Plugin version
+ sh_minversion: 1.10.0.3 # minimum shNG version to use this plugin
# sh_maxversion: # maximum shNG version to use this plugin (leave empty if latest)
# py_minversion: # minimum Python version to use for this plugin
multi_instance: True # plugin supports multi instance
@@ -38,7 +38,6 @@ parameters:
de: 'Zeitabstand in Sekunden in dem die Tasmota Devices Telemetrie Daten senden sollen'
en: 'Timeperiod in seconds in which Tasmota devices shall send telemetry data'
-
item_attributes:
tasmota_topic:
type: str
@@ -128,5 +127,3 @@ item_structs: NONE
plugin_functions: NONE
logic_parameters: NONE
-
-
diff --git a/tasmota/user_doc.rst b/tasmota/user_doc.rst
old mode 100755
new mode 100644
index 58ccec3cf..e1c2152c3
--- a/tasmota/user_doc.rst
+++ b/tasmota/user_doc.rst
@@ -60,6 +60,15 @@ folgenden Beispiel gezeigt:
tasmota_zb_device: snzb02_01
tasmota_zb_attr: Temperature
+Das Plugin versucht eine ZigBee-Bridge automatisch zu erkennen. Zudem kann diese auch per Attribut dediziert definiert werden:
+
+.. code-block:: yaml
+
+ temp:
+ type: num
+ tasmota_topic: ZB-GW03_01
+ tasmota_zb_device: bridge
+
Für die Nutzung von SML Devices über ein Tasmota-Gerät müssen in dem entsprechenden Item die drei Attribute
``tasmota_topic``, ``tasmota_sml_device`` und ``tasmota_sml_attr`` konfiguriert werden, wie im
folgenden Beispiel gezeigt:
@@ -147,7 +156,7 @@ Die folgenden Attribute (Werte für das Item-Attribut ``tasmota-attr``) sind bis
* "rf_send": Zu sendende RF Daten bei Tasmota Device mit RF Sendemöglichkeit (SONOFF RF Bridge) -> dict {'RfSync': 12220, 'RfLow': 440, 'RfHigh': 1210, 'RfCode':'#F06104'}, r/w
* "rf_key_send": Zu sendender RF-Key Tasmota Device mit RF Sendemöglichkeit (SONOFF RF Bridge) -> num [1-16], r/w
* "rf_key_recv": Zu empfangender RF-Key Tasmota Device mit RF Sendemöglichkeit (SONOFF RF Bridge) -> num [1-16], r/w
- * rf_key: 'RF Key'
+ * "rf_key": RF Key
* "zb_permit_join": Schaltet das Pairing an der ZigBee Bridge ein/aus -> bool, r/w
* "zb_forget": Löscht das Zigbee-Gerät aus dem Item Wert aus der Liste bekannter Geräte in der Zigbee-Bridge -> str, r/w
* "zb_ping": Sendet ein Ping zum Zigbee-Gerät aus dem Item Wert -> str, r/w
diff --git a/tasmota/user_doc/assets/webif_tab1.jpg b/tasmota/user_doc/assets/webif_tab1.jpg
old mode 100755
new mode 100644
diff --git a/tasmota/user_doc/assets/webif_tab2.jpg b/tasmota/user_doc/assets/webif_tab2.jpg
old mode 100755
new mode 100644
diff --git a/tasmota/user_doc/assets/webif_tab3.jpg b/tasmota/user_doc/assets/webif_tab3.jpg
old mode 100755
new mode 100644
diff --git a/tasmota/user_doc/assets/webif_tab4.jpg b/tasmota/user_doc/assets/webif_tab4.jpg
old mode 100755
new mode 100644
diff --git a/tasmota/user_doc/assets/webif_tab5.jpg b/tasmota/user_doc/assets/webif_tab5.jpg
old mode 100755
new mode 100644
diff --git a/tasmota/user_doc/assets/webif_tab6.jpg b/tasmota/user_doc/assets/webif_tab6.jpg
old mode 100755
new mode 100644
diff --git a/tasmota/webif/__init__.py b/tasmota/webif/__init__.py
old mode 100755
new mode 100644
index 893d51ce3..49ad9d31e
--- a/tasmota/webif/__init__.py
+++ b/tasmota/webif/__init__.py
@@ -66,23 +66,19 @@ def index(self, reload=None):
"""
self.plugin.get_broker_info()
- pagelength = self.plugin.get_parameter_value('webif_pagelength')
tmpl = self.tplenv.get_template('index.html')
- items = self.plugin.get_item_list()
-
return tmpl.render(p=self.plugin,
- webif_pagelength=pagelength,
- items=items,
- item_count=len(items),
- plugin_shortname=self.plugin.get_shortname(),
- plugin_version=self.plugin.get_version(),
- plugin_info=self.plugin.get_info(),
+ webif_pagelength=self.plugin.get_parameter_value('webif_pagelength'),
+ item_count=len(self.plugin.get_item_list()),
+ zigbee = True if self.plugin.tasmota_zigbee_devices else False,
+ broker_config = self.plugin.broker_config,
+ full_topic = self.plugin.full_topic,
maintenance=True if self.plugin.log_level == 10 else False,
)
@cherrypy.expose
- def get_data_html(self, dataSet=None):
+ def get_data_html(self, dataSet=None, params=None):
"""
Return data to update the webpage
@@ -91,37 +87,94 @@ def get_data_html(self, dataSet=None):
:param dataSet: Dataset for which the data should be returned (standard: None)
:return: dict with the data needed to update the web page.
"""
- if dataSet is None:
- # get the new data
+
+ self.logger.debug(f"get_data_html: {dataSet=}, {params=}")
+
+ data = dict()
+
+ if dataSet == "items_info":
+ data[dataSet] = {}
+ for item in self.plugin.get_item_list():
+ item_data = {
+ 'value': item.property.value,
+ 'type': item.property.type,
+ 'topic': self.plugin.get_iattr_value(item.conf, 'tasmota_topic'),
+ 'relais': self._get_relay_value(item),
+ 'last_update': item.property.last_update.strftime('%d.%m.%Y %H:%M:%S'),
+ 'last_change': item.property.last_change.strftime('%d.%m.%Y %H:%M:%S'),
+ }
+ data['items_info'][item.property.path] = item_data
+
+ elif dataSet == "devices_info":
+ data[dataSet] = {}
+ for device_name, device_data in self.plugin.tasmota_devices.items():
+ device_data = device_data.copy()
+ device_data.pop('discovery_config', None)
+ data[dataSet][device_name] = device_data
+
+ elif dataSet == "zigbee_info":
+ data[dataSet] = self.plugin.tasmota_zigbee_devices.copy()
+
+ elif dataSet == "broker_info":
self.plugin.get_broker_info()
- data = dict()
- data['broker_info'] = self.plugin._broker
- data['broker_uptime'] = self.plugin.broker_uptime()
+ data[dataSet] = self.plugin._broker.copy()
+ data[dataSet]['broker_uptime'] = self.plugin.broker_uptime()
+
+ elif dataSet == "details_info":
+ data['devices_info'] = {}
+ for device_name, device_data in self.plugin.tasmota_devices.items():
+ device_data = device_data.copy()
+ device_data.pop('discovery_config', None)
+ data['devices_info'][device_name] = device_data
+ data['zigbee_info'] = self.plugin.tasmota_zigbee_devices.copy()
+
+ # return it as json the web page
+ try:
+ return json.dumps(data, default=str)
+ except Exception as e:
+ self.logger.error("get_data_html exception: {}".format(e))
+ return {}
- data['item_values'] = {}
- for item in self.plugin.get_item_list():
- data['item_values'][item.property.path] = {}
- data['item_values'][item.property.path]['value'] = item.property.value
- data['item_values'][item.property.path]['last_update'] = item.property.last_update.strftime('%d.%m.%Y %H:%M:%S')
- data['item_values'][item.property.path]['last_change'] = item.property.last_change.strftime('%d.%m.%Y %H:%M:%S')
-
- data['device_values'] = {}
- for device in self.plugin.tasmota_devices:
- data['device_values'][device] = {}
- data['device_values'][device]['online'] = self.plugin.tasmota_devices[device].get('online', '-')
- data['device_values'][device]['uptime'] = self.plugin.tasmota_devices[device].get('uptime', '-')
- data['device_values'][device]['fw_ver'] = self.plugin.tasmota_devices[device].get('fw_ver', '-')
- data['device_values'][device]['wifi_signal'] = self.plugin.tasmota_devices[device].get('wifi_signal', '-')
- data['device_values'][device]['sensors'] = self.plugin.tasmota_devices[device].get('sensors', '-')
- data['device_values'][device]['lights'] = self.plugin.tasmota_devices[device].get('lights', '-')
- data['device_values'][device]['rf'] = self.plugin.tasmota_devices[device].get('rf', '-')
-
- data['tasmota_zigbee_devices'] = self.plugin.tasmota_zigbee_devices
-
- # return it as json the web page
- try:
- return json.dumps(data, default=str)
- except Exception as e:
- self.logger.error("get_data_html exception: {}".format(e))
- return {}
- return
+
+ @cherrypy.expose
+ def submit(self, cmd=None, params=None):
+
+ self.logger.debug(f"submit: {cmd=}, {params=}")
+ result = None
+
+ if cmd == "zbstatus":
+ result = self.plugin._poll_zigbee_devices()
+
+ elif cmd == "tasmota_status":
+ result = self.plugin._interview_device(params)
+
+ elif cmd == "zb_ping":
+ result = self.plugin._poll_zigbee_device(params)
+
+ self.logger.debug(f"submit: {cmd=}, {params=} --> {result=}")
+
+ if result is not None:
+ # JSON zurücksenden
+ cherrypy.response.headers['Content-Type'] = 'application/json'
+ self.logger.debug(f"Result for web interface: {result}")
+ return json.dumps(result).encode('utf-8')
+
+ def _get_relay_value(self, item):
+ """
+ Determines the relay value based on item configuration.
+
+ Args:
+ item: The item object containing configuration data.
+ Returns:
+ The relay value as a string.
+ """
+
+ relay = self.plugin.get_iattr_value(item.conf, 'tasmota_relay')
+ if relay in ['1', '2', '3', '4', '5', '6', '7', '8']:
+ return relay
+
+ if self.plugin.get_iattr_value(item.conf, 'tasmota_attr') == 'relay':
+ return "1"
+
+ return "-"
+
\ No newline at end of file
diff --git a/tasmota/webif/static/img/plugin_logo.svg b/tasmota/webif/static/img/plugin_logo.svg
old mode 100755
new mode 100644
diff --git a/tasmota/webif/static/img/readme.txt b/tasmota/webif/static/img/readme.txt
old mode 100755
new mode 100644
diff --git a/tasmota/webif/templates/index.html b/tasmota/webif/templates/index.html
old mode 100755
new mode 100644
index 17f5e42f1..93aa78477
--- a/tasmota/webif/templates/index.html
+++ b/tasmota/webif/templates/index.html
@@ -1,764 +1,1408 @@
{% extends "base_plugin.html" %}
+
{% set logo_frame = false %}
-{% set update_interval = [(((10 * item_count) / 1000) | round | int) * 1000, 5000]|max %}
+{% set update_interval = 0 %}
+
+
+{% set update_interval = (200 * (log_array | length)) %}
+
+
+{% set dataSet = 'devices_info' %}
+
+
+{% set update_params = item_id %}
+
+
+{% set buttons = true %}
+
+
+{% set autorefresh_buttons = true %}
+
+
+{% set reload_button = true %}
-
+
+{% set close_button = true %}
+
+
+{% set row_count = false %}
+
+
+{% set initial_update = false %}
+
+
{% block pluginstyles %}
-
+
{% endblock pluginstyles %}
-
+
{% block pluginscripts %}
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{% endblock pluginscripts %}
+
{% block headtable %}
-{{ webif_pagelength }}
-
-
-
- {{_('Broker Host')}}
- {{ p.broker_config.host }}
-
- {{_('Broker Port')}}
- {{ p.broker_config.port }}
-
-
-
- {{_('Benutzer')}}
- {{ p.broker_config.user }}
-
- {{_('Passwort')}}
-
- {% if p.broker_config.password %}
- {% for letter in p.broker_config.password %}*{% endfor %}
- {% endif %}
-
-
-
-
- {{_('QoS')}}
- {{ p.broker_config.qos }}
-
- {{_('full_topic')}}
- {{ p.full_topic }}
-
-
-
-
+
+
+
+ {{_('Broker Host')}}
+ {{ broker_config.host }}
+ {{_('Broker Port')}}
+ {{ broker_config.port }}
+ {{_('Anzahl Geräte')}}
+ {{ len(p.tasmota_devices) }}
+
+
+ {{_('Benutzer')}}
+ {{ broker_config.user }}
+ {{_('Passwort')}}
+
+ {% if broker_config.password %}
+ {% for letter in broker_config.password %}*{% endfor %}
+ {% endif %}
+
+ {{_('Anzahl Zigbee')}}
+ {{ len(p.tasmota_zigbee_devices) }}
+
+
+ {{_('QoS')}}
+ {{ broker_config.qos }}
+ {{_('full_topic')}}
+ {{ full_topic }}
+
+
+
+
+
{% endblock headtable %}
-
+
+
{% block buttons %}
+
+ {{_('Zigbee-Geräte abfragen')}}
+
+
{% endblock %}
-
+
{% set tabcount = 6 %}
-
-{% if p.tasmota_items != [] %}
- {% set start_tab = 1 %}
+
+
+{% if not item_count %}
+ {% set start_tab = 6 %}
{% endif %}
+
-{% if items != [] %}
- {% set tab1title = _("" ~ plugin_shortname ~ " Items ") %}
+{% if item_count %}
+ {% set tab1title = _("" " Items ") %}
{% else %}
{% set tab1title = "hidden" %}
{% endif %}
-{% set tab2title = _("" ~ plugin_shortname ~ " Devices ") %}
-{% set tab3title = _("" ~ plugin_shortname ~ " " ~ _('Details') ~ " ") %}
-{% set tab4title = _("" ~ plugin_shortname ~ " " ~ _('Zigbee Devices') ~ " ") %}
-{% set tab5title = _("" ~ " Broker Information ") %}
+
+{% set tab2title = _("" " Devices ") %}
+
+{% set tab3title = _("" ~ _('Sensor Data') ~ " ") %}
+
+{% if zigbee %}
+ {% set tab4title = _("" ~ _('Zigbee Devices') ~ " ") %}
+{% else %}
+ {% set tab4title = "hidden" %}
+{% endif %}
+
+{% set tab5title = _("" " Broker Information ") %}
+
{% if maintenance %}
- {% set tab6title = _("" ~ plugin_shortname ~ " " ~ _('Maintenance') ~ " ") %}
+ {% set tab6title = _("" ~ _('Device Details') ~ " ") %}
{% else %}
{% set tab6title = "hidden" %}
{% endif %}
-
+
{% block bodytab1 %}
-
-
Item Information
-
-
-
-
- {{ _('Item') }}
- {{ _('Typ') }}
- {{ _('Wert') }}
- {{ _('Tasmota Topic') }}
- {{ _('Relais') }}
- {{ _('Letztes Update') }}
- {{ _('Letzter Change') }}
-
-
-
- {% for item in items %}
-
-
- {{ item._path }}
- {{ item._type }}
- {{ item() }}
- {{ p.get_iattr_value(item.conf, 'tasmota_topic') }}
- {% if p.get_iattr_value(item.conf, 'tasmota_relay') is in ['1', '2', '3', '4', '5', '6', '7', '8'] %}
- {{ p.get_iattr_value(item.conf, 'tasmota_relay') }}
- {% elif p.get_iattr_value(item.conf, 'tasmota_attr') == 'relay' %}
- 1
- {% else %}
- -
- {% endif %}
- {{ item.last_update().strftime('%d.%m.%Y %H:%M:%S') }}
- {{ item.last_change().strftime('%d.%m.%Y %H:%M:%S') }}
-
- {% endfor %}
-
-
-
+ Item Information
+
{% endblock %}
{% block bodytab2 %}
-
-
Device Information
-
-
-
-
- {{ _('Tasmota Topic') }}
- {{ _('Online') }}
- {{ _('Friendy Name') }}
- {{ _('Mac Adresse') }}
- {{ _('IP Adresse') }}
- {{ _('Uptime') }}
- {{ _('Sensor Type') }}
- {{ _('Firmware') }}
- {{ _('Module') }}
- {{ _('Wifi') }}
- {{ _('Details') }}
-
-
-
- {% for device in p.tasmota_devices %}
- {% if 'fw_ver' in p.tasmota_devices[device] %}
-
-
- {{ device }}
- {{ p.tasmota_devices[device].online }}
- {{ p.tasmota_devices[device].friendly_name }}
- {{ p.tasmota_devices[device].mac }}
- {{ p.tasmota_devices[device].ip }}
- {{ p.tasmota_devices[device].uptime }}
-
- {% if p.tasmota_devices[device]['sensors'] != {} %}
- {% for key in p.tasmota_devices[device]['sensors'] %}
- {{ key }}
- {%if not loop.last%}, {%endif%}
- {% endfor %}
- {% else %}
- -
- {% endif %}
-
- {{ p.tasmota_devices[device].fw_ver }}
- {{ p.tasmota_devices[device].module }}
- {% if p.tasmota_devices[device]['wifi_signal'] %}
- {{ p.tasmota_devices[device].wifi_signal }} dBm
- {% else %}
-
- {% endif %}
-
-
- {% for entry in p.tasmota_devices[device]['discovery_config'] %}
-
- {{ entry }}:
- {{ p.tasmota_devices[device]['discovery_config'][entry] }}
-
- {% endfor %}
-
-
-
- {% endif %}
- {% endfor %}
-
-
-
-
+ Device Information
+
{% endblock %}
{% block bodytab3 %}
-
-{% if p.has_energy_sensor() %}
-
ENERGY SENSORS
-
-
-
-
- {{ _('Tasmota Topic') }}
- {{ _('Spannung') }}
- {{ _('Strom') }}
- {{ _('Leistung') }}
-
- {{ _('Heute') }}
- {{ _('Gestern') }}
- {{ _('Gesamt') }}
- {{ _('Gesamt - Startzeit') }}
-
-
-
- {% for device in p.tasmota_devices %}
- {% if p.tasmota_devices[device]['sensors']['ENERGY'] %}
-
-
- {{ device }}
- {{ p.tasmota_devices[device]['sensors']['ENERGY']['voltage'] }}V.
- {{ p.tasmota_devices[device]['sensors']['ENERGY']['current'] }}A.
- {{ p.tasmota_devices[device]['sensors']['ENERGY']['power'] }}W
-
- {{ p.tasmota_devices[device]['sensors']['ENERGY']['today'] }}kWh
- {{ p.tasmota_devices[device]['sensors']['ENERGY']['yesterday'] }}kWh
- {{ p.tasmota_devices[device]['sensors']['ENERGY']['total'] }}kWh
- {{ p.tasmota_devices[device]['sensors']['ENERGY']['total_starttime'] }}
-
- {% endif %}
- {% endfor %}
-
-
-
-
-{% endif %}
+ {% if p.has_energy_sensor() %}
+
ENERGY SENSORS
+
-{% if p.has_env_sensor() %}
-
ENVIRONMENTAL SENSORS
-
-
-
-
- {{ _('Tasmota Topic') }}
- {{ _('Temperatur') }}
- {{ _('Luftfeuchtigkeit') }}
- {{ _('Taupunkt') }}
- {{ _('1w-ID') }}
-
-
-
- {% if p.has_ds18b20_sensor() %}
- {% for device in p.tasmota_devices %}
- {% if p.tasmota_devices[device]['sensors'] %}
- {% if p.tasmota_devices[device]['sensors']['DS18B20'] %}
-
-
- {{ device }}
- {{ p.tasmota_devices[device]['sensors']['DS18B20'].temperature }}°C.
- -
- -
- {{ p.tasmota_devices[device]['sensors']['DS18B20'].id }}
-
- {% endif %}
- {% endif %}
- {% endfor %}
- {% endif %}
- {% if p.has_am2301_sensor() or p.has_sht3x_sensor() %}
- {% for device in p.tasmota_devices %}
- {% if p.tasmota_devices[device]['sensors'] %}
- {% if p.tasmota_devices[device]['sensors']['AM2301'] %}
-
-
- {{ device }}
- {{ p.tasmota_devices[device]['sensors']['AM2301'].temperature }}°C.
- {{ p.tasmota_devices[device]['sensors']['AM2301'].humidity }}%rH.
- {{ p.tasmota_devices[device]['sensors']['AM2301'].dewpoint }}°C.
- -
-
- {% endif %}
- {% if p.tasmota_devices[device]['sensors']['SHT3X'] %}
-
-
- {{ device }}
- {{ p.tasmota_devices[device]['sensors']['SHT3X'].temperature }}°C.
- {{ p.tasmota_devices[device]['sensors']['SHT3X'].humidity }}%rH.
- {{ p.tasmota_devices[device]['sensors']['SHT3X'].dewpoint }}°C.
- -
-
- {% endif %}
- {% endif %}
- {% endfor %}
- {% endif %}
-
-
-
-
-{% endif %}
+
+
+ {% endif %}
-{% if p.has_other_sensor() %}
-
OTHER SENSORS
-
-
-
-
- {{ _('Sensor') }}
- {{ _('Sensor Details') }}
-
-
-
- {% for device in p.tasmota_devices %}
- {% for sensor in p.tasmota_devices[device]['sensors'] %}
- {% if sensor not in p.SENSORS %}
-
-
- {{ sensor }}
- {{ p.tasmota_devices[device]['sensors'][sensor] }}
-
- {% endif %}
- {% endfor %}
- {% endfor %}
-
-
-{% endif %}
+ {% if p.has_env_sensor() %}
+
ENVIRONMENTAL SENSORS
+
-{% if p.has_lights() %}
-
LIGHTS
-
-
-
-
- {{ _('Tasmota Topic') }}
- {{ _('HSB') }}
- {{ _('Dimmer') }}
- {{ _('Color') }}
- {{ _('CT') }}
- {{ _('Scheme') }}
- {{ _('Fade') }}
- {{ _('Speed') }}
- {{ _('LED-Table') }}
-
-
-
- {% for device in p.tasmota_devices %}
- {% if p.tasmota_devices[device]['lights'] %}
-
-
- {{ device }}
- {{ p.tasmota_devices[device]['lights'].hsb }}.
- {{ p.tasmota_devices[device]['lights'].dimmer }}.
- {{ p.tasmota_devices[device]['lights'].color }}.
- {{ p.tasmota_devices[device]['lights'].ct }}.
- {{ p.tasmota_devices[device]['lights'].scheme }}.
- {{ p.tasmota_devices[device]['lights'].fade }}.
- {{ p.tasmota_devices[device]['lights'].speed }}.
- {{ p.tasmota_devices[device]['lights'].ledtable }}.
-
- {% endif %}
- {% endfor %}
-
-
-
-
-
-{% endif %}
+
+
+ {% endif %}
-{% if p.has_rf() %}
-
RF
-
-
-
-
- {{ _('Tasmota Topic') }}
- {{ _('RF-Received') }}
- {{ _('RF-Send Result') }}
- {{ _('RF-Key Result') }}
-
-
-
- {% for device in p.tasmota_devices %}
- {% if p.tasmota_devices[device]['rf'] %}
-
-
- {{ device }}
- {{ p.tasmota_devices[device]['rf'].rf_received }}
- {{ p.tasmota_devices[device]['rf'].rf_send_result }}
- {{ p.tasmota_devices[device]['rf'].rfkey_result }}
-
- {% endif %}
- {% endfor %}
-
-
-
-
-
-{% endif %}
-
+ {% if p.has_other_sensor() %}
+ OTHER SENSORS
+
+
+
+
+ {% endif %}
+
+ {% if p.has_lights() %}
+ LIGHTS
+
+
+
+
+ {% endif %}
+
+ {% if p.has_rf() %}
+ RF
+
+
+
+
+ {% endif %}
{% endblock %}
{% block bodytab4 %}
-
-
Zigbee Information
-
-
-
-
- {{ _('Device ID') }}
- {{ _('IEEEAddr') }}
- {{ _('Hersteller') }}
- {{ _('ModelId') }}
- {{ _('LinkQuality') }}
- {{ _('Battery %') }}
- {{ _('LastSeen') }}
- {{ _('Data') }}
-
-
-
- {% for device in p.tasmota_zigbee_devices %}
-
-
- {{ device }}
- {{ p.tasmota_zigbee_devices[device]['ieeeaddr'] }}
- {{ p.tasmota_zigbee_devices[device]['manufacturer'] }}
- {{ p.tasmota_zigbee_devices[device]['modelid'] }}
- {{ p.tasmota_zigbee_devices[device]['linkquality'] }}
- {{ p.tasmota_zigbee_devices[device]['batterypercentage'] }}
- {{ p.tasmota_zigbee_devices[device]['lastseenepoch'] }}
- {{ p.tasmota_zigbee_devices[device] }}
-
- {% endfor %}
-
-
-
+ Zigbee Information
+
{% endblock %}
{% block bodytab5 %}
-
-
Broker Information
-
-
-
- {{ _('Merkmal') }}
- {{ _('Wert') }}
-
-
-
-
- {{ 'Broker Version' }}
- {{ p._broker.version }}
-
-
- {{ 'Active Clients' }}
- {{ p._broker.active_clients }}
-
-
- {{ 'Subscriptions' }}
- {{ p._broker.subscriptions }}
-
-
- {{ 'Messages stored' }}
- {{ p._broker.stored_messages }}
-
-
- {{ 'Retained Messages' }}
- {{ p._broker.retained_messages }}
-
-
- {% if p.broker_monitoring %}
-
- {{ _('Laufzeit') }}
- {{ p.broker_uptime() }}
-
- {% endif %}
-
-
-
-
- {% if p.broker_monitoring %}
-
-
-
Broker Monitor
-
-
- {{ _('Message Durchsatz') }}
- {{ _('letzte Minute') }}
- {{ _('letzte 5 Min.') }}
- {{ _('letzte 15 Min.') }}
-
-
-
- {{ _('Durchschnittlich Messages je Minute empfangen') }}
- {{ p._broker.msg_rcv_1min }}
- {{ p._broker.msg_rcv_5min }}
- {{ p._broker.msg_rcv_15min }}
-
-
- {{ _('Durchschnittlich Messages je Minute gesendet') }}
- {{ p._broker.msg_snt_1min }}
- {{ p._broker.msg_snt_5min }}
- {{ p._broker.msg_snt_15min }}
-
-
-
-{% endif %}
-
+ Broker Information
+
+
+ {% if p.broker_monitoring %}
+
+
+ Broker Monitor
+
+ {% endif %}
{% endblock %}
{% block bodytab6 %}
-
-
-
-
- {{ _('Tasmota Device') }}
- {{ _('Tasmota Device Details') }}
-
-
-
- {% for device in p.tasmota_devices %}
-
- {{ device }}
- {{ p.tasmota_devices[device] }}
-
- {% endfor %}
-
-
-
-
-
-
-
-
-
-
-
- {{ _('Tasmota Items') }}
- {{ _('Tasmota Item Config') }}
-
-
-
- {% for item in p.get_item_list() %}
-
- {{ item }}
- {{ p.get_item_config(item) }}
-
- {% endfor %}
-
-
-
-
-
-
-
-
-
-
-
- {{ _('Zigbee Device') }}
- {{ _('Zigbee Device Details') }}
-
-
-
- {% for device in p.tasmota_zigbee_devices %}
-
- {{ device }}
- {{ p.tasmota_zigbee_devices[device] }}
-
- {% endfor %}
-
-
-
-{% endblock %}
-
+ Tasmota Device Details
+
+
+
+ Tasmota Zigbee-Device Details
+
+{% endblock %}
\ No newline at end of file