Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions hatasmota/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,13 @@
SENSOR_PROXIMITY = "Proximity"
SENSOR_AMBIENT = "Ambient"
SENSOR_SWITCH = "Switch"
SENSOR_STATUS_MQTT_COUNT = "status_mqtt_count"
SENSOR_STATUS_LINK_COUNT = "status_link_count"
SENSOR_STATUS_SIGNAL = "status_signal"
SENSOR_STATUS_RSSI = "status_rssi"
SENSOR_STATUS_RESTART = "status_restart_reason"
SENSOR_STATUS_IP = "status_ip"
SENSOR_STATUS_LAST_RESTART_TIME = "last_restart_time"
SENSOR_STATUS_LINK_COUNT = "status_link_count"
SENSOR_STATUS_MQTT_COUNT = "status_mqtt_count"
SENSOR_STATUS_RESTART_REASON = "status_restart_reason"
SENSOR_STATUS_RSSI = "status_rssi"
SENSOR_STATUS_SIGNAL = "status_signal"

SENSOR_UNIT_PRESSURE = "PressureUnit"
SENSOR_UNIT_SPEED = "SpeedUnit"
Expand Down
22 changes: 16 additions & 6 deletions hatasmota/discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,19 +356,29 @@ def has_entities_with_platform(discovery_msg, platform):
return any(x is not None for (x, _) in entities)


def get_entity(config, mqtt_client):
def get_entity(config, mqtt_client, create_task):
"""Create entity for the given platform."""
platform = config.platform
if platform == "binary_sensor":
return TasmotaSwitch(config=config, mqtt_client=mqtt_client)
return TasmotaSwitch(
config=config, mqtt_client=mqtt_client, create_task=create_task
)
if platform == "light":
return TasmotaLight(config=config, mqtt_client=mqtt_client)
return TasmotaLight(
config=config, mqtt_client=mqtt_client, create_task=create_task
)
if platform == "sensor":
return TasmotaSensor(config=config, mqtt_client=mqtt_client)
return TasmotaSensor(
config=config, mqtt_client=mqtt_client, create_task=create_task
)
if platform == "status_sensor":
return TasmotaStatusSensor(config=config, mqtt_client=mqtt_client)
return TasmotaStatusSensor(
config=config, mqtt_client=mqtt_client, create_task=create_task
)
if platform == "switch":
return TasmotaRelay(config=config, mqtt_client=mqtt_client)
return TasmotaRelay(
config=config, mqtt_client=mqtt_client, create_task=create_task
)
return None


Expand Down
3 changes: 2 additions & 1 deletion hatasmota/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ class TasmotaAvailabilityConfig(TasmotaEntityConfig):
class TasmotaEntity:
"""Base class for Tasmota entities."""

