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

Don't prune blank entity names in overridden discovery data #523

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from

Conversation

tstabrawa
Copy link
Contributor

Proposed change

This change fixes a bug where entities using the default, blank-string entity names that are configured with device_override_class settings that modify their config fields would have their blank name fields removed from their MQTT discovery data, causing Home Assistant to name the entity "<device name> MQTT JSON Light" instead of the default "<device name>". I'm not really sure if this is the intended behavior of Home Assistant (i.e. this could be an HA bug, not ours), but we can preserve our desired naming by not pruning empty name fields from the MQTT discovery data.

Additional information

  • This PR fixes or closes issue: fixes #
  • This PR is related to issue:
  • Link to documentation pull request:

Here is a simple discovery_overrides config that can reproduce the problem using Insteon Dimmers:

  light_no_change:
    discovery_overrides:
      dimmer:
        config:
          brightness: true

With the above set as device_override_class for a dimmer named "Desk Lamp" Home Assistant produces the name "Desk Lamp MQTT JSON Light":

image

This appears to be because the "name" field is removed from the MQTT discovery data:

image

With the proposed change, the blank "name" field is preserved, and the entity name stays set to "Desk Lamp" as it would without using the device_override_class.

Checklist

  • The code change is tested and works locally.
  • Local tests pass. Your PR cannot be merged unless tests pass
  • Tests have been added to verify that the new code works.
  • Code documentation was added where necessary - N/A

If user exposed functionality or configuration variables are added/changed:

  • Documentation added/updated - N/A

Confirmed no new flake8 errors, pylint errors, or code coverage gaps. All tests passing. Also, confirmed updated test (test_load_device_discovery_overrides) fails prior to applying fix:

================================================================================ FAILURES ================================================================================
________________________________________________________ Test_DiscoveryTopic.test_load_device_discovery_overrides ________________________________________________________

self = <test_DiscoveryTopic.Test_DiscoveryTopic object at 0x7f1edc97eaa0>
discovery_fan = <insteon_mqtt.mqtt.topic.DiscoveryTopic.DiscoveryTopic object at 0x7f1edc6eac20>, caplog = <_pytest.logging.LogCaptureFixture object at 0x7f1edc87ff40>

    def test_load_device_discovery_overrides(self, discovery_fan, caplog):
        discovery_fan.mqtt.discovery_enabled = True
        # build and request fake class to be used for tests
        config = {}
        config['fake_dev'] = {'discovery_entities': {
            'fake': {
                "component": "fan",
                "config": {
                    "name": "",
                    "unique_id": "unique",
                    "icon": "fake",
                },
            },
        }}
        discovery_fan.device.config_extra['discovery_class'] = 'fake_dev'
        # Override data from this point
        discovery_fan.discovery_template_data = mock.Mock(return_value={})

        # test empty override dict
        discovery_fan.device.config_extra['discovery_overrides'] = {}
        discovery_fan.load_discovery_data(config)
        assert len(discovery_fan.disc_templates) == 1
        discovery_fan.disc_templates = []

        # test empty device override dict
        discovery_fan.device.config_extra['discovery_overrides'] = { 'device': {} }
        discovery_fan.load_discovery_data(config)
        assert len(discovery_fan.disc_templates) == 1
        discovery_fan.disc_templates = []

        # test empty config override dict
        discovery_fan.device.config_extra['discovery_overrides'] = { 'fake': {
            "config": {},
        }}
        discovery_fan.load_discovery_data(config)
        assert len(discovery_fan.disc_templates) == 1
        discovery_fan.disc_templates = []

        # test for non-matching entity name
        discovery_fan.device.config_extra['discovery_overrides'] = { 'fakefail': {
        }}
        discovery_fan.load_discovery_data(config)
        assert 'Entity to override was not found' in caplog.text
        caplog.clear()

        # test for suppressing entity
        discovery_fan.device.config_extra['discovery_overrides'] = { 'fake': {
            "discoverable": False,
        }}
        discovery_fan.load_discovery_data(config)
        assert len(discovery_fan.disc_templates) == 0

        # test for overriding component
        discovery_fan.device.config_extra['discovery_overrides'] = { 'fake': {
           "component": "switch",
        }}
        discovery_fan.load_discovery_data(config)
        expected_topic = "homeassistant/switch/11_22_33/unique/config"
        assert discovery_fan.disc_templates[0].topic_str == expected_topic
        discovery_fan.disc_templates = []

        # test for overriding config unique_id
        discovery_fan.device.config_extra['discovery_overrides'] = { 'fake': {
            "config": {
                "unique_id": "override",
            },
        }}
        discovery_fan.load_discovery_data(config)
        expected_topic = "homeassistant/fan/11_22_33/override/config"
        assert discovery_fan.disc_templates[0].topic_str == expected_topic
        discovery_fan.disc_templates = []

        # test for adding config attribute
        # Also test that name isn't removed
        discovery_fan.device.config_extra['discovery_overrides'] = { 'fake': {
            "config": {
                "foo": "fake",
            },
        }}
        discovery_fan.load_discovery_data(config)
        payload = json.loads(discovery_fan.disc_templates[0].payload_str)
        assert payload.get("foo", None) == "fake"
