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 binary_sensor component if discovery info is changed #18169

Merged

Conversation

emontnemery
Copy link
Contributor

@emontnemery emontnemery commented Nov 3, 2018

Description:

Reconfigure component if discovery info is changed.
This is bullet 2 in home-assistant/architecture#70

PRs for other platforms will be opened separately.

Checklist:

  • The code change is tested and works locally.
  • Local tests pass with tox.
  • Tests have been added to verify that the new code works.

homeassistant/components/mqtt/__init__.py Show resolved Hide resolved
@@ -864,9 +864,14 @@ def available(self) -> bool:
class MqttDiscoveryUpdate(Entity):
"""Mixin used to handle updated discovery message."""

def __init__(self, discovery_hash) -> None:
def __init__(self, discovery_hash, discovery_payload=None,
async_discover=None) -> None:
Copy link
Member

@OttoWinter OttoWinter Nov 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like this that much. Passing this async_discover callback will become quite a mess once we start implementing MQTT config entry unloading. For now it's probably ok though

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed (I think?)

homeassistant/components/binary_sensor/mqtt.py Outdated Show resolved Hide resolved
homeassistant/components/mqtt/__init__.py Outdated Show resolved Hide resolved
homeassistant/components/mqtt/__init__.py Outdated Show resolved Hide resolved
@emontnemery
Copy link
Contributor Author

emontnemery commented Nov 4, 2018

@OttoWinter Thanks a lot for the comments!
The code is modified as you proposed such that the component is updated instead of removed+added.

Some questions:

  • Does it make sense to add a method _setup_from_config also to MqttAvailability?
  • What to do if device is changed, add some handling to MqttEntityDeviceInfo?
  • What to do if unique_id is changed?
  • In MqttDiscoveryUpdate I'm checking if self._discovery_payload != payload, but I think that's quite redundant, no need to check?

@emontnemery emontnemery force-pushed the mqtt_discovery_update_binary_sensor branch from aa53d67 to ac19a0b Compare November 4, 2018 15:42
@emontnemery emontnemery changed the title Recreate binary_sensor component if discovery info is changed Reconfigure MQTT binary_sensor component if discovery info is changed Nov 4, 2018
@emontnemery emontnemery force-pushed the mqtt_discovery_update_binary_sensor branch from b357dce to 61541a0 Compare November 4, 2018 19:01
@emontnemery emontnemery force-pushed the mqtt_discovery_update_binary_sensor branch from 61541a0 to 0542b2d Compare November 4, 2018 19:02
self._unique_id = config.get(CONF_UNIQUE_ID)

# TODO: Handle changed device?
# config.get(CONF_DEVICE),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@OttoWinter What do you suggest to do if device info is changed, just update the MqttEntityDeviceInfo?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not the same as availability_discovery_update, just called device_info_discovery_update - this method would set the internal self._device_info object to the latest values.

(It might be the case though that the device_info is only read when the device is initially added to hass, then I guess we ignore the update to this attribute, as it's probably not used too often)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be the case though that the device_info is only read when the device is initially added to hass

Yes, this seems to be the cased based on some quick testing.
Either just ignore this case as you suggest, or delete + re-add the component.

homeassistant/components/mqtt/discovery.py Show resolved Hide resolved
self._unique_id = config.get(CONF_UNIQUE_ID)

# TODO: Handle changed device?
# config.get(CONF_DEVICE),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not the same as availability_discovery_update, just called device_info_discovery_update - this method would set the internal self._device_info object to the latest values.

(It might be the case though that the device_info is only read when the device is initially added to hass, then I guess we ignore the update to this attribute, as it's probably not used too often)

@bind_hass
async def async_subscribe_topics(hass: HomeAssistantType, sub_state: dict,
new_topics: dict,
msg_callback: MessageCallbackType,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not have a generic msg callback for all topics. For example, this won't work for the MQTT light, as it has a different callback for brightness and state.

I would expect new_topics to be called topics (as there might nothing be new about it) and be defined like this:

{
  '/home/light/kitchen/state': {
    'qos': 2,
    'encoding': 'utf-8',
    'msg_callback': state_received
  }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

State is kept in sub_state.
"""
if sub_state is None:
sub_state = {'topics': {}}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No reason to wrap it in a dictionary. It's an opaque object to the outside world, inside this method we always know the implementation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, fixed.

for key, topic in new_topics.items():
if key not in old_topics and topic is not None:
unsub = await mqtt.async_subscribe(hass, topic, msg_callback, qos)
old_topics[key] = (topic, unsub)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's kinda confusing that we have an object called old_topics that we're writing to. That's also why we need to wrap the for-loop with a list around values.

We should rename old_topic to cur_topics and create a new state dictionary. Then just while iterating over the new_topics param, we pop keys from cur_topics. When done with the for-loop, anything that's left in cur_topics can be unsubscribed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, rewritten as you suggest.

@emontnemery
Copy link
Contributor Author

@balloob Thanks a lot for the review! subscription.py rewritten as you suggest, and tests added.

@emontnemery
Copy link
Contributor Author

emontnemery commented Nov 15, 2018

@balloob Do you consider this ready for merge now, or are additional changes needed?

@balloob balloob merged commit de9bac9 into home-assistant:dev Nov 19, 2018
@ghost ghost removed the in progress label Nov 19, 2018
@balloob
Copy link
Member

balloob commented Nov 19, 2018

Looks good! Delayed because I was taking a week off GitHub :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants