Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reconfigure MQTT alarm component if discovery info is changed #18173

Merged
merged 1 commit into from
Nov 24, 2018
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
91 changes: 59 additions & 32 deletions homeassistant/components/alarm_control_panel/mqtt.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from homeassistant.components.mqtt import (
ATTR_DISCOVERY_HASH, CONF_AVAILABILITY_TOPIC, CONF_STATE_TOPIC,
CONF_COMMAND_TOPIC, CONF_PAYLOAD_AVAILABLE, CONF_PAYLOAD_NOT_AVAILABLE,
CONF_QOS, CONF_RETAIN, MqttAvailability, MqttDiscoveryUpdate)
CONF_QOS, CONF_RETAIN, MqttAvailability, MqttDiscoveryUpdate, subscription)
from homeassistant.components.mqtt.discovery import MQTT_DISCOVERY_NEW
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.dispatcher import async_dispatcher_connect
Expand Down Expand Up @@ -71,50 +71,69 @@ async def _async_setup_entity(hass, config, async_add_entities,
discovery_hash=None):
"""Set up the MQTT Alarm Control Panel platform."""
async_add_entities([MqttAlarm(
config.get(CONF_NAME),
config.get(CONF_STATE_TOPIC),
config.get(CONF_COMMAND_TOPIC),
config.get(CONF_QOS),
config.get(CONF_RETAIN),
config.get(CONF_PAYLOAD_DISARM),
config.get(CONF_PAYLOAD_ARM_HOME),
config.get(CONF_PAYLOAD_ARM_AWAY),
config.get(CONF_CODE),
config.get(CONF_AVAILABILITY_TOPIC),
config.get(CONF_PAYLOAD_AVAILABLE),
config.get(CONF_PAYLOAD_NOT_AVAILABLE),
config,
discovery_hash,)])


class MqttAlarm(MqttAvailability, MqttDiscoveryUpdate,
alarm.AlarmControlPanel):
"""Representation of a MQTT alarm status."""

def __init__(self, name, state_topic, command_topic, qos, retain,
payload_disarm, payload_arm_home, payload_arm_away, code,
availability_topic, payload_available, payload_not_available,
discovery_hash):
def __init__(self, config, discovery_hash):
"""Init the MQTT Alarm Control Panel."""
MqttAvailability.__init__(self, availability_topic, qos,
payload_available, payload_not_available)
MqttDiscoveryUpdate.__init__(self, discovery_hash)
self._state = STATE_UNKNOWN
self._name = name
self._state_topic = state_topic
self._command_topic = command_topic
self._qos = qos
self._retain = retain
self._payload_disarm = payload_disarm
self._payload_arm_home = payload_arm_home
self._payload_arm_away = payload_arm_away
self._code = code
self._discovery_hash = discovery_hash
self._config = config
self._sub_state = None

self._name = None
self._state_topic = None
self._command_topic = None
self._qos = None
self._retain = None
self._payload_disarm = None
self._payload_arm_home = None
self._payload_arm_away = None
self._code = None

# Load config
self._setup_from_config(config)

availability_topic = config.get(CONF_AVAILABILITY_TOPIC)
payload_available = config.get(CONF_PAYLOAD_AVAILABLE)
payload_not_available = config.get(CONF_PAYLOAD_NOT_AVAILABLE)
MqttAvailability.__init__(self, availability_topic, self._qos,
payload_available, payload_not_available)
MqttDiscoveryUpdate.__init__(self, discovery_hash,
self.discovery_update)

async def async_added_to_hass(self):
"""Subscribe mqtt events."""
await MqttAvailability.async_added_to_hass(self)
await MqttDiscoveryUpdate.async_added_to_hass(self)
await self._subscribe_topics()

async def discovery_update(self, discovery_payload):
"""Handle updated discovery message."""
config = PLATFORM_SCHEMA(discovery_payload)
self._setup_from_config(config)
await self.availability_discovery_update(config)
await self._subscribe_topics()
self.async_schedule_update_ha_state()

def _setup_from_config(self, config):
"""(Re)Setup the entity."""
self._name = config.get(CONF_NAME)
self._state_topic = config.get(CONF_STATE_TOPIC)
self._command_topic = config.get(CONF_COMMAND_TOPIC)
self._qos = config.get(CONF_QOS)
self._retain = config.get(CONF_RETAIN)
self._payload_disarm = config.get(CONF_PAYLOAD_DISARM)
self._payload_arm_home = config.get(CONF_PAYLOAD_ARM_HOME)
self._payload_arm_away = config.get(CONF_PAYLOAD_ARM_AWAY)
self._code = config.get(CONF_CODE)

async def _subscribe_topics(self):
"""(Re)Subscribe to topics."""
@callback
def message_received(topic, payload, qos):
"""Run when new MQTT message has been received."""
Expand All @@ -126,8 +145,16 @@ def message_received(topic, payload, qos):
self._state = payload
self.async_schedule_update_ha_state()

await mqtt.async_subscribe(
self.hass, self._state_topic, message_received, self._qos)
self._sub_state = await subscription.async_subscribe_topics(
self.hass, self._sub_state,
{'state_topic': {'topic': self._state_topic,
'msg_callback': message_received,
'qos': self._qos}})

async def async_will_remove_from_hass(self):
"""Unsubscribe when removed."""
await subscription.async_unsubscribe_topics(self.hass, self._sub_state)
await MqttAvailability.async_will_remove_from_hass(self)

@property
def should_poll(self):
Expand Down
39 changes: 39 additions & 0 deletions tests/components/alarm_control_panel/test_mqtt.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,3 +271,42 @@ async def test_discovery_removal_alarm(hass, mqtt_mock, caplog):

state = hass.states.get('alarm_control_panel.beer')
assert state is None


async def test_discovery_update_alarm(hass, mqtt_mock, caplog):
"""Test removal of discovered alarm_control_panel."""
entry = MockConfigEntry(domain=mqtt.DOMAIN)
await async_start(hass, 'homeassistant', {}, entry)

data1 = (
'{ "name": "Beer",'
' "status_topic": "test_topic",'
' "command_topic": "test_topic" }'
)
data2 = (
'{ "name": "Milk",'
' "status_topic": "test_topic",'
' "command_topic": "test_topic" }'
)

async_fire_mqtt_message(hass,
'homeassistant/alarm_control_panel/bla/config',
data1)
await hass.async_block_till_done()

state = hass.states.get('alarm_control_panel.beer')
assert state is not None
assert state.name == 'Beer'

async_fire_mqtt_message(hass,
'homeassistant/alarm_control_panel/bla/config',
data2)
await hass.async_block_till_done()
await hass.async_block_till_done()

state = hass.states.get('alarm_control_panel.beer')
assert state is not None
assert state.name == 'Milk'

state = hass.states.get('alarm_control_panel.milk')
assert state is None