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
2 changes: 1 addition & 1 deletion homeassistant/components/tasmota/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "Tasmota (beta)",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/tasmota",
"requirements": ["hatasmota==0.0.26"],
"requirements": ["hatasmota==0.0.27"],
"dependencies": ["mqtt"],
"mqtt": ["tasmota/discovery/#"],
"codeowners": ["@emontnemery"]
Expand Down
5 changes: 3 additions & 2 deletions homeassistant/components/tasmota/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
SENSOR_STATUS_IP,
SENSOR_STATUS_LINK_COUNT,
SENSOR_STATUS_MQTT_COUNT,
SENSOR_STATUS_RESTART,
SENSOR_STATUS_RSSI,
SENSOR_STATUS_SIGNAL,
SENSOR_STATUS_UPTIME,
Expand All @@ -59,7 +60,6 @@
DEVICE_CLASS_PRESSURE,
DEVICE_CLASS_SIGNAL_STRENGTH,
DEVICE_CLASS_TEMPERATURE,
DEVICE_CLASS_TIMESTAMP,
)
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
Expand Down Expand Up @@ -108,14 +108,15 @@
SENSOR_PRESSUREATSEALEVEL: {DEVICE_CLASS: DEVICE_CLASS_PRESSURE},
SENSOR_PROXIMITY: {ICON: "mdi:ruler"},
SENSOR_REACTIVE_POWERUSAGE: {DEVICE_CLASS: DEVICE_CLASS_POWER},
SENSOR_STATUS_RESTART: {ICON: "mdi:information-outline"},
SENSOR_STATUS_SIGNAL: {DEVICE_CLASS: DEVICE_CLASS_SIGNAL_STRENGTH},
SENSOR_STATUS_RSSI: {ICON: "mdi:access-point"},
SENSOR_STATUS_UPTIME: {ICON: "mdi:progress-clock"},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a reason this changed from DEVICE_CLASS_TIMESTAMP? there may be some differences in frontend formatting without such.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it's because the uptime is not a timestamp, it measures elapsed time.

Copy link
Copy Markdown
Contributor

@effelle effelle Nov 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uptime has its own format: [n days]T[hh:mm:ss].

{"Uptime":"3T13:38:27"}

To have it working as DEVICE_CLASS_TIMESTAMP a conversion is needed by our side and frankly doesn't worth the effort since is already showing a clear information.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

while it may seem not worth it, this is going to create a lot of state changes which is why using timestamp is preferrred as you would only set the last boot time

Copy link
Copy Markdown
Contributor Author

@emontnemery emontnemery Nov 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, that's a good point. Storing the timestamp of last restart would be enough, but it's maybe not so user friendly for display?

Edit: Maybe a solution could be to truncate the uptime to full hours to prevent spamming a lot of state changes.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our standard is to use device class timestamp for these cases. Please convert the time to an absolute time if needed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Martin, we'll get that sorted in next hatasmota version.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected in #43013

SENSOR_TEMPERATURE: {DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE},
SENSOR_TODAY: {DEVICE_CLASS: DEVICE_CLASS_POWER},
SENSOR_TOTAL: {DEVICE_CLASS: DEVICE_CLASS_POWER},
SENSOR_TOTAL_START_TIME: {ICON: "mdi:progress-clock"},
SENSOR_TVOC: {ICON: "mdi:air-filter"},
SENSOR_STATUS_UPTIME: {DEVICE_CLASS: DEVICE_CLASS_TIMESTAMP},
SENSOR_VOLTAGE: {ICON: "mdi:alpha-v-circle-outline"},
SENSOR_WEIGHT: {ICON: "mdi:scale"},
SENSOR_YESTERDAY: {DEVICE_CLASS: DEVICE_CLASS_POWER},
Expand Down
2 changes: 1 addition & 1 deletion requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -738,7 +738,7 @@ hass-nabucasa==0.37.1
hass_splunk==0.1.1

# homeassistant.components.tasmota
hatasmota==0.0.26
hatasmota==0.0.27

# homeassistant.components.jewish_calendar
hdate==0.9.12
Expand Down
2 changes: 1 addition & 1 deletion requirements_test_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ hangups==0.4.11
hass-nabucasa==0.37.1

# homeassistant.components.tasmota
hatasmota==0.0.26
hatasmota==0.0.27

# homeassistant.components.jewish_calendar
hdate==0.9.12
Expand Down
34 changes: 24 additions & 10 deletions tests/components/tasmota/test_binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
import json

from hatasmota.utils import (
get_topic_stat_result,
get_topic_stat_status,
get_topic_stat_switch,
get_topic_tele_sensor,
get_topic_tele_will,
)
Expand Down Expand Up @@ -61,11 +61,15 @@ async def test_controlling_state_via_mqtt(hass, mqtt_mock, setup_tasmota):
assert not state.attributes.get(ATTR_ASSUMED_STATE)

# Test normal state update
async_fire_mqtt_message(hass, "tasmota_49A3BC/stat/SWITCH1", '{"STATE":"ON"}')
async_fire_mqtt_message(
hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"ON"}}'
)
state = hass.states.get("binary_sensor.test")
assert state.state == STATE_ON

async_fire_mqtt_message(hass, "tasmota_49A3BC/stat/SWITCH1", '{"STATE":"OFF"}')
async_fire_mqtt_message(
hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"OFF"}}'
)
state = hass.states.get("binary_sensor.test")
assert state.state == STATE_OFF

Expand All @@ -80,13 +84,13 @@ async def test_controlling_state_via_mqtt(hass, mqtt_mock, setup_tasmota):

# Test polled state update
async_fire_mqtt_message(
hass, "tasmota_49A3BC/stat/STATUS8", '{"StatusSNS":{"Switch1":"ON"}}'
hass, "tasmota_49A3BC/stat/STATUS10", '{"StatusSNS":{"Switch1":"ON"}}'
)
state = hass.states.get("binary_sensor.test")
assert state.state == STATE_ON

async_fire_mqtt_message(
hass, "tasmota_49A3BC/stat/STATUS8", '{"StatusSNS":{"Switch1":"OFF"}}'
hass, "tasmota_49A3BC/stat/STATUS10", '{"StatusSNS":{"Switch1":"OFF"}}'
)
state = hass.states.get("binary_sensor.test")
assert state.state == STATE_OFF
Expand Down Expand Up @@ -141,13 +145,17 @@ def callback(event):
async_fire_mqtt_message(hass, "tasmota_49A3BC/tele/LWT", "Online")
await hass.async_block_till_done()
assert events == ["off"]
async_fire_mqtt_message(hass, "tasmota_49A3BC/stat/SWITCH1", '{"STATE":"ON"}')
async_fire_mqtt_message(
hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"ON"}}'
)
await hass.async_block_till_done()
state = hass.states.get("binary_sensor.test")
assert state.state == STATE_ON
assert events == ["off", "on"]

async_fire_mqtt_message(hass, "tasmota_49A3BC/stat/SWITCH1", '{"STATE":"ON"}')
async_fire_mqtt_message(
hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"ON"}}'
)
await hass.async_block_till_done()
state = hass.states.get("binary_sensor.test")
assert state.state == STATE_ON
Expand Down Expand Up @@ -195,7 +203,13 @@ async def test_availability_poll_state(
config["swc"][0] = 1
poll_topic = "tasmota_49A3BC/cmnd/STATUS"
await help_test_availability_poll_state(
hass, mqtt_client_mock, mqtt_mock, binary_sensor.DOMAIN, config, poll_topic, "8"
hass,
mqtt_client_mock,
mqtt_mock,
binary_sensor.DOMAIN,
config,
poll_topic,
"10",
)


Expand Down Expand Up @@ -240,9 +254,9 @@ async def test_entity_id_update_subscriptions(hass, mqtt_mock, setup_tasmota):
config = copy.deepcopy(DEFAULT_CONFIG)
config["swc"][0] = 1
topics = [
get_topic_stat_switch(config, 0),
get_topic_stat_result(config),
get_topic_tele_sensor(config),
get_topic_stat_status(config, 8),
get_topic_stat_status(config, 10),
get_topic_tele_will(config),
]
await help_test_entity_id_update_subscriptions(
Expand Down
38 changes: 38 additions & 0 deletions tests/components/tasmota/test_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,44 @@
from tests.common import async_fire_mqtt_message

DEFAULT_CONFIG = {
"ip": "192.168.15.10",
"dn": "Tasmota",
"fn": ["Test", "Beer", "Milk", "Four", None],
"hn": "tasmota_49A3BC-0956",
"if": 0, # iFan
"lk": 1, # RGB + white channels linked to a single light
"mac": "00000049A3BC",
"md": "Sonoff Basic",
"ofln": "Offline",
"onln": "Online",
"state": ["OFF", "ON", "TOGGLE", "HOLD"],
"sw": "8.4.0.2",
"swn": [None, None, None, None, None],
"t": "tasmota_49A3BC",
"ft": "%topic%/%prefix%/",
"tp": ["cmnd", "stat", "tele"],
"rl": [0, 0, 0, 0, 0, 0, 0, 0],
"swc": [-1, -1, -1, -1, -1, -1, -1, -1],
"btn": [0, 0, 0, 0],
"so": {
"4": 0, # Return MQTT response as RESULT or %COMMAND%
"11": 0, # Swap button single and double press functionality
"13": 0, # Allow immediate action on single button press
"17": 1, # Show Color string as hex or comma-separated
"20": 0, # Update of Dimmer/Color/CT without turning power on
"30": 0, # Enforce Home Assistant auto-discovery as light
"68": 0, # Multi-channel PWM instead of a single light
"73": 0, # Enable Buttons decoupling and send multi-press and hold MQTT messages
"82": 0, # Reduce the CT range from 153..500 to 200.380
"114": 0, # Enable sending switch MQTT messages
},
"ty": 0, # Tuya MCU
"lt_st": 0,
"ver": 1,
}


DEFAULT_CONFIG_9_0_0_3 = {
"ip": "192.168.15.10",
"dn": "Tasmota",
"fn": ["Test", "Beer", "Milk", "Four", None],
Expand Down
Loading