Remove mqtt sensor support for last_reset_topic
(#93792)
* Remove mqtt sensor support for `last_reset_topic` * Add cases for empty last reset messages
This commit is contained in:
parent
d421a51576
commit
3a7f9ab57d
2 changed files with 35 additions and 169 deletions
|
@ -53,7 +53,7 @@ from .models import (
|
||||||
ReceiveMessage,
|
ReceiveMessage,
|
||||||
ReceivePayloadType,
|
ReceivePayloadType,
|
||||||
)
|
)
|
||||||
from .util import get_mqtt_data, valid_subscribe_topic
|
from .util import get_mqtt_data
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -73,36 +73,11 @@ DEFAULT_NAME = "MQTT Sensor"
|
||||||
DEFAULT_FORCE_UPDATE = False
|
DEFAULT_FORCE_UPDATE = False
|
||||||
|
|
||||||
|
|
||||||
def validate_options(conf: ConfigType) -> ConfigType:
|
|
||||||
"""Validate options.
|
|
||||||
|
|
||||||
If last reset topic is present it must be same as the state topic.
|
|
||||||
"""
|
|
||||||
if (
|
|
||||||
CONF_LAST_RESET_TOPIC in conf
|
|
||||||
and CONF_STATE_TOPIC in conf
|
|
||||||
and conf[CONF_LAST_RESET_TOPIC] != conf[CONF_STATE_TOPIC]
|
|
||||||
):
|
|
||||||
_LOGGER.warning(
|
|
||||||
"'%s' must be same as '%s'", CONF_LAST_RESET_TOPIC, CONF_STATE_TOPIC
|
|
||||||
)
|
|
||||||
|
|
||||||
if CONF_LAST_RESET_TOPIC in conf and CONF_LAST_RESET_VALUE_TEMPLATE not in conf:
|
|
||||||
_LOGGER.warning(
|
|
||||||
"'%s' must be set if '%s' is set",
|
|
||||||
CONF_LAST_RESET_VALUE_TEMPLATE,
|
|
||||||
CONF_LAST_RESET_TOPIC,
|
|
||||||
)
|
|
||||||
|
|
||||||
return conf
|
|
||||||
|
|
||||||
|
|
||||||
_PLATFORM_SCHEMA_BASE = MQTT_RO_SCHEMA.extend(
|
_PLATFORM_SCHEMA_BASE = MQTT_RO_SCHEMA.extend(
|
||||||
{
|
{
|
||||||
vol.Optional(CONF_DEVICE_CLASS): vol.Any(DEVICE_CLASSES_SCHEMA, None),
|
vol.Optional(CONF_DEVICE_CLASS): vol.Any(DEVICE_CLASSES_SCHEMA, None),
|
||||||
vol.Optional(CONF_EXPIRE_AFTER): cv.positive_int,
|
vol.Optional(CONF_EXPIRE_AFTER): cv.positive_int,
|
||||||
vol.Optional(CONF_FORCE_UPDATE, default=DEFAULT_FORCE_UPDATE): cv.boolean,
|
vol.Optional(CONF_FORCE_UPDATE, default=DEFAULT_FORCE_UPDATE): cv.boolean,
|
||||||
vol.Optional(CONF_LAST_RESET_TOPIC): valid_subscribe_topic,
|
|
||||||
vol.Optional(CONF_LAST_RESET_VALUE_TEMPLATE): cv.template,
|
vol.Optional(CONF_LAST_RESET_VALUE_TEMPLATE): cv.template,
|
||||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||||
vol.Optional(CONF_SUGGESTED_DISPLAY_PRECISION): cv.positive_int,
|
vol.Optional(CONF_SUGGESTED_DISPLAY_PRECISION): cv.positive_int,
|
||||||
|
@ -112,8 +87,10 @@ _PLATFORM_SCHEMA_BASE = MQTT_RO_SCHEMA.extend(
|
||||||
).extend(MQTT_ENTITY_COMMON_SCHEMA.schema)
|
).extend(MQTT_ENTITY_COMMON_SCHEMA.schema)
|
||||||
|
|
||||||
PLATFORM_SCHEMA_MODERN = vol.All(
|
PLATFORM_SCHEMA_MODERN = vol.All(
|
||||||
|
# Deprecated in HA Core 2021.11.0 https://github.com/home-assistant/core/pull/54840
|
||||||
|
# Removed in HA Core 2023.6.0
|
||||||
|
cv.removed(CONF_LAST_RESET_TOPIC),
|
||||||
_PLATFORM_SCHEMA_BASE,
|
_PLATFORM_SCHEMA_BASE,
|
||||||
validate_options,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Configuring MQTT Sensors under the sensor platform key was deprecated in
|
# Configuring MQTT Sensors under the sensor platform key was deprecated in
|
||||||
|
@ -123,9 +100,10 @@ PLATFORM_SCHEMA = vol.All(
|
||||||
)
|
)
|
||||||
|
|
||||||
DISCOVERY_SCHEMA = vol.All(
|
DISCOVERY_SCHEMA = vol.All(
|
||||||
cv.deprecated(CONF_LAST_RESET_TOPIC),
|
# Deprecated in HA Core 2021.11.0 https://github.com/home-assistant/core/pull/54840
|
||||||
|
# Removed in HA Core 2023.6.0
|
||||||
|
cv.removed(CONF_LAST_RESET_TOPIC),
|
||||||
_PLATFORM_SCHEMA_BASE.extend({}, extra=vol.REMOVE_EXTRA),
|
_PLATFORM_SCHEMA_BASE.extend({}, extra=vol.REMOVE_EXTRA),
|
||||||
validate_options,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -319,10 +297,7 @@ class MqttSensor(MqttEntity, RestoreSensor):
|
||||||
def message_received(msg: ReceiveMessage) -> None:
|
def message_received(msg: ReceiveMessage) -> None:
|
||||||
"""Handle new MQTT messages."""
|
"""Handle new MQTT messages."""
|
||||||
_update_state(msg)
|
_update_state(msg)
|
||||||
if CONF_LAST_RESET_VALUE_TEMPLATE in self._config and (
|
if CONF_LAST_RESET_VALUE_TEMPLATE in self._config:
|
||||||
CONF_LAST_RESET_TOPIC not in self._config
|
|
||||||
or self._config[CONF_LAST_RESET_TOPIC] == self._config[CONF_STATE_TOPIC]
|
|
||||||
):
|
|
||||||
_update_last_reset(msg)
|
_update_last_reset(msg)
|
||||||
get_mqtt_data(self.hass).state_write_requests.write_state_request(self)
|
get_mqtt_data(self.hass).state_write_requests.write_state_request(self)
|
||||||
|
|
||||||
|
@ -333,24 +308,6 @@ class MqttSensor(MqttEntity, RestoreSensor):
|
||||||
"encoding": self._config[CONF_ENCODING] or None,
|
"encoding": self._config[CONF_ENCODING] or None,
|
||||||
}
|
}
|
||||||
|
|
||||||
@callback
|
|
||||||
@log_messages(self.hass, self.entity_id)
|
|
||||||
def last_reset_message_received(msg: ReceiveMessage) -> None:
|
|
||||||
"""Handle new last_reset messages."""
|
|
||||||
_update_last_reset(msg)
|
|
||||||
get_mqtt_data(self.hass).state_write_requests.write_state_request(self)
|
|
||||||
|
|
||||||
if (
|
|
||||||
CONF_LAST_RESET_TOPIC in self._config
|
|
||||||
and self._config[CONF_LAST_RESET_TOPIC] != self._config[CONF_STATE_TOPIC]
|
|
||||||
):
|
|
||||||
topics["last_reset_topic"] = {
|
|
||||||
"topic": self._config[CONF_LAST_RESET_TOPIC],
|
|
||||||
"msg_callback": last_reset_message_received,
|
|
||||||
"qos": self._config[CONF_QOS],
|
|
||||||
"encoding": self._config[CONF_ENCODING] or None,
|
|
||||||
}
|
|
||||||
|
|
||||||
self._sub_state = subscription.async_prepare_subscribe_topics(
|
self._sub_state = subscription.async_prepare_subscribe_topics(
|
||||||
self.hass, self._sub_state, topics
|
self.hass, self._sub_state, topics
|
||||||
)
|
)
|
||||||
|
|
|
@ -480,117 +480,44 @@ async def test_setting_sensor_value_via_mqtt_json_message_and_default_current_st
|
||||||
"state_class": "total",
|
"state_class": "total",
|
||||||
"state_topic": "test-topic",
|
"state_topic": "test-topic",
|
||||||
"unit_of_measurement": "fav unit",
|
"unit_of_measurement": "fav unit",
|
||||||
"last_reset_topic": "last-reset-topic",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
)
|
|
||||||
async def test_setting_sensor_last_reset_via_mqtt_message(
|
|
||||||
hass: HomeAssistant,
|
|
||||||
mqtt_mock_entry: MqttMockHAClientGenerator,
|
|
||||||
caplog: pytest.LogCaptureFixture,
|
|
||||||
) -> None:
|
|
||||||
"""Test the setting of the last_reset property via MQTT."""
|
|
||||||
await mqtt_mock_entry()
|
|
||||||
|
|
||||||
async_fire_mqtt_message(hass, "last-reset-topic", "2020-01-02 08:11:00")
|
|
||||||
state = hass.states.get("sensor.test")
|
|
||||||
assert state.attributes.get("last_reset") == "2020-01-02T08:11:00"
|
|
||||||
assert "'last_reset_topic' must be same as 'state_topic'" in caplog.text
|
|
||||||
assert (
|
|
||||||
"'last_reset_value_template' must be set if 'last_reset_topic' is set"
|
|
||||||
in caplog.text
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"hass_config",
|
|
||||||
[
|
|
||||||
{
|
|
||||||
mqtt.DOMAIN: {
|
|
||||||
sensor.DOMAIN: {
|
|
||||||
"name": "test",
|
|
||||||
"state_class": "total",
|
|
||||||
"state_topic": "test-topic",
|
|
||||||
"unit_of_measurement": "fav unit",
|
|
||||||
"last_reset_topic": "last-reset-topic",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
)
|
|
||||||
@pytest.mark.parametrize("datestring", ["2020-21-02 08:11:00", "Hello there!"])
|
|
||||||
async def test_setting_sensor_bad_last_reset_via_mqtt_message(
|
|
||||||
hass: HomeAssistant,
|
|
||||||
caplog: pytest.LogCaptureFixture,
|
|
||||||
datestring,
|
|
||||||
mqtt_mock_entry: MqttMockHAClientGenerator,
|
|
||||||
) -> None:
|
|
||||||
"""Test the setting of the last_reset property via MQTT."""
|
|
||||||
await mqtt_mock_entry()
|
|
||||||
|
|
||||||
async_fire_mqtt_message(hass, "last-reset-topic", datestring)
|
|
||||||
state = hass.states.get("sensor.test")
|
|
||||||
assert state.attributes.get("last_reset") is None
|
|
||||||
assert "Invalid last_reset message" in caplog.text
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"hass_config",
|
|
||||||
[
|
|
||||||
{
|
|
||||||
mqtt.DOMAIN: {
|
|
||||||
sensor.DOMAIN: {
|
|
||||||
"name": "test",
|
|
||||||
"state_class": "total",
|
|
||||||
"state_topic": "test-topic",
|
|
||||||
"unit_of_measurement": "fav unit",
|
|
||||||
"last_reset_topic": "last-reset-topic",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
)
|
|
||||||
async def test_setting_sensor_empty_last_reset_via_mqtt_message(
|
|
||||||
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
|
|
||||||
) -> None:
|
|
||||||
"""Test the setting of the last_reset property via MQTT."""
|
|
||||||
await mqtt_mock_entry()
|
|
||||||
|
|
||||||
async_fire_mqtt_message(hass, "last-reset-topic", "")
|
|
||||||
state = hass.states.get("sensor.test")
|
|
||||||
assert state.attributes.get("last_reset") is None
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"hass_config",
|
|
||||||
[
|
|
||||||
{
|
|
||||||
mqtt.DOMAIN: {
|
|
||||||
sensor.DOMAIN: {
|
|
||||||
"name": "test",
|
|
||||||
"state_class": "total",
|
|
||||||
"state_topic": "test-topic",
|
|
||||||
"unit_of_measurement": "fav unit",
|
|
||||||
"last_reset_topic": "last-reset-topic",
|
|
||||||
"last_reset_value_template": "{{ value_json.last_reset }}",
|
"last_reset_value_template": "{{ value_json.last_reset }}",
|
||||||
|
"value_template": "{{ value_json.state }}",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("message", "last_reset", "state"),
|
||||||
|
[
|
||||||
|
(
|
||||||
|
'{ "last_reset": "2020-01-02 08:11:00" }',
|
||||||
|
"2020-01-02T08:11:00",
|
||||||
|
STATE_UNKNOWN,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'{ "last_reset": "2020-01-02 08:11:03", "state": 10.0 }',
|
||||||
|
"2020-01-02T08:11:03",
|
||||||
|
"10.0",
|
||||||
|
),
|
||||||
|
('{ "last_reset": null, "state": 10.1 }', None, "10.1"),
|
||||||
|
('{ "last_reset": "", "state": 10.1 }', None, "10.1"),
|
||||||
|
],
|
||||||
|
)
|
||||||
async def test_setting_sensor_last_reset_via_mqtt_json_message(
|
async def test_setting_sensor_last_reset_via_mqtt_json_message(
|
||||||
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
|
hass: HomeAssistant,
|
||||||
|
mqtt_mock_entry: MqttMockHAClientGenerator,
|
||||||
|
message: str,
|
||||||
|
last_reset: str,
|
||||||
|
state: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the setting of the value via MQTT with JSON payload."""
|
"""Test the setting of the value via MQTT with JSON payload."""
|
||||||
await mqtt_mock_entry()
|
await mqtt_mock_entry()
|
||||||
|
|
||||||
async_fire_mqtt_message(
|
async_fire_mqtt_message(hass, "test-topic", message)
|
||||||
hass, "last-reset-topic", '{ "last_reset": "2020-01-02 08:11:00" }'
|
sensor_state = hass.states.get("sensor.test")
|
||||||
)
|
assert sensor_state.attributes.get("last_reset") == last_reset
|
||||||
state = hass.states.get("sensor.test")
|
assert sensor_state.state == state
|
||||||
assert state.attributes.get("last_reset") == "2020-01-02T08:11:00"
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
|
@ -608,19 +535,6 @@ async def test_setting_sensor_last_reset_via_mqtt_json_message(
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
mqtt.DOMAIN: {
|
|
||||||
sensor.DOMAIN: {
|
|
||||||
"name": "test",
|
|
||||||
"state_class": "total",
|
|
||||||
"state_topic": "test-topic",
|
|
||||||
"unit_of_measurement": "kWh",
|
|
||||||
"value_template": "{{ value_json.value | float / 60000 }}",
|
|
||||||
"last_reset_value_template": "{{ utcnow().fromtimestamp(value_json.time / 1000, tz=utcnow().tzinfo) }}",
|
|
||||||
"last_reset_topic": "test-topic",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_setting_sensor_last_reset_via_mqtt_json_message_2(
|
async def test_setting_sensor_last_reset_via_mqtt_json_message_2(
|
||||||
|
@ -640,11 +554,6 @@ async def test_setting_sensor_last_reset_via_mqtt_json_message_2(
|
||||||
state = hass.states.get("sensor.test")
|
state = hass.states.get("sensor.test")
|
||||||
assert float(state.state) == pytest.approx(0.015796176944444445)
|
assert float(state.state) == pytest.approx(0.015796176944444445)
|
||||||
assert state.attributes.get("last_reset") == "2021-08-19T15:05:00+00:00"
|
assert state.attributes.get("last_reset") == "2021-08-19T15:05:00+00:00"
|
||||||
assert "'last_reset_topic' must be same as 'state_topic'" not in caplog.text
|
|
||||||
assert (
|
|
||||||
"'last_reset_value_template' must be set if 'last_reset_topic' is set"
|
|
||||||
not in caplog.text
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
|
|
Loading…
Add table
Reference in a new issue