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

Improve thing initialization and enable thing-type updates #3330

Merged
merged 11 commits into from
Feb 15, 2023

Conversation

J-N-K
Copy link
Member

@J-N-K J-N-K commented Jan 22, 2023

Closes #1924

This

  • moves config description URI to type-base class
  • decouples the thing manager from bundle loading
  • makes sure that all thing/channel-types and config descriptions are available when the thing is initialized
  • enables thing type updates

Supersedes #3191

Signed-off-by: Jan N. Klug github@klug.nrw

@J-N-K J-N-K added bug An unexpected problem or unintended behavior of the Core enhancement An enhancement or new feature of the Core work in progress A PR that is not yet ready to be merged labels Jan 22, 2023
@J-N-K J-N-K linked an issue Jan 22, 2023 that may be closed by this pull request
@J-N-K J-N-K force-pushed the feature-thing-update-mechanism branch from eb3efdc to f8b78bd Compare January 23, 2023 18:06
@jlaur
Copy link
Contributor

jlaur commented Jan 23, 2023

@J-N-K - do you know if this will also fix this issue that I'm seeing from time to time:

2023-01-21 09:31:08.326 [WARN ] [core.thing.internal.ThingManagerImpl] - No config description for 'thing-type:energidataservice:service' found when normalizing configuration for 'energidataservice:service:energidataservice'. This is probably a bug.

It sounds very much like it, just seeking confirmation.

@J-N-K
Copy link
Member Author

J-N-K commented Jan 23, 2023

Yes.

This

- moves config description URI to type-base class
- decouples the thing manager from bundle loading
- makes sure that all thing/channel-types and config descriptions are available when the thing is initialized
- enables thing type updates

Signed-off-by: Jan N. Klug <github@klug.nrw>
@J-N-K J-N-K force-pushed the feature-thing-update-mechanism branch from 138f8c0 to bb9d555 Compare January 25, 2023 22:13
J-N-K added 2 commits January 26, 2023 16:15
Signed-off-by: Jan N. Klug <github@klug.nrw>
Signed-off-by: Jan N. Klug <github@klug.nrw>
@J-N-K J-N-K marked this pull request as ready for review January 27, 2023 08:52
@J-N-K J-N-K requested a review from a team as a code owner January 27, 2023 08:52
J-N-K added 2 commits February 1, 2023 21:19
Signed-off-by: Jan N. Klug <github@klug.nrw>
Signed-off-by: Jan N. Klug <github@klug.nrw>
@J-N-K J-N-K removed the work in progress A PR that is not yet ready to be merged label Feb 1, 2023
@kaikreuzer
Copy link
Member

FTR: I have started reviewing this PR today, but I will need a few more days, since it is a lot of code and it is touching the core mechanisms - but so far all looks good. 👍

Copy link
Member

@kaikreuzer kaikreuzer left a comment

Choose a reason for hiding this comment

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

Many thanks, @J-N-K, this looks overall pretty good!
Please find my review comments below. I went through the code, but didn't yet do any extensive testing, though - but I guess that can be done once merged, we should just not do it right before releasing a milestone.


// time after we try to initialize a thing even if the thing-type is not registered (in s)
private static final int MAX_CHECK_PREREQUISITE_TIME = 120;
Copy link
Member

Choose a reason for hiding this comment

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

Might it make sense to make this configurable for the user?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not sure. In my original version I did not have this at all, but while testing I realized that the systeminfo binding does something really strange: It has a seperate thing-type for each thing with a ThingTypeUID systeminfo:computer-mba-jan-wifi_janessa_me where the last part is the id-part of the ThingUID. The factory reports "supported" for every ThingTypeUID that starts with systeminfo:computer-. The ThingType itself added dynamically to the ThingTypeRegistry during the initialization of the thing, so at the time the ThingManager checks if everything needed to initialize the thing is present in the registries it fails. IMO this is a faulty behavior of the binding, if it dynamically creates ThingTypes it should add those to the registry and make sure that they are present when a factory reports they are supported. WDYT?

Copy link
Member

Choose a reason for hiding this comment

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

Yes, I agree that this sounds like a pretty weird behavior. Did you find out why at all different types are created for all things? That does not seem to make much sense...

Copy link
Contributor

Choose a reason for hiding this comment

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

The reason for this in the systeminfo binding to have thing types by thing is that thing specific channel groups are added. In my understanding, this has to be done on the thing type level. E.g. a system with 5 harddisks will get 5 storage channel groups created dynamically. This cannot be defined upfront across all things.
I am open for alternative suggestions for this if it avoids complexity in core. There are probably other bindings doing this for the same reason though.