>       assert "name" in payload
E       AssertionError: assert 'name' in {'foo': 'fake', 'icon': 'fake', 'unique_id': 'unique'}

tests/mqtt/topic/test_DiscoveryTopic.py:239: AssertionError
--------------------------------------------------------------------------- Captured log call ----------------------------------------------------------------------------
ERROR    insteon_mqtt:DiscoveryTopic.py:347 11.22.33 - Entity to override was not found - fakefail
======================================================================== short test summary info =========================================================================
FAILED tests/mqtt/topic/test_DiscoveryTopic.py::Test_DiscoveryTopic::test_load_device_discovery_overrides - AssertionError: assert 'name' in {'foo': 'fake', 'icon': 'fake', 'unique_id': 'unique'}
===================================================================== 1 failed, 706 passed in 10.65s =====================================================================

Missing name causes HA to name lights as "MQTT JSON Light", etc.
Missing name causes HA to name lights as "MQTT JSON Light", etc.
@tstabrawa
Copy link
Contributor Author

Updating to note that with a recent change in the HA behavior (home-assistant/core#107188), my workaround for this issue is no longer effective.

Specifically, I used to be able to be able to set the name in my discovery_overrides entries to "{{name_user_case}}", and HA would present the entity name as the same as the device name. Now, in HA 2024.2.0, with this setting, the entity name is the device name repeated twice.

For example, with the following overrides:

  switch_as_light:
    # Maps a switch to a light, which is nicer in HA for actual lights
    discovery_overrides:
      switch:
        component: "light"
        config:
          name: "{{name_user_case}}"
          uniq_id: "{{address}}_light"
          brightness: false
          schema: "json"
          cmd_t: "{{on_off_topic}}"

I end up with entities with names like "Front Porch Light Front Porch Light".

Please let me know if there's anything else you need in order to get this fix merged. Thanks!

@f1d094
Copy link

f1d094 commented Feb 25, 2024

Is this the same as what is being discussed in #514 ?

@tstabrawa
Copy link
Contributor Author

tstabrawa commented Feb 26, 2024

Not really, though #514 is somewhat related. In particular #514 (via its associated merge request -- #516) changed insteon_mqtt/data/config-base.yaml / discovery_entities to set the default name value for simple devices (switches, lights, etc) and the default entities of more complex devices to a blank string (""). This has the effect of causing Home Assistant to assign the corresponding entity name to match the device name. This is the desired behavior.

#523 is about fixing a bug where if you use a discovery_overrides configuration to override some template values, then the blank name field gets completely removed from the MQTT discovery data, which causes Home Assistant to set the entity name to something like "<device name> MQTT JSON Light" instead of the preferred "<device name>".

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

Successfully merging this pull request may close these issues.

2 participants