def __init__(self, config, mqtt_client):
def __init__(self, config, create_task, mqtt_client):
"""Initialize."""
self._cfg = config
self._create_task = create_task
self._mqtt_client = mqtt_client
self._on_state_callback = None
super().__init__()
Expand Down
2 changes: 1 addition & 1 deletion hatasmota/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ def state_message_received(msg):
"topic": self._cfg.state_topic1,
"msg_callback": state_message_received,
},
# Polled state update (stat/STATUS8)
# Polled state update (stat/STATUS10)
"state_topic2": {
"event_loop_safe": True,
"topic": self._cfg.state_topic2,
Expand Down
64 changes: 45 additions & 19 deletions hatasmota/status_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@

from .const import (
CONF_DEVICENAME,
CONF_IP,
CONF_MAC,
PERCENTAGE,
SENSOR_STATUS_IP,
SENSOR_STATUS_LAST_RESTART_TIME,
SENSOR_STATUS_LINK_COUNT,
SENSOR_STATUS_MQTT_COUNT,
SENSOR_STATUS_RESTART,
SENSOR_STATUS_RESTART_REASON,
SENSOR_STATUS_RSSI,
SENSOR_STATUS_SIGNAL,
SIGNAL_STRENGTH_DECIBELS,
Expand Down Expand Up @@ -55,7 +56,7 @@
SENSORS = [
SENSOR_STATUS_IP,
SENSOR_STATUS_SIGNAL,
SENSOR_STATUS_RESTART,
SENSOR_STATUS_RESTART_REASON,
SENSOR_STATUS_RSSI,
SENSOR_STATUS_MQTT_COUNT,
SENSOR_STATUS_LINK_COUNT,
Expand All @@ -66,35 +67,34 @@
SENSOR_STATUS_IP: "IP",
SENSOR_STATUS_LINK_COUNT: "WiFi Connect Count",
SENSOR_STATUS_MQTT_COUNT: "MQTT Connect Count",
SENSOR_STATUS_RESTART: "Restart Reason",
SENSOR_STATUS_RESTART_REASON: "Restart Reason",
SENSOR_STATUS_RSSI: "RSSI",
SENSOR_STATUS_SIGNAL: "Signal",
SENSOR_STATUS_LAST_RESTART_TIME: "Last Restart Time",
}

SINGLE_SHOT = [SENSOR_STATUS_RESTART_REASON, SENSOR_STATUS_LAST_RESTART_TIME]

STATE_PATHS = {
SENSOR_STATUS_LINK_COUNT: ["Wifi", "LinkCount"],
SENSOR_STATUS_MQTT_COUNT: ["MqttCount"],
SENSOR_STATUS_RSSI: ["Wifi", "RSSI"],
SENSOR_STATUS_SIGNAL: ["Wifi", "Signal"],
SENSOR_STATUS_LAST_RESTART_TIME: ["UptimeSec"],
}

STATUS_PATHS = {
SENSOR_STATUS_IP: ["StatusNET", "IPAddress"],
SENSOR_STATUS_LINK_COUNT: ["StatusSTS", "Wifi", "LinkCount"],
SENSOR_STATUS_MQTT_COUNT: ["StatusSTS", "MqttCount"],
SENSOR_STATUS_RESTART: ["StatusPRM", "RestartReason"],
SENSOR_STATUS_RESTART_REASON: ["StatusPRM", "RestartReason"],
SENSOR_STATUS_RSSI: ["StatusSTS", "Wifi", "RSSI"],
SENSOR_STATUS_SIGNAL: ["StatusSTS", "Wifi", "Signal"],
SENSOR_STATUS_LAST_RESTART_TIME: ["StatusSTS", "UptimeSec"],
}

STATUS_TOPICS = {
SENSOR_STATUS_IP: 5,
SENSOR_STATUS_LINK_COUNT: 11,
SENSOR_STATUS_MQTT_COUNT: 11,
SENSOR_STATUS_RESTART: 1,
SENSOR_STATUS_RESTART_REASON: 1,
SENSOR_STATUS_RSSI: 11,
SENSOR_STATUS_SIGNAL: 11,
SENSOR_STATUS_LAST_RESTART_TIME: 11,
Expand All @@ -104,7 +104,7 @@
SENSOR_STATUS_IP: SENSOR_STATUS_IP,
SENSOR_STATUS_LINK_COUNT: SENSOR_STATUS_LINK_COUNT,
SENSOR_STATUS_MQTT_COUNT: SENSOR_STATUS_MQTT_COUNT,
SENSOR_STATUS_RESTART: SENSOR_STATUS_RESTART,
SENSOR_STATUS_RESTART_REASON: SENSOR_STATUS_RESTART_REASON,
SENSOR_STATUS_RSSI: SENSOR_STATUS_RSSI,
SENSOR_STATUS_SIGNAL: SENSOR_STATUS_SIGNAL,
SENSOR_STATUS_LAST_RESTART_TIME: SENSOR_STATUS_LAST_RESTART_TIME,
Expand All @@ -114,7 +114,7 @@
SENSOR_STATUS_IP: None,
SENSOR_STATUS_LINK_COUNT: None,
SENSOR_STATUS_MQTT_COUNT: None,
SENSOR_STATUS_RESTART: None,
SENSOR_STATUS_RESTART_REASON: None,
SENSOR_STATUS_RSSI: PERCENTAGE,
SENSOR_STATUS_SIGNAL: SIGNAL_STRENGTH_DECIBELS,
SENSOR_STATUS_LAST_RESTART_TIME: None,
Expand All @@ -127,6 +127,7 @@ class TasmotaStatusSensorConfig(TasmotaAvailabilityConfig, TasmotaEntityConfig):

poll_topic: str = attr.ib()
sensor: str = attr.ib()
state: str = attr.ib()
state_topic: str = attr.ib()
status_topic: str = attr.ib()

Expand All @@ -140,14 +141,15 @@ def from_discovery_message(cls, config, platform):
friendly_name=f"{config[CONF_DEVICENAME]} {NAMES[sensor]}",
mac=config[CONF_MAC],
platform=platform,
poll_payload=str(STATUS_TOPICS[sensor]),
poll_payload=str(STATUS_TOPICS.get(sensor)),
poll_topic=get_topic_command_status(config),
availability_topic=get_topic_tele_will(config),
availability_offline=config_get_state_offline(config),
availability_online=config_get_state_online(config),
sensor=sensor,
state=config[CONF_IP] if sensor == SENSOR_STATUS_IP else None,
state_topic=get_topic_tele_state(config),
status_topic=get_topic_stat_status(config, STATUS_TOPICS[sensor]),
status_topic=get_topic_stat_status(config, STATUS_TOPICS.get(sensor)),
)
for sensor in SENSORS
]
Expand All @@ -168,6 +170,17 @@ def __init__(self, **kwds):
self._attributes = {}
super().__init__(**kwds)

async def _poll_status(self):
"""Poll for status."""
await self.subscribe_topics()
self._mqtt_client.publish_debounced(
self._cfg.poll_topic, self._cfg.poll_payload
)

def poll_status(self):
"""Poll for status."""
self._create_task(self._poll_status())

async def subscribe_topics(self):
"""Subscribe to topics."""

Expand All @@ -184,6 +197,8 @@ def state_message_received(msg):
else:
state = get_value_by_path(payload, STATUS_PATHS[self._cfg.sensor])
if state is not None:
if self._cfg.sensor in SINGLE_SHOT:
self._create_task(self._unsubscribe_state_topics())
if self._cfg.sensor == SENSOR_STATUS_LAST_RESTART_TIME:
state = datetime.utcnow() - timedelta(seconds=int(state))
self._on_state_callback(state)
Expand All @@ -197,21 +212,32 @@ def state_message_received(msg):
"topic": self._cfg.state_topic,
"msg_callback": state_message_received,
}
# Polled state update (stat/STATUS#)
topics["status_topic"] = {
"event_loop_safe": True,
"topic": self._cfg.status_topic,
"msg_callback": state_message_received,
}
if self._cfg.sensor in STATUS_PATHS:
# Polled state update (stat/STATUS#)
topics["status_topic"] = {
"event_loop_safe": True,
"topic": self._cfg.status_topic,
"msg_callback": state_message_received,
}
topics = {**topics, **availability_topics}

