Add device to mqtt camera (#26238)

* Add device to mqtt camera

* Support discovery device info update and add tests
This commit is contained in:
zewelor 2019-09-04 16:15:40 +02:00 committed by Erik Montnemery
parent 2c65e02491
commit c4c21d3e99
2 changed files with 99 additions and 7 deletions

View File

@ -7,13 +7,19 @@ import voluptuous as vol
from homeassistant.components import camera, mqtt from homeassistant.components import camera, mqtt
from homeassistant.components.camera import PLATFORM_SCHEMA, Camera from homeassistant.components.camera import PLATFORM_SCHEMA, Camera
from homeassistant.const import CONF_NAME from homeassistant.const import CONF_NAME, CONF_DEVICE
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.typing import ConfigType, HomeAssistantType from homeassistant.helpers.typing import ConfigType, HomeAssistantType
from . import ATTR_DISCOVERY_HASH, CONF_UNIQUE_ID, MqttDiscoveryUpdate, subscription from . import (
ATTR_DISCOVERY_HASH,
CONF_UNIQUE_ID,
MqttDiscoveryUpdate,
MqttEntityDeviceInfo,
subscription,
)
from .discovery import MQTT_DISCOVERY_NEW, clear_discovery_hash from .discovery import MQTT_DISCOVERY_NEW, clear_discovery_hash
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -26,6 +32,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Required(CONF_TOPIC): mqtt.valid_subscribe_topic, vol.Required(CONF_TOPIC): mqtt.valid_subscribe_topic,
vol.Optional(CONF_UNIQUE_ID): cv.string, vol.Optional(CONF_UNIQUE_ID): cv.string,
vol.Optional(CONF_DEVICE): mqtt.MQTT_ENTITY_DEVICE_INFO_SCHEMA,
} }
) )
@ -45,7 +52,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
try: try:
discovery_hash = discovery_payload.pop(ATTR_DISCOVERY_HASH) discovery_hash = discovery_payload.pop(ATTR_DISCOVERY_HASH)
config = PLATFORM_SCHEMA(discovery_payload) config = PLATFORM_SCHEMA(discovery_payload)
await _async_setup_entity(config, async_add_entities, discovery_hash) await _async_setup_entity(
config, async_add_entities, config_entry, discovery_hash
)
except Exception: except Exception:
if discovery_hash: if discovery_hash:
clear_discovery_hash(hass, discovery_hash) clear_discovery_hash(hass, discovery_hash)
@ -56,15 +65,17 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
) )
async def _async_setup_entity(config, async_add_entities, discovery_hash=None): async def _async_setup_entity(
config, async_add_entities, config_entry=None, discovery_hash=None
):
"""Set up the MQTT Camera.""" """Set up the MQTT Camera."""
async_add_entities([MqttCamera(config, discovery_hash)]) async_add_entities([MqttCamera(config, config_entry, discovery_hash)])
class MqttCamera(MqttDiscoveryUpdate, Camera): class MqttCamera(MqttDiscoveryUpdate, MqttEntityDeviceInfo, Camera):
"""representation of a MQTT camera.""" """representation of a MQTT camera."""
def __init__(self, config, discovery_hash): def __init__(self, config, config_entry, discovery_hash):
"""Initialize the MQTT Camera.""" """Initialize the MQTT Camera."""
self._config = config self._config = config
self._unique_id = config.get(CONF_UNIQUE_ID) self._unique_id = config.get(CONF_UNIQUE_ID)
@ -73,8 +84,11 @@ class MqttCamera(MqttDiscoveryUpdate, Camera):
self._qos = 0 self._qos = 0
self._last_image = None self._last_image = None
device_config = config.get(CONF_DEVICE)
Camera.__init__(self) Camera.__init__(self)
MqttDiscoveryUpdate.__init__(self, discovery_hash, self.discovery_update) MqttDiscoveryUpdate.__init__(self, discovery_hash, self.discovery_update)
MqttEntityDeviceInfo.__init__(self, device_config, config_entry)
async def async_added_to_hass(self): async def async_added_to_hass(self):
"""Subscribe MQTT events.""" """Subscribe MQTT events."""
@ -85,6 +99,7 @@ class MqttCamera(MqttDiscoveryUpdate, Camera):
"""Handle updated discovery message.""" """Handle updated discovery message."""
config = PLATFORM_SCHEMA(discovery_payload) config = PLATFORM_SCHEMA(discovery_payload)
self._config = config self._config = config
await self.device_info_discovery_update(config)
await self._subscribe_topics() await self._subscribe_topics()
self.async_write_ha_state() self.async_write_ha_state()