Copy link
Member Author

Choose a reason for hiding this comment

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

Digitalstrom, Homematic, MQTT, Netatmo and Systeminfo use ThingTypeProvider, I did not check in which way. IMO having different thing-types is fine (also your specific case should be handled by dynamic channel addition), my problem is that you report support for a given ThingTypeUID but you don't add the ThingType to the ThingTypeRegistry.

Copy link
Member

Choose a reason for hiding this comment

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

The issue might be that the specific thing types can only be determined/defined as soon as thing handlers become active - and then it feels too late for adding them to the ThingTypeRegistry.
But let's not try to solve this here as part of this PR, but rather live with the implementation you have done. If this causes issues or we have good ideas how to refactor the system info binding, we can any time address this and simplify the logic.

}

Map<UpdateInstructionKey, List<ThingUpdateInstruction>> updateInstructions = new HashMap<>();
Enumeration<URL> entries = bundle.findEntries("update", "*.update", true);
Copy link
Member

Choose a reason for hiding this comment

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

Might it make sense to put the update folder also underneath OH-INF as this is where all other metadata resides?

Copy link
Member

Choose a reason for hiding this comment

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

Another thought, looking at our OH-INF folder: So far, all metadata that binding developers are expected to deliver are XML files (and property files, but those are typically generated).

From a consistency point of view: Might it make sense to also switch to XML for the update information and provide a proper XSD for them as well?

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree on moving to the OH-INF folder, that avoids future collisions.

I'm not so sure regarding the XML (although I see the benefit of validating the content with the XSD and having proper documentation). The reason is that parsing XML with XStream is really a PITA. If we can agree on using Jakarta XML, I'm fine with it.

Copy link
Member Author

Choose a reason for hiding this comment

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

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<update:update-descriptions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:update="https://openhab.org/schemas/update-description/v1.0.0"
	xsi:schemaLocation="https://openhab.org/schemas/update-description/v1.0.0 https://openhab.org/schemas/update-description-1.0.0.xsd">

	<thing-type uid="testBinding:testThingTypeAdd">
		<instruction-set targetVersion="1">
			<add-channel id="testChannel1">
				<channelTypeUid>testBinding:testChannelTypeId</channelTypeUid>
			</add-channel>
			<add-channel id="testChannel2">
				<channelTypeUid>testBinding:testChannelTypeId</channelTypeUid>
				<label>Test Label</label>
			</add-channel>
			<add-channel id="testChannel3">
				<channelTypeUid>testBinding:testChannelTypeId</channelTypeUid>
				<label>Test Label</label>
				<description>Test Description</description>
			</add-channel>
		</instruction-set>
	</thing-type>

	<thing-type uid="testBinding:testThingTypeRemove">
		<instruction-set targetVersion="1">
			<remove-channel id="testChannel"/>
		</instruction-set>
	</thing-type>

	<thing-type uid="testBinding:testThingTypeUpdate">
		<instruction-set targetVersion="1">
			<update-channel id="testChannel">
				<channelTypeUid>testBinding:testChannelNewTypeId</channelTypeUid>
				<label>New Test Label</label>
			</update-channel>
		</instruction-set>
	</thing-type>

</update:update-descriptions>

WDYT?

Copy link
Member

Choose a reason for hiding this comment

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

Much more boilerplate, but that's what comes with XML. I like the fact that we can easily check it against XSDs.

I agree that parsing with XStream is no fun, I'll have a look at your Jakarta implementation.

J-N-K added 2 commits February 9, 2023 12:49
Signed-off-by: Jan N. Klug <github@klug.nrw>
Signed-off-by: Jan N. Klug <github@klug.nrw>
@openhab-bot
Copy link
Collaborator

This pull request has been mentioned on openHAB Community. There might be relevant details there:

https://community.openhab.org/t/openhab-4-0-snapshot-discussion/142322/152

Signed-off-by: Jan N. Klug <github@klug.nrw>
Signed-off-by: Jan N. Klug <github@klug.nrw>
Signed-off-by: Jan N. Klug <github@klug.nrw>
Signed-off-by: Jan N. Klug <github@klug.nrw>
Copy link
Member

@kaikreuzer kaikreuzer left a comment

Choose a reason for hiding this comment

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

Wow, you're incredibly fast - thanks!
I think you have addressed all my comments and I am very happy about the result - so let's wait for the build to succeed and we can merge. 👍

@wborn
Copy link
Member

wborn commented Feb 18, 2023

Looks like these changes break the add-ons build, see:

If I revert these changes locally the tests succeed again. Can you have a look @J-N-K?

@wborn wborn added bounty and removed bug An unexpected problem or unintended behavior of the Core labels Feb 18, 2023
@wborn
Copy link
Member

wborn commented Feb 18, 2023

A more descriptive title would also be nice for the release notes and if it is resolved you can claim the bounty. 😉

@J-N-K J-N-K changed the title Refactor ThingManagerImpl Improve thing initialization and enable thing-type updates Feb 18, 2023
@J-N-K
Copy link
Member Author

J-N-K commented Feb 18, 2023

Looks like these changes break the add-ons build, see:

If I revert these changes locally the tests succeed again. Can you have a look @J-N-K?

See openhab/openhab-addons#14431

@jlaur
Copy link
Contributor

jlaur commented Feb 20, 2023

@J-N-K - I guess I have to be the one asking the stupid question. 😊 I understand from openhab/openhab-addons#14447 (comment) that update instructions are needed when adding new channels. What is the reason that this cannot be auto-detected? Performance? I can understand more complex scenarios needing instructions, but it seems to me that if a channel doesn't exist in jsondb, but is declared in the binding, then it must be added? I haven't looked into the jsondb data model as I'm personally using files, so there might be a simple explanation.

@J-N-K
Copy link
Member Author

J-N-K commented Feb 20, 2023

There are different reason:

  • A missing channel (in the thing, existing in the XML) could have been removed by the thing itself (because it is not available). This is the reverse action of dynamically adding channels (which is more common) but still a valid option.
  • An existing channel (in the thing, but missing in the XML) could have been dynamically added by the thing itself or be an extensible channel that has been added by the user.
  • A channel could change (e.g. the channel-type changes from deconz:switch to system:power, the label and/or description could change).

We have tried for five years to find a solution that autodetects such changes (there have been several attempts here and in ESH), but there have always been issues (which are not absolute corner-cases) where an automatic solution failed. Especially the first two points make it very hard and the solution with the update instruction is far more fail-safe - it requires a deliberate action of the developer to change existing things.

@jlaur
Copy link
Contributor

jlaur commented Feb 20, 2023

@J-N-K - I see, thanks for the summary/additional context.

@lolodomo
Copy link
Contributor

lolodomo commented Mar 7, 2023

We have now to promote this new feature before merging changes in add-ons.
But I assume it remains only an option ?

This feature only concerns things created with MainUI and of course not things defined in things file; I am right ?

@J-N-K
Copy link
Member Author

J-N-K commented Mar 8, 2023

Technically it is ab "option". But IMO there should be policy to upgrade everything that is possible to make a smoother user experience.

@lolodomo
Copy link
Contributor

@J-N-K : is there a special syntax to mention the adding or removal of a thing configuration parameter ? Or is it just unnecessary to consider that ?

@J-N-K
Copy link
Member Author

J-N-K commented Mar 11, 2023

It is unnecessary because that depends on the config description and config descriptions are always build when the bundle loads/reloads, so they are automatically updated. The database only stores the config values, so the worst thing that could happen is a value that is no longer used.

For managed things the channels are stored in the database and the thing description is only used when creating the thing and from then on only "restored" from the database (as opposed to the file-base things, there the thing is always "deleted" and "created" when the file is unloaded/loaded).

@lolodomo
Copy link
Contributor

Ok.
And if there is a change of the channel type (change of UID), is it necessary to provide something or not ?

@openhab-bot
Copy link
Collaborator

This pull request has been mentioned on openHAB Community. There might be relevant details there:

https://community.openhab.org/t/how-to-notify-user-about-deprecations-properly/145533/5

splatch pushed a commit to ConnectorIO/copybara-hab-core that referenced this pull request Jul 12, 2023
* Refactor ThingManagerImpl

This

- moves config description URI to type-base class
- decouples the thing manager from bundle loading
- makes sure that all thing/channel-types and config descriptions are available when the thing is initialized
- enables thing type updates

Signed-off-by: Jan N. Klug <github@klug.nrw>
GitOrigin-RevId: d7fa553
@openhab-bot
Copy link
Collaborator

This pull request has been mentioned on openHAB Community. There might be relevant details there:

https://community.openhab.org/t/how-to-implement-thing-upgrades/148290/2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bounty enhancement An enhancement or new feature of the Core
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Update existing Things for definition changes
7 participants