self._sub_state = await self._mqtt_client.subscribe(
self._sub_state,
topics,
)
if self._cfg.state:
self._on_state_callback(self._cfg.state)

async def _unsubscribe_state_topics(self):
"""Unsubscribe from state topics."""
availability_topics = self.get_availability_topics()
self._sub_state = await self._mqtt_client.subscribe(
self._sub_state,
availability_topics,
)

async def unsubscribe_topics(self):
"""Unsubscribe to all MQTT topics."""
"""Unsubscribe from all MQTT topics."""
self._sub_state = await self._mqtt_client.unsubscribe(self._sub_state)

@property
Expand Down
4 changes: 2 additions & 2 deletions hatasmota/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ def state_message_received(msg):
# tasmota_0848A2/tele/SENSOR / {"Time":"2020-09-20T09:41:28","Switch1":"ON"}
if msg.topic == self._cfg.state_topic2:
state = get_value_by_path(msg.payload, [self._cfg.switchname])
# tasmota_0848A2/stat/STATUS8 / {"StatusSNS":{"Time":"2020-09-20T09:41:00","Switch1":"ON"}}
# tasmota_0848A2/stat/STATUS10 / {"StatusSNS":{"Time":"2020-09-20T09:41:00","Switch1":"ON"}}
if msg.topic == self._cfg.state_topic3:
state = get_value_by_path(
msg.payload, [STATUS_SENSOR, self._cfg.switchname]
Expand All @@ -296,7 +296,7 @@ def state_message_received(msg):
availability_topics = self.get_availability_topics()
# tasmota_0848A2/stat/RESULT / {"Switch1":{"Action":"ON"}}
# tasmota_0848A2/tele/SENSOR / {"Time":"2020-09-20T09:41:28","Switch1":"ON"}
# tasmota_0848A2/stat/STATUS8 / {"StatusSNS":{"Time":"2020-09-20T09:41:00","Switch1":"ON"}}
# tasmota_0848A2/stat/STATUS10 / {"StatusSNS":{"Time":"2020-09-20T09:41:00","Switch1":"ON"}}
topics = {
"state_topic1": {
"event_loop_safe": True,
Expand Down