View File

@ -1,5 +1,6 @@
"""The tests for mqtt camera component.""" """The tests for mqtt camera component."""
from unittest.mock import ANY from unittest.mock import ANY
import json
from homeassistant.components import camera, mqtt from homeassistant.components import camera, mqtt
from homeassistant.components.mqtt.discovery import async_start from homeassistant.components.mqtt.discovery import async_start
@ -167,3 +168,79 @@ async def test_entity_id_update(hass, mqtt_mock):
assert state is not None assert state is not None
assert mock_mqtt.async_subscribe.call_count == 1 assert mock_mqtt.async_subscribe.call_count == 1
mock_mqtt.async_subscribe.assert_any_call("test-topic", ANY, 0, None) mock_mqtt.async_subscribe.assert_any_call("test-topic", ANY, 0, None)
async def test_entity_device_info_with_identifier(hass, mqtt_mock):
"""Test MQTT camera device registry integration."""
entry = MockConfigEntry(domain=mqtt.DOMAIN)
entry.add_to_hass(hass)
await async_start(hass, "homeassistant", {}, entry)
registry = await hass.helpers.device_registry.async_get_registry()
data = json.dumps(
{
"platform": "mqtt",
"name": "Test 1",
"topic": "test-topic",
"device": {
"identifiers": ["helloworld"],
"connections": [["mac", "02:5b:26:a8:dc:12"]],
"manufacturer": "Whatever",
"name": "Beer",
"model": "Glass",
"sw_version": "0.1-beta",
},
"unique_id": "veryunique",
}
)
async_fire_mqtt_message(hass, "homeassistant/camera/bla/config", data)
await hass.async_block_till_done()
device = registry.async_get_device({("mqtt", "helloworld")}, set())
assert device is not None
assert device.identifiers == {("mqtt", "helloworld")}
assert device.connections == {("mac", "02:5b:26:a8:dc:12")}
assert device.manufacturer == "Whatever"
assert device.name == "Beer"
assert device.model == "Glass"
assert device.sw_version == "0.1-beta"
async def test_entity_device_info_update(hass, mqtt_mock):
"""Test device registry update."""
entry = MockConfigEntry(domain=mqtt.DOMAIN)
entry.add_to_hass(hass)
await async_start(hass, "homeassistant", {}, entry)
registry = await hass.helpers.device_registry.async_get_registry()
config = {
"platform": "mqtt",
"name": "Test 1",
"topic": "test-topic",
"device": {
"identifiers": ["helloworld"],
"connections": [["mac", "02:5b:26:a8:dc:12"]],
"manufacturer": "Whatever",
"name": "Beer",
"model": "Glass",
"sw_version": "0.1-beta",
},
"unique_id": "veryunique",
}
data = json.dumps(config)
async_fire_mqtt_message(hass, "homeassistant/camera/bla/config", data)
await hass.async_block_till_done()
device = registry.async_get_device({("mqtt", "helloworld")}, set())
assert device is not None
assert device.name == "Beer"
config["device"]["name"] = "Milk"
data = json.dumps(config)
async_fire_mqtt_message(hass, "homeassistant/camera/bla/config", data)
await hass.async_block_till_done()
device = registry.async_get_device({("mqtt", "helloworld")}, set())
assert device is not None
assert device.name == "Milk"