-
-
Notifications
You must be signed in to change notification settings - Fork 3.5k
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
[mqtt] Simplify homeassistant thing types, and use AbstractStorageBasedTypeProvider #16600
base: main
Are you sure you want to change the base?
Conversation
Instead, use state descriptions for the varying parts, which means that there is not an explosion of channel types for every single Home Assistant channel, which can cause performance issues if you have a lot of devices/channels Signed-off-by: Cody Cutrer <cody@cutrer.us>
This has two important impacts, and one not-as-important-but-still- beneficial impact: * ThingTypes are not created for Things that are never actually created, but only discovered, reducing bloat. * Avoids warnings about things types not being in the registry * Thing IDs end up like mqtt:homeassistant:broker:mydevice instead of mqtt:homeassistant_mydevice:broker:mydevice Note that already-created things will maintain their original ID, and it's only new things created from auto-discovery that will have the new, shorter thing IDs. Signed-off-by: Cody Cutrer <cody@cutrer.us>
This is triggered by a property only set by discovery, so will only apply to newly created things. Channel groups are now named after simply the component type and object_id, if possible, and without additional encoding, instead off encoding the unique_id. Most devices will encode the component type and device identifiers into the unique_id, and of arbitrary format, so it is far more complicated than necessary, when a channel group is already only within the scope of the thing/device. Many component types that can only ever have one channel (button, switch, sensor, select, scene, etc.) will not be in a channel group anymore. In this case their channel id is what their group id would have been, without the repetitiveness of "sensor_<unique_id>#sensor". Signed-off-by: Cody Cutrer <cody@cutrer.us>
Includes both homie and homeassistant dynamic things. It also fixes all ordering issues in both bindings in order to be consistent in how types are persisted: * For Homie, Nodes (channel groups) and Properties (channels) are ordered in the way they are defined in $nodes and $properties * For Home Assistant, Components are ordered by label. This includes both single channel components that are not in a channel group, as well as channel groups. We also ensure that on the Thing itself non-grouped channels consistently sort before grouped channels. Signed-off-by: Cody Cutrer <cody@cutrer.us>
Signed-off-by: Cody Cutrer <cody@cutrer.us>
Signed-off-by: Cody Cutrer <cody@cutrer.us>
...ing.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/MqttChannelTypeProvider.java
Outdated
Show resolved
Hide resolved
...ing.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/MqttChannelTypeProvider.java
Outdated
Show resolved
Hide resolved
...ing.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/MqttChannelTypeProvider.java
Outdated
Show resolved
Hide resolved
...ing.mqtt.generic/src/main/java/org/openhab/binding/mqtt/generic/MqttChannelTypeProvider.java
Outdated
Show resolved
Hide resolved
...c/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/AbstractComponent.java
Outdated
Show resolved
Hide resolved
....binding.mqtt.homie/src/main/java/org/openhab/binding/mqtt/homie/internal/homie300/Node.java
Outdated
Show resolved
Hide resolved
...c/main/java/org/openhab/binding/mqtt/homeassistant/internal/component/AbstractComponent.java
Outdated
Show resolved
Hide resolved
*/ | ||
public AbstractComponent(ComponentFactory.ComponentConfiguration componentConfiguration, Class<C> clazz) { | ||
public AbstractComponent(ComponentFactory.ComponentConfiguration componentConfiguration, Class<C> clazz, | ||
boolean newStyleChannels, boolean singleChannelComponent) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this possible to move newStyleChannels into haID?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
before I spend time making changes here, I'd like feedback on how we want to address backwards compatibility:
- as is - newly discovered things get the shorter channels, already-existing things don't. file-based things don't (which... I don't even know if file-based Home Assistant things really work, so might not matter)
- an explicit configuration on the thing to opt in (means can be used for file-based things, or if you have to re-create your things for some reason) - but means it's an additional step, so most people won't ever know about it. and not really useful for re-creating things, since the thing uid will always be the shorter version, even if you choose the longer channel ids.
- an explicit configuration on the thing to opt out (means can be used for file-based things, or if you have to re-create your things for some reason) - but means it will break all existing things causing issues for existing users anyway. and not really useful for re-creating things, since the thing uid will always be the shorter version, even if you choose the longer channel ids.
- just pull off the band aid and call a breaking change - all existing things get the newer shorter ids, and no way to go back. definitely simplifies the code to not need to plumb this through, or to have to have two branches
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the as-is option, i think this is elegant. One question, how long would you support the deprecated convention? One or two releases? When this comes with a clear eol date and an upgrade notice (distro repo) it is probably my favorite.
Imho opt-in/opt-out is only making it more complex and not solving any issue in the ugprade path.
The last option is clear, convenient for the developers, but disruptive to the end user.
So all in all, my vote would go to the first option.
if (newStyleChannels && this.singleChannelComponent) { | ||
groupId = haID.component; | ||
} else { | ||
groupId = ""; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should not it be null as in the org.openhab.core.thing.ChannelUID.getGroupId?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can't be null, since it's not just used as part of a channel id, but also for other uses in the thing handler that don't allow null. Perhaps when I have more time I'll check if I can change those all to allow nullable.
protected ComponentChannel.Builder buildChannel(String channelID, ChannelTypeUID channelTypeUID, Value valueState, | ||
String label, ChannelStateUpdateListener channelStateUpdateListener) { | ||
if (singleChannelComponent) { | ||
channelID = groupId; | ||
} | ||
return new ComponentChannel.Builder(this, channelID, channelTypeUID, valueState, label, | ||
channelStateUpdateListener); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently, there are no restrictions on which UIDs can be used as channelTypeUID, but the types are determined. Could you create a build method for each channel type. The next step would be abstract builders with factory methods specific for channel types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please elaborate here? I'm not sure what you mean about types being determined.
@ccutrer : did you notice the build failed ? |
I did. And I've gotten to the point that I can reproduce the failures locally, but have not yet had time to troubleshoot them (or address @antroids comments). |
Signed-off-by: Cody Cutrer <cody@cutrer.us>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've addressed (most) the review comments, but not looked at itests. The suggested changes have also caused (non-test) test failures - I think related to some of the foreach changes, possibly due to needing to mock different methods. I don't have time today to look into any of that, but will when I can
*/ | ||
public AbstractComponent(ComponentFactory.ComponentConfiguration componentConfiguration, Class<C> clazz) { | ||
public AbstractComponent(ComponentFactory.ComponentConfiguration componentConfiguration, Class<C> clazz, | ||
boolean newStyleChannels, boolean singleChannelComponent) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
before I spend time making changes here, I'd like feedback on how we want to address backwards compatibility:
- as is - newly discovered things get the shorter channels, already-existing things don't. file-based things don't (which... I don't even know if file-based Home Assistant things really work, so might not matter)
- an explicit configuration on the thing to opt in (means can be used for file-based things, or if you have to re-create your things for some reason) - but means it's an additional step, so most people won't ever know about it. and not really useful for re-creating things, since the thing uid will always be the shorter version, even if you choose the longer channel ids.
- an explicit configuration on the thing to opt out (means can be used for file-based things, or if you have to re-create your things for some reason) - but means it will break all existing things causing issues for existing users anyway. and not really useful for re-creating things, since the thing uid will always be the shorter version, even if you choose the longer channel ids.
- just pull off the band aid and call a breaking change - all existing things get the newer shorter ids, and no way to go back. definitely simplifies the code to not need to plumb this through, or to have to have two branches
protected ComponentChannel.Builder buildChannel(String channelID, ChannelTypeUID channelTypeUID, Value valueState, | ||
String label, ChannelStateUpdateListener channelStateUpdateListener) { | ||
if (singleChannelComponent) { | ||
channelID = groupId; | ||
} | ||
return new ComponentChannel.Builder(this, channelID, channelTypeUID, valueState, label, | ||
channelStateUpdateListener); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please elaborate here? I'm not sure what you mean about types being determined.
if (newStyleChannels && this.singleChannelComponent) { | ||
groupId = haID.component; | ||
} else { | ||
groupId = ""; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can't be null, since it's not just used as part of a channel id, but also for other uses in the thing handler that don't allow null. Perhaps when I have more time I'll check if I can change those all to allow nullable.
This is a rather large PR, but is built of a few commits with essentially two distinct goals. I have not tested them individually, and there are lots of interactions between the two goals, which is why I did not disentangle them.
This first goal is to simplify and optimize thing and channel types for mqtt.homeassistant. This fixes #14295. This in itself has two user visible changes:
mqtt:homeassistant
in its ID. In practice, newly discovered things will get UIDs such asmqtt:homeassistant:mosquitto:awair-element-63611
instead ofmqtt:homeassistant_awair_2Delement_2D63611:mosquitto:awair_2Delement_2D63611
(unnecessary escaping has also been removed). Existing things will not change their UID. I'm not sure if this is considered a breaking change, since existing things will not change at all. But if you were to delete the thing, and re-add it from discovery, it would end up with a different ID. This new behavior matches how mqtt.homie works.For this change, I did a bit of hoop-jumping to pass a property through from auto-discovery, so that existing things will not have their channels change, only newly discovered and created things will use this new channel type. Again, I'm not sure if this counts as a breaking change. If it does, I'm possibly inclined to not use this hinky property, and simply apply the new channel IDs to all things. An example change is from
mqtt:homeassistant_zigbee2mqtt_5F0x8cf681fffe32e58e:mosquitto:zigbee2mqtt_5F0x8cf681fffe32e58e:0x8cf681fffe32e58e_5Fbattery_5Fzigbee2mqtt#sensor
tomqtt:homeassistant:mosquitto:zigbee2mqtt_5F0x8cf681fffe32e58e:sensor_battery
The second goal is relatively simple - use AbstractStorageBasedTypeProvider. Because the thing and channel group types are dynamic, they don't exist in the binding's XML. But since openHAB 4.0, if a thing type isn't available at startup, it will leave the thing in an unknown state for two minutes before it initializes it. By using AbstractStorageBasedTypeProvider, the dynamic types will be persisted to JSON storage, and thus available immediately at startup, avoiding the two minute delay. This fixes #15577