Remove deprecated features from MQTT platforms (#32909)

* Remove deprecated features

* Lint
This commit is contained in:
Erik Montnemery 2020-03-19 06:39:15 +01:00 committed by GitHub
parent 5c1dc60505
commit e0d2e5dcb0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 30 additions and 305 deletions

View file

@ -11,7 +11,7 @@ from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.typing import HomeAssistantType from homeassistant.helpers.typing import HomeAssistantType
from .abbreviations import ABBREVIATIONS, DEVICE_ABBREVIATIONS from .abbreviations import ABBREVIATIONS, DEVICE_ABBREVIATIONS
from .const import ATTR_DISCOVERY_HASH, ATTR_DISCOVERY_TOPIC, CONF_STATE_TOPIC from .const import ATTR_DISCOVERY_HASH, ATTR_DISCOVERY_TOPIC
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -50,15 +50,6 @@ CONFIG_ENTRY_COMPONENTS = [
"vacuum", "vacuum",
] ]
DEPRECATED_PLATFORM_TO_SCHEMA = {
"light": {"mqtt_json": "json", "mqtt_template": "template"}
}
# These components require state_topic to be set.
# If not specified, infer state_topic from discovery topic.
IMPLICIT_STATE_TOPIC_COMPONENTS = ["alarm_control_panel", "binary_sensor", "sensor"]
ALREADY_DISCOVERED = "mqtt_discovered_components" ALREADY_DISCOVERED = "mqtt_discovered_components"
DATA_CONFIG_ENTRY_LOCK = "mqtt_config_entry_lock" DATA_CONFIG_ENTRY_LOCK = "mqtt_config_entry_lock"
CONFIG_ENTRY_IS_SETUP = "mqtt_config_entry_is_setup" CONFIG_ENTRY_IS_SETUP = "mqtt_config_entry_is_setup"
@ -143,39 +134,8 @@ async def async_start(
} }
setattr(payload, "discovery_data", discovery_data) setattr(payload, "discovery_data", discovery_data)
if CONF_PLATFORM in payload and "schema" not in payload:
platform = payload[CONF_PLATFORM]
if (
component in DEPRECATED_PLATFORM_TO_SCHEMA
and platform in DEPRECATED_PLATFORM_TO_SCHEMA[component]
):
schema = DEPRECATED_PLATFORM_TO_SCHEMA[component][platform]
payload["schema"] = schema
_LOGGER.warning(
'"platform": "%s" is deprecated, ' 'replace with "schema":"%s"',
platform,
schema,
)
payload[CONF_PLATFORM] = "mqtt" payload[CONF_PLATFORM] = "mqtt"
if (
CONF_STATE_TOPIC not in payload
and component in IMPLICIT_STATE_TOPIC_COMPONENTS
):
# state_topic not specified, infer from discovery topic
fmt_node_id = f"{node_id}/" if node_id else ""
payload[
CONF_STATE_TOPIC
] = f"{discovery_topic}/{component}/{fmt_node_id}{object_id}/state"
_LOGGER.warning(
'implicit %s is deprecated, add "%s":"%s" to '
"%s discovery message",
CONF_STATE_TOPIC,
CONF_STATE_TOPIC,
payload[CONF_STATE_TOPIC],
topic,
)
if ALREADY_DISCOVERED not in hass.data: if ALREADY_DISCOVERED not in hass.data:
hass.data[ALREADY_DISCOVERED] = {} hass.data[ALREADY_DISCOVERED] = {}
if discovery_hash in hass.data[ALREADY_DISCOVERED]: if discovery_hash in hass.data[ALREADY_DISCOVERED]:

View file

