diff --git a/homeassistant/components/mqtt/camera.py b/homeassistant/components/mqtt/camera.py index 9bbb1503196..a75ae33f861 100644 --- a/homeassistant/components/mqtt/camera.py +++ b/homeassistant/components/mqtt/camera.py @@ -4,7 +4,7 @@ import logging import voluptuous as vol from homeassistant.components import camera, mqtt -from homeassistant.components.camera import PLATFORM_SCHEMA, Camera +from homeassistant.components.camera import Camera from homeassistant.const import CONF_DEVICE, CONF_NAME from homeassistant.core import callback from homeassistant.helpers import config_validation as cv @@ -13,7 +13,10 @@ from homeassistant.helpers.typing import ConfigType, HomeAssistantType from . import ( ATTR_DISCOVERY_HASH, + CONF_QOS, CONF_UNIQUE_ID, + MqttAttributes, + MqttAvailability, MqttDiscoveryUpdate, MqttEntityDeviceInfo, subscription, @@ -25,13 +28,17 @@ _LOGGER = logging.getLogger(__name__) CONF_TOPIC = "topic" DEFAULT_NAME = "MQTT Camera" -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( - { - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Required(CONF_TOPIC): mqtt.valid_subscribe_topic, - vol.Optional(CONF_UNIQUE_ID): cv.string, - vol.Optional(CONF_DEVICE): mqtt.MQTT_ENTITY_DEVICE_INFO_SCHEMA, - } +PLATFORM_SCHEMA = ( + mqtt.MQTT_BASE_PLATFORM_SCHEMA.extend( + { + vol.Optional(CONF_DEVICE): mqtt.MQTT_ENTITY_DEVICE_INFO_SCHEMA, + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, + vol.Required(CONF_TOPIC): mqtt.valid_subscribe_topic, + vol.Optional(CONF_UNIQUE_ID): cv.string, + } + ) + .extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema) + .extend(mqtt.MQTT_JSON_ATTRS_SCHEMA.schema) ) @@ -69,7 +76,9 @@ async def _async_setup_entity( async_add_entities([MqttCamera(config, config_entry, discovery_data)]) -class MqttCamera(MqttDiscoveryUpdate, MqttEntityDeviceInfo, Camera): +class MqttCamera( + MqttAttributes, MqttAvailability, MqttDiscoveryUpdate, MqttEntityDeviceInfo, Camera +): """representation of a MQTT camera.""" def __init__(self, config, config_entry, discovery_data): @@ -78,12 +87,13 @@ class MqttCamera(MqttDiscoveryUpdate, MqttEntityDeviceInfo, Camera): self._unique_id = config.get(CONF_UNIQUE_ID) self._sub_state = None - self._qos = 0 self._last_image = None device_config = config.get(CONF_DEVICE) Camera.__init__(self) + MqttAttributes.__init__(self, config) + MqttAvailability.__init__(self, config) MqttDiscoveryUpdate.__init__(self, discovery_data, self.discovery_update) MqttEntityDeviceInfo.__init__(self, device_config, config_entry) @@ -96,6 +106,8 @@ class MqttCamera(MqttDiscoveryUpdate, MqttEntityDeviceInfo, Camera): """Handle updated discovery message.""" config = PLATFORM_SCHEMA(discovery_payload) self._config = config + await self.attributes_discovery_update(config) + await self.availability_discovery_update(config) await self.device_info_discovery_update(config) await self._subscribe_topics() self.async_write_ha_state() @@ -115,7 +127,7 @@ class MqttCamera(MqttDiscoveryUpdate, MqttEntityDeviceInfo, Camera): "state_topic": { "topic": self._config[CONF_TOPIC], "msg_callback": message_received, - "qos": self._qos, + "qos": self._config[CONF_QOS], "encoding": None, } }, @@ -126,6 +138,8 @@ class MqttCamera(MqttDiscoveryUpdate, MqttEntityDeviceInfo, Camera): self._sub_state = await subscription.async_unsubscribe_topics( self.hass, self._sub_state ) + await MqttAttributes.async_will_remove_from_hass(self) + await MqttAvailability.async_will_remove_from_hass(self) await MqttDiscoveryUpdate.async_will_remove_from_hass(self) async def async_camera_image(self): diff --git a/tests/components/mqtt/test_camera.py b/tests/components/mqtt/test_camera.py index f77e5945ae5..96ea9b3005f 100644 --- a/tests/components/mqtt/test_camera.py +++ b/tests/components/mqtt/test_camera.py @@ -6,15 +6,23 @@ from homeassistant.components.mqtt.discovery import async_start from homeassistant.setup import async_setup_component from .common import ( + help_test_availability_without_topic, + help_test_custom_availability_payload, + help_test_default_availability_payload, help_test_discovery_broken, help_test_discovery_removal, help_test_discovery_update, + help_test_discovery_update_attr, help_test_entity_device_info_remove, help_test_entity_device_info_update, help_test_entity_device_info_with_connection, help_test_entity_device_info_with_identifier, help_test_entity_id_update, + help_test_setting_attribute_via_mqtt_json_message, + help_test_setting_attribute_with_template, help_test_unique_id, + help_test_update_with_json_attrs_bad_JSON, + help_test_update_with_json_attrs_not_dict, ) from tests.common import ( @@ -49,6 +57,62 @@ async def test_run_camera_setup(hass, aiohttp_client): assert body == "beer" +async def test_availability_without_topic(hass, mqtt_mock): + """Test availability without defined availability topic.""" + await help_test_availability_without_topic( + hass, mqtt_mock, camera.DOMAIN, DEFAULT_CONFIG + ) + + +async def test_default_availability_payload(hass, mqtt_mock): + """Test availability by default payload with defined topic.""" + await help_test_default_availability_payload( + hass, mqtt_mock, camera.DOMAIN, DEFAULT_CONFIG + ) + + +async def test_custom_availability_payload(hass, mqtt_mock): + """Test availability by custom payload with defined topic.""" + await help_test_custom_availability_payload( + hass, mqtt_mock, camera.DOMAIN, DEFAULT_CONFIG + ) + + +async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock): + """Test the setting of attribute via MQTT with JSON payload.""" + await help_test_setting_attribute_via_mqtt_json_message( + hass, mqtt_mock, camera.DOMAIN, DEFAULT_CONFIG + ) + + +async def test_setting_attribute_with_template(hass, mqtt_mock): + """Test the setting of attribute via MQTT with JSON payload.""" + await help_test_setting_attribute_with_template( + hass, mqtt_mock, camera.DOMAIN, DEFAULT_CONFIG + ) + + +async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog): + """Test attributes get extracted from a JSON result.""" + await help_test_update_with_json_attrs_not_dict( + hass, mqtt_mock, caplog, camera.DOMAIN, DEFAULT_CONFIG + ) + + +async def test_update_with_json_attrs_bad_JSON(hass, mqtt_mock, caplog): + """Test attributes get extracted from a JSON result.""" + await help_test_update_with_json_attrs_bad_JSON( + hass, mqtt_mock, caplog, camera.DOMAIN, DEFAULT_CONFIG + ) + + +async def test_discovery_update_attr(hass, mqtt_mock, caplog): + """Test update of discovered MQTTAttributes.""" + await help_test_discovery_update_attr( + hass, mqtt_mock, caplog, camera.DOMAIN, DEFAULT_CONFIG + ) + + async def test_unique_id(hass): """Test unique id option only creates one camera per unique_id.""" config = {