@ -1,6 +1,5 @@
"""Support for MQTT sensors.""" """Support for MQTT sensors."""
from datetime import timedelta from datetime import timedelta
import json
import logging import logging
from typing import Optional from typing import Optional
@ -41,7 +40,6 @@ from .discovery import MQTT_DISCOVERY_NEW, clear_discovery_hash
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
CONF_EXPIRE_AFTER = "expire_after" CONF_EXPIRE_AFTER = "expire_after"
CONF_JSON_ATTRS = "json_attributes"
DEFAULT_NAME = "MQTT Sensor" DEFAULT_NAME = "MQTT Sensor"
DEFAULT_FORCE_UPDATE = False DEFAULT_FORCE_UPDATE = False
@ -53,7 +51,6 @@ PLATFORM_SCHEMA = (
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_ICON): cv.icon, vol.Optional(CONF_ICON): cv.icon,
vol.Optional(CONF_JSON_ATTRS, default=[]): cv.ensure_list_csv,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_UNIQUE_ID): cv.string, vol.Optional(CONF_UNIQUE_ID): cv.string,
vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string, vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string,
@ -110,16 +107,9 @@ class MqttSensor(
self._state = None self._state = None
self._sub_state = None self._sub_state = None
self._expiration_trigger = None self._expiration_trigger = None
self._attributes = None
device_config = config.get(CONF_DEVICE) device_config = config.get(CONF_DEVICE)
if config.get(CONF_JSON_ATTRS):
_LOGGER.warning(
'configuration variable "json_attributes" is '
'deprecated, replace with "json_attributes_topic"'
)
MqttAttributes.__init__(self, config) MqttAttributes.__init__(self, config)
MqttAvailability.__init__(self, config) MqttAvailability.__init__(self, config)
MqttDiscoveryUpdate.__init__(self, discovery_data, self.discovery_update) MqttDiscoveryUpdate.__init__(self, discovery_data, self.discovery_update)
@ -165,22 +155,6 @@ class MqttSensor(
self.hass, self.value_is_expired, expiration_at self.hass, self.value_is_expired, expiration_at
) )
json_attributes = set(self._config[CONF_JSON_ATTRS])
if json_attributes:
self._attributes = {}
try:
json_dict = json.loads(payload)
if isinstance(json_dict, dict):
attrs = {
k: json_dict[k] for k in json_attributes & json_dict.keys()
}
self._attributes = attrs
else:
_LOGGER.warning("JSON result was not a dictionary")
except ValueError:
_LOGGER.warning("MQTT payload could not be parsed as JSON")
_LOGGER.debug("Erroneous JSON: %s", payload)
if template is not None: if template is not None:
payload = template.async_render_with_possible_json_value( payload = template.async_render_with_possible_json_value(
payload, self._state payload, self._state
@ -241,11 +215,6 @@ class MqttSensor(
"""Return the state of the entity.""" """Return the state of the entity."""
return self._state return self._state
@property
def device_state_attributes(self):
"""Return the state attributes."""
return self._attributes
@property @property
def unique_id(self): def unique_id(self):
"""Return a unique ID.""" """Return a unique ID."""

View file

@ -117,7 +117,9 @@ async def test_correct_config_discovery(hass, mqtt_mock, caplog):
await async_start(hass, "homeassistant", {}, entry) await async_start(hass, "homeassistant", {}, entry)
async_fire_mqtt_message( async_fire_mqtt_message(
hass, "homeassistant/binary_sensor/bla/config", '{ "name": "Beer" }' hass,
"homeassistant/binary_sensor/bla/config",
'{ "name": "Beer", "state_topic": "test-topic" }',
) )
await hass.async_block_till_done() await hass.async_block_till_done()
@ -199,7 +201,9 @@ async def test_discovery_incl_nodeid(hass, mqtt_mock, caplog):
await async_start(hass, "homeassistant", {}, entry) await async_start(hass, "homeassistant", {}, entry)
async_fire_mqtt_message( async_fire_mqtt_message(
hass, "homeassistant/binary_sensor/my_node_id/bla/config", '{ "name": "Beer" }', hass,
"homeassistant/binary_sensor/my_node_id/bla/config",
'{ "name": "Beer", "state_topic": "test-topic" }',
) )
await hass.async_block_till_done() await hass.async_block_till_done()
@ -217,10 +221,14 @@ async def test_non_duplicate_discovery(hass, mqtt_mock, caplog):
await async_start(hass, "homeassistant", {}, entry) await async_start(hass, "homeassistant", {}, entry)
async_fire_mqtt_message( async_fire_mqtt_message(
hass, "homeassistant/binary_sensor/bla/config", '{ "name": "Beer" }' hass,
"homeassistant/binary_sensor/bla/config",
'{ "name": "Beer", "state_topic": "test-topic" }',
) )
async_fire_mqtt_message( async_fire_mqtt_message(
hass, "homeassistant/binary_sensor/bla/config", '{ "name": "Beer" }' hass,
"homeassistant/binary_sensor/bla/config",
'{ "name": "Beer", "state_topic": "test-topic" }',
) )
await hass.async_block_till_done() await hass.async_block_till_done()
@ -240,7 +248,9 @@ async def test_removal(hass, mqtt_mock, caplog):
await async_start(hass, "homeassistant", {}, entry) await async_start(hass, "homeassistant", {}, entry)
async_fire_mqtt_message( async_fire_mqtt_message(
hass, "homeassistant/binary_sensor/bla/config", '{ "name": "Beer" }' hass,
"homeassistant/binary_sensor/bla/config",
'{ "name": "Beer", "state_topic": "test-topic" }',
) )
await hass.async_block_till_done() await hass.async_block_till_done()
state = hass.states.get("binary_sensor.beer") state = hass.states.get("binary_sensor.beer")
@ -259,7 +269,9 @@ async def test_rediscover(hass, mqtt_mock, caplog):
await async_start(hass, "homeassistant", {}, entry) await async_start(hass, "homeassistant", {}, entry)
async_fire_mqtt_message( async_fire_mqtt_message(
hass, "homeassistant/binary_sensor/bla/config", '{ "name": "Beer" }' hass,
"homeassistant/binary_sensor/bla/config",
'{ "name": "Beer", "state_topic": "test-topic" }',
) )
await hass.async_block_till_done() await hass.async_block_till_done()
state = hass.states.get("binary_sensor.beer") state = hass.states.get("binary_sensor.beer")
@ -271,7 +283,9 @@ async def test_rediscover(hass, mqtt_mock, caplog):
assert state is None assert state is None
async_fire_mqtt_message( async_fire_mqtt_message(
hass, "homeassistant/binary_sensor/bla/config", '{ "name": "Beer" }' hass,
"homeassistant/binary_sensor/bla/config",
'{ "name": "Beer", "state_topic": "test-topic" }',
) )
await hass.async_block_till_done() await hass.async_block_till_done()
state = hass.states.get("binary_sensor.beer") state = hass.states.get("binary_sensor.beer")
@ -285,7 +299,9 @@ async def test_duplicate_removal(hass, mqtt_mock, caplog):
await async_start(hass, "homeassistant", {}, entry) await async_start(hass, "homeassistant", {}, entry)
async_fire_mqtt_message( async_fire_mqtt_message(
hass, "homeassistant/binary_sensor/bla/config", '{ "name": "Beer" }' hass,
"homeassistant/binary_sensor/bla/config",
'{ "name": "Beer", "state_topic": "test-topic" }',
) )
await hass.async_block_till_done() await hass.async_block_till_done()
async_fire_mqtt_message(hass, "homeassistant/binary_sensor/bla/config", "") async_fire_mqtt_message(hass, "homeassistant/binary_sensor/bla/config", "")
@ -431,93 +447,6 @@ async def test_missing_discover_abbreviations(hass, mqtt_mock, caplog):
assert not missing assert not missing
async def test_implicit_state_topic_alarm(hass, mqtt_mock, caplog):
"""Test implicit state topic for alarm_control_panel."""
entry = MockConfigEntry(domain=mqtt.DOMAIN)
await async_start(hass, "homeassistant", {}, entry)
data = (
'{ "name": "Test1",'
' "command_topic": "homeassistant/alarm_control_panel/bla/cmnd"'
"}"
)
async_fire_mqtt_message(hass, "homeassistant/alarm_control_panel/bla/config", data)
await hass.async_block_till_done()
assert (
"implicit state_topic is deprecated, add "
'"state_topic":"homeassistant/alarm_control_panel/bla/state"' in caplog.text
)
state = hass.states.get("alarm_control_panel.Test1")
assert state is not None
assert state.name == "Test1"
assert ("alarm_control_panel", "bla") in hass.data[ALREADY_DISCOVERED]
assert state.state == "unknown"
async_fire_mqtt_message(
hass, "homeassistant/alarm_control_panel/bla/state", "armed_away"
)
state = hass.states.get("alarm_control_panel.Test1")
assert state.state == "armed_away"
async def test_implicit_state_topic_binary_sensor(hass, mqtt_mock, caplog):
"""Test implicit state topic for binary_sensor."""
entry = MockConfigEntry(domain=mqtt.DOMAIN)
await async_start(hass, "homeassistant", {}, entry)
data = '{ "name": "Test1"' "}"
async_fire_mqtt_message(hass, "homeassistant/binary_sensor/bla/config", data)
await hass.async_block_till_done()
assert (
"implicit state_topic is deprecated, add "
'"state_topic":"homeassistant/binary_sensor/bla/state"' in caplog.text
)
state = hass.states.get("binary_sensor.Test1")
assert state is not None
assert state.name == "Test1"
assert ("binary_sensor", "bla") in hass.data[ALREADY_DISCOVERED]
assert state.state == "off"
async_fire_mqtt_message(hass, "homeassistant/binary_sensor/bla/state", "ON")
state = hass.states.get("binary_sensor.Test1")
assert state.state == "on"
async def test_implicit_state_topic_sensor(hass, mqtt_mock, caplog):
"""Test implicit state topic for sensor."""
entry = MockConfigEntry(domain=mqtt.DOMAIN)
await async_start(hass, "homeassistant", {}, entry)
data = '{ "name": "Test1"' "}"
async_fire_mqtt_message(hass, "homeassistant/sensor/bla/config", data)
await hass.async_block_till_done()
assert (
"implicit state_topic is deprecated, add "
'"state_topic":"homeassistant/sensor/bla/state"' in caplog.text
)
state = hass.states.get("sensor.Test1")
assert state is not None
assert state.name == "Test1"
assert ("sensor", "bla") in hass.data[ALREADY_DISCOVERED]
assert state.state == "unknown"
async_fire_mqtt_message(hass, "homeassistant/sensor/bla/state", "1234")
state = hass.states.get("sensor.Test1")
assert state.state == "1234"
async def test_no_implicit_state_topic_switch(hass, mqtt_mock, caplog): async def test_no_implicit_state_topic_switch(hass, mqtt_mock, caplog):
"""Test no implicit state topic for switch.""" """Test no implicit state topic for switch."""
entry = MockConfigEntry(domain=mqtt.DOMAIN) entry = MockConfigEntry(domain=mqtt.DOMAIN)
@ -552,7 +481,7 @@ async def test_complex_discovery_topic_prefix(hass, mqtt_mock, caplog):
async_fire_mqtt_message( async_fire_mqtt_message(
hass, hass,
("my_home/homeassistant/register/binary_sensor/node1/object1/config"), ("my_home/homeassistant/register/binary_sensor/node1/object1/config"),
'{ "name": "Beer" }', '{ "name": "Beer", "state_topic": "test-topic" }',
) )
await hass.async_block_till_done() await hass.async_block_till_done()

View file

@ -91,8 +91,7 @@ import json
from unittest import mock from unittest import mock
from unittest.mock import patch from unittest.mock import patch
from homeassistant.components import light, mqtt from homeassistant.components import light
from homeassistant.components.mqtt.discovery import async_start
from homeassistant.const import ( from homeassistant.const import (
ATTR_ASSUMED_STATE, ATTR_ASSUMED_STATE,
ATTR_SUPPORTED_FEATURES, ATTR_SUPPORTED_FEATURES,
@ -122,7 +121,7 @@ from .common import (
help_test_update_with_json_attrs_not_dict, help_test_update_with_json_attrs_not_dict,
) )
from tests.common import MockConfigEntry, async_fire_mqtt_message, mock_coro from tests.common import async_fire_mqtt_message, mock_coro
from tests.components.light import common from tests.components.light import common
DEFAULT_CONFIG = { DEFAULT_CONFIG = {
@ -1061,22 +1060,6 @@ async def test_discovery_removal(hass, mqtt_mock, caplog):
await help_test_discovery_removal(hass, mqtt_mock, caplog, light.DOMAIN, data) await help_test_discovery_removal(hass, mqtt_mock, caplog, light.DOMAIN, data)
async def test_discovery_deprecated(hass, mqtt_mock, caplog):
"""Test discovery of mqtt_json light with deprecated platform option."""
entry = MockConfigEntry(domain=mqtt.DOMAIN)
await async_start(hass, "homeassistant", {"mqtt": {}}, entry)
data = (
'{ "name": "Beer",'
' "platform": "mqtt_json",'
' "command_topic": "test_topic"}'
)
async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data)
await hass.async_block_till_done()
state = hass.states.get("light.beer")
assert state is not None
assert state.name == "Beer"
async def test_discovery_update_light(hass, mqtt_mock, caplog): async def test_discovery_update_light(hass, mqtt_mock, caplog):
"""Test update of discovered light.""" """Test update of discovered light."""
data1 = ( data1 = (

View file

@ -28,8 +28,7 @@ If your light doesn't support RGB feature, omit `(red|green|blue)_template`.
""" """
from unittest.mock import patch from unittest.mock import patch
from homeassistant.components import light, mqtt from homeassistant.components import light
from homeassistant.components.mqtt.discovery import async_start
from homeassistant.const import ( from homeassistant.const import (
ATTR_ASSUMED_STATE, ATTR_ASSUMED_STATE,
ATTR_SUPPORTED_FEATURES, ATTR_SUPPORTED_FEATURES,
@ -59,12 +58,7 @@ from .common import (
help_test_update_with_json_attrs_not_dict, help_test_update_with_json_attrs_not_dict,
) )
from tests.common import ( from tests.common import assert_setup_component, async_fire_mqtt_message, mock_coro
MockConfigEntry,
assert_setup_component,
async_fire_mqtt_message,
mock_coro,
)
from tests.components.light import common from tests.components.light import common
DEFAULT_CONFIG = { DEFAULT_CONFIG = {
@ -883,24 +877,6 @@ async def test_discovery_removal(hass, mqtt_mock, caplog):
await help_test_discovery_removal(hass, mqtt_mock, caplog, light.DOMAIN, data) await help_test_discovery_removal(hass, mqtt_mock, caplog, light.DOMAIN, data)
async def test_discovery_deprecated(hass, mqtt_mock, caplog):
"""Test discovery of mqtt template light with deprecated option."""
entry = MockConfigEntry(domain=mqtt.DOMAIN)
await async_start(hass, "homeassistant", {"mqtt": {}}, entry)
data = (
'{ "name": "Beer",'
' "platform": "mqtt_template",'
' "command_topic": "test_topic",'
' "command_on_template": "on",'
' "command_off_template": "off"}'
)
async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data)
await hass.async_block_till_done()
state = hass.states.get("light.beer")
assert state is not None
assert state.name == "Beer"
async def test_discovery_update_light(hass, mqtt_mock, caplog): async def test_discovery_update_light(hass, mqtt_mock, caplog):
"""Test update of discovered light.""" """Test update of discovered light."""
data1 = ( data1 = (

View file

@ -240,98 +240,6 @@ async def test_custom_availability_payload(hass, mqtt_mock):
) )
async def test_setting_sensor_attribute_via_legacy_mqtt_json_message(hass, mqtt_mock):
"""Test the setting of attribute via MQTT with JSON payload."""
assert await async_setup_component(
hass,
sensor.DOMAIN,
{
sensor.DOMAIN: {
"platform": "mqtt",
"name": "test",
"state_topic": "test-topic",
"unit_of_measurement": "fav unit",
"json_attributes_topic": "test-attributes-topic",
}
},
)
async_fire_mqtt_message(hass, "test-attributes-topic", '{ "val": "100" }')
state = hass.states.get("sensor.test")
assert state.attributes.get("val") == "100"
async def test_update_with_legacy_json_attrs_not_dict(hass, mqtt_mock, caplog):
"""Test attributes get extracted from a JSON result."""
assert await async_setup_component(
hass,
sensor.DOMAIN,
{
sensor.DOMAIN: {
"platform": "mqtt",
"name": "test",
"state_topic": "test-topic",
"unit_of_measurement": "fav unit",
"json_attributes_topic": "test-attributes-topic",
}
},
)
async_fire_mqtt_message(hass, "test-attributes-topic", '[ "list", "of", "things"]')
state = hass.states.get("sensor.test")
assert state.attributes.get("val") is None
assert "JSON result was not a dictionary" in caplog.text
async def test_update_with_legacy_json_attrs_bad_JSON(hass, mqtt_mock, caplog):
"""Test attributes get extracted from a JSON result."""
assert await async_setup_component(
hass,
sensor.DOMAIN,
{
sensor.DOMAIN: {
"platform": "mqtt",
"name": "test",
"state_topic": "test-topic",
"unit_of_measurement": "fav unit",
"json_attributes_topic": "test-attributes-topic",
}
},
)
async_fire_mqtt_message(hass, "test-attributes-topic", "This is not JSON")
state = hass.states.get("sensor.test")
assert state.attributes.get("val") is None
assert "Erroneous JSON: This is not JSON" in caplog.text
async def test_update_with_legacy_json_attrs_and_template(hass, mqtt_mock):
"""Test attributes get extracted from a JSON result."""
assert await async_setup_component(
hass,
sensor.DOMAIN,
{
sensor.DOMAIN: {
"platform": "mqtt",
"name": "test",
"state_topic": "test-topic",
"unit_of_measurement": "fav unit",
"value_template": "{{ value_json.val }}",
"json_attributes": "val",
}
},
)
async_fire_mqtt_message(hass, "test-topic", '{ "val": "100" }')
state = hass.states.get("sensor.test")
assert state.attributes.get("val") == "100"
assert state.state == "100"
async def test_invalid_device_class(hass, mqtt_mock): async def test_invalid_device_class(hass, mqtt_mock):
"""Test device_class option with invalid value.""" """Test device_class option with invalid value."""
assert await async_setup_component( assert await async_setup_component(