Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
8fafb61
work in progress
andrewfg Jul 18, 2025
3a24e64
work in progress
andrewfg Jul 18, 2025
30677ee
work in progress
andrewfg Jul 18, 2025
3af3e83
add integration tests and fix code so the tests pass
andrewfg Jul 19, 2025
49867e4
move to item registry
andrewfg Jul 20, 2025
128190e
remove bat file
andrewfg Jul 20, 2025
e4524b2
tweak
andrewfg Jul 20, 2025
4d975ac
revised pom
andrewfg Jul 20, 2025
c9c73e3
work in progress
andrewfg Jul 21, 2025
9616f54
work in progress
andrewfg Jul 21, 2025
673f9f3
work in progress
andrewfg Jul 21, 2025
1fd05a7
work in progress
andrewfg Jul 21, 2025
b213720
refactoring, added javadoc, added test cases
andrewfg Jul 21, 2025
0359524
check if osgi tests are being run
andrewfg Jul 21, 2025
78f8f04
support removal of channel links
andrewfg Jul 22, 2025
1f27164
Update ItemChannelLinkAssignDefaultTagsOSGiTest.java
andrewfg Jul 22, 2025
de82a01
formally update the item registry
andrewfg Jul 22, 2025
207b666
handle pre-orphaned links, and refactoring
andrewfg Jul 23, 2025
f8205b4
Update bundles/org.openhab.core.thing/src/main/java/org/openhab/core/…
andrewfg Jul 23, 2025
c77e441
fix tag removal edge case
andrewfg Jul 24, 2025
b6000b0
default useTags=true; clear tagsLinked on item removal
andrewfg Jul 24, 2025
eea1bc9
java doc
andrewfg Jul 24, 2025
172f9e2
adjust tests for useTags opt-out model
andrewfg Jul 24, 2025
8084d1f
add TODO
andrewfg Jul 24, 2025
e6e08f4
fix item registry update and notification process
andrewfg Jul 24, 2025
5f85893
revert to opt-in model
andrewfg Jul 24, 2025
a220197
fix build
andrewfg Jul 24, 2025
b674de6
change log level to info
andrewfg Jul 24, 2025
c54e38e
Add system wide configuration
andrewfg Jul 24, 2025
b4cadc0
rename config scope and key name
andrewfg Jul 25, 2025
2898509
fixes based on reviewer suggestions
andrewfg Jul 25, 2025
b33185a
revert prior
andrewfg Jul 25, 2025
d8f3a92
fix itests and bndrun
andrewfg Jul 25, 2025
7588041
resolve bndrun on other modules
andrewfg Jul 25, 2025
e9c54d7
allow useTags to be string or bool, and logging tweaks
andrewfg Jul 26, 2025
38fe5f4
remove osgi test; initialize tags on start up
andrewfg Jul 26, 2025
75953e8
work in progress
andrewfg Jul 26, 2025
1511abf
tweaks to logging
andrewfg Jul 26, 2025
9fa2e5e
unit tests work in progress
andrewfg Jul 27, 2025
fcded82
ready for final review
andrewfg Jul 27, 2025
3f9c32e
fix integration test
andrewfg Jul 28, 2025
218c565
fix bndrun merge conflict
andrewfg Aug 17, 2025
b444477
fix bndrun (trailing backslashes)
andrewfg Aug 23, 2025
cabdb2f
adopt reviewer suggestion
andrewfg Aug 23, 2025
6931c25
Apply suggestion from @Copilot
andrewfg Aug 30, 2025
737b01d
Update itests/org.openhab.core.model.item.tests/itest.bndrun
andrewfg Aug 30, 2025
fcacea2
per link useTags can opt out of global useTags
andrewfg Aug 30, 2025
ada3952
fix bndrun (again)
andrewfg Aug 30, 2025
8c6b7ee
log exceptions
andrewfg Aug 30, 2025
1f5443c
Merge remote-tracking branch 'upstream/main' into apply-tags-from-ite…
andrewfg Aug 30, 2025
5238cb9
fix bndrun again again
andrewfg Aug 30, 2025
680a238
Merge branch 'main' into apply-tags-from-items-file
andrewfg Aug 30, 2025
b7f017d
update bndrun again again again
andrewfg Aug 30, 2025
04c0983
Merge branch 'apply-tags-from-items-file' of https://github.com/andre…
andrewfg Aug 30, 2025
d2bf657
Merge branch 'openhab:main' into apply-tags-from-items-file
andrewfg Aug 31, 2025
01eee72
fix bndrun again again again again
andrewfg Aug 31, 2025
79b8b2e
Update bundles/org.openhab.core.thing/src/main/java/org/openhab/core/…
andrewfg Aug 31, 2025
6ae5dbb
Update bundles/org.openhab.core.thing/src/main/java/org/openhab/core/…
andrewfg Aug 31, 2025
0296e3b
add comments
andrewfg Aug 31, 2025
a7b1c11
Merge branch 'main' into apply-tags-from-items-file
andrewfg Sep 21, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ public class ItemChannelLink extends AbstractLink {
private final @NonNullByDefault({}) ChannelUID channelUID;
private final Configuration configuration;

Comment thread
andrewfg marked this conversation as resolved.
// this field tracks whether the item's current tags were applied from the linked channel's default tags
private transient boolean tagsLinked = false;

/**
* Default constructor in package scope only. Will allow to instantiate this
* class by reflection. Not intended to be used for normal instantiation.
Expand Down Expand Up @@ -71,4 +74,18 @@ public boolean equals(@Nullable Object obj) {
public int hashCode() {
return super.hashCode() * configuration.hashCode();
}

/**
* Check if the item's current tags were applied from the linked channel's default tags
*/
public boolean tagsLinked() {
return tagsLinked;
}

/**
* Set the flag that indicates if the item's current tags were applied from the linked channel's default tags
*/
public void setTagsLinked(boolean value) {
tagsLinked = value;
}
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -464,4 +464,9 @@ public void updated(Metadata oldElement, Metadata element) {
metadataAwareItem.updatedMetadata(oldElement, element);
}
}

@Override
public void notifyListenersAboutItemExternalUpdate(Item oldItem, Item newItem) {
notifyListenersAboutUpdatedElement(oldItem, newItem);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,11 @@ public interface ItemRegistry extends Registry<Item, String> {
*/
@Nullable
Item remove(String itemName, boolean recursive);

/**
* Called when an item instance has been externally updated in order to inform all registry
* listeners the change between its old and new state.
*/
default void notifyListenersAboutItemExternalUpdate(Item oldItem, Item newItem) {
}
}
3 changes: 3 additions & 0 deletions itests/org.openhab.core.model.item.tests/itest.bndrun
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,7 @@ Fragment-Host: org.openhab.core.model.item
com.fasterxml.jackson.dataformat.jackson-dataformat-xml;version='[2.19.2,2.19.3)',\
com.fasterxml.jackson.dataformat.jackson-dataformat-yaml;version='[2.19.2,2.19.3)',\
org.yaml.snakeyaml;version='[2.4.0,2.4.1)',\
org.openhab.core.model.persistence.runtime;version='[5.1.0,5.1.1)',\
de.focus_shift.jollyday-core;version='[1.5.4,1.5.5)',\
de.focus_shift.jollyday-jackson;version='[1.5.4,1.5.5)'
org.osgi.service.cm;version='[1.6.1,1.6.2)'
1 change: 1 addition & 0 deletions itests/org.openhab.core.model.rule.tests/itest.bndrun
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,5 @@ Fragment-Host: org.openhab.core.model.rule.runtime
com.fasterxml.jackson.dataformat.jackson-dataformat-xml;version='[2.19.2,2.19.3)',\
com.fasterxml.jackson.dataformat.jackson-dataformat-yaml;version='[2.19.2,2.19.3)',\
org.yaml.snakeyaml;version='[2.4.0,2.4.1)',\
org.openhab.core.model.persistence.runtime;version='[5.1.0,5.1.1)',\
org.osgi.service.cm;version='[1.6.1,1.6.2)'
5 changes: 4 additions & 1 deletion itests/org.openhab.core.model.script.tests/itest.bndrun
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,7 @@ Fragment-Host: org.openhab.core.model.script
com.fasterxml.jackson.core.jackson-databind;version='[2.19.2,2.19.3)',\
com.fasterxml.jackson.dataformat.jackson-dataformat-xml;version='[2.19.2,2.19.3)',\
com.fasterxml.jackson.dataformat.jackson-dataformat-yaml;version='[2.19.2,2.19.3)',\
org.yaml.snakeyaml;version='[2.4.0,2.4.1)'
org.yaml.snakeyaml;version='[2.4.0,2.4.1)',\
org.openhab.core.model.persistence.runtime;version='[5.1.0,5.1.1)',\
de.focus_shift.jollyday-core;version='[1.5.4,1.5.5)',\
de.focus_shift.jollyday-jackson;version='[1.5.4,1.5.5)'
3 changes: 3 additions & 0 deletions itests/org.openhab.core.model.thing.tests/itest.bndrun
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,7 @@ Fragment-Host: org.openhab.core.model.thing
com.fasterxml.jackson.dataformat.jackson-dataformat-xml;version='[2.19.2,2.19.3)',\
com.fasterxml.jackson.dataformat.jackson-dataformat-yaml;version='[2.19.2,2.19.3)',\
org.yaml.snakeyaml;version='[2.4.0,2.4.1)',\
org.openhab.core.model.persistence.runtime;version='[5.1.0,5.1.1)',\
de.focus_shift.jollyday-core;version='[1.5.4,1.5.5)',\
de.focus_shift.jollyday-jackson;version='[1.5.4,1.5.5)'
org.osgi.service.cm;version='[1.6.1,1.6.2)'
63 changes: 61 additions & 2 deletions itests/org.openhab.core.thing.tests/itest.bndrun
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,65 @@ Fragment-Host: org.openhab.core.thing
org.openhab.core.thing.tests;version='[5.1.0,5.1.1)',\
org.openhab.core.transform;version='[5.1.0,5.1.1)',\
biz.aQute.tester.junit-platform;version='[7.1.0,7.1.1)',\
org.ops4j.pax.logging.pax-logging-api;version='[2.3.0,2.3.1)',\
org.openhab.core.semantics;version='[5.1.0,5.1.1)',\
org.objectweb.asm;version='[9.8.0,9.8.1)'
com.google.inject;version='[7.0.0,7.0.1)',\
de.focus_shift.jollyday-core;version='[1.5.4,1.5.5)',\
de.focus_shift.jollyday-jackson;version='[1.5.4,1.5.5)',\
io.github.classgraph.classgraph;version='[4.8.180,4.8.181)',\
org.antlr.runtime;version='[3.2.0,3.2.1)',\
org.eclipse.jetty.alpn.client;version='[9.4.57,9.4.58)',\
org.eclipse.jetty.client;version='[9.4.57,9.4.58)',\
org.eclipse.jetty.http2.client;version='[9.4.57,9.4.58)',\
org.eclipse.jetty.http2.common;version='[9.4.57,9.4.58)',\
org.eclipse.jetty.http2.hpack;version='[9.4.57,9.4.58)',\
org.eclipse.jetty.jaas;version='[9.4.57,9.4.58)',\
org.eclipse.jetty.websocket.api;version='[9.4.57,9.4.58)',\
org.eclipse.jetty.websocket.client;version='[9.4.57,9.4.58)',\
org.eclipse.jetty.websocket.common;version='[9.4.57,9.4.58)',\
org.eclipse.jetty.xml;version='[9.4.57,9.4.58)',\
org.glassfish.hk2.external.aopalliance-repackaged;version='[3.1.1,3.1.2)',\
org.openhab.core.audio;version='[5.1.0,5.1.1)',\
org.openhab.core.automation;version='[5.1.0,5.1.1)',\
org.openhab.core.automation.module.script;version='[5.1.0,5.1.1)',\
org.openhab.core.automation.module.script.rulesupport;version='[5.1.0,5.1.1)',\
org.openhab.core.ephemeris;version='[5.1.0,5.1.1)',\
org.openhab.core.io.net;version='[5.1.0,5.1.1)',\
org.openhab.core.model.core;version='[5.1.0,5.1.1)',\
org.openhab.core.model.item;version='[5.1.0,5.1.1)',\
org.openhab.core.model.persistence;version='[5.1.0,5.1.1)',\
org.openhab.core.model.persistence.runtime;version='[5.1.0,5.1.1)',\
org.openhab.core.model.rule;version='[5.1.0,5.1.1)',\
org.openhab.core.model.script;version='[5.1.0,5.1.1)',\
org.openhab.core.model.script.runtime;version='[5.1.0,5.1.1)',\
org.openhab.core.model.sitemap;version='[5.1.0,5.1.1)',\
org.openhab.core.model.thing;version='[5.1.0,5.1.1)',\
org.openhab.core.persistence;version='[5.1.0,5.1.1)',\
org.openhab.core.voice;version='[5.1.0,5.1.1)',\
org.threeten.extra;version='[1.8.0,1.8.1)',\
stax2-api;version='[4.2.2,4.2.3)',\
com.fasterxml.jackson.core.jackson-annotations;version='[2.19.2,2.19.3)',\
com.fasterxml.jackson.core.jackson-core;version='[2.19.2,2.19.3)',\
com.fasterxml.jackson.core.jackson-databind;version='[2.19.2,2.19.3)',\
com.fasterxml.jackson.dataformat.jackson-dataformat-xml;version='[2.19.2,2.19.3)',\
com.fasterxml.jackson.dataformat.jackson-dataformat-yaml;version='[2.19.2,2.19.3)',\
com.google.guava;version='[33.4.8,33.4.9)',\
com.google.guava.failureaccess;version='[1.0.3,1.0.4)',\
org.eclipse.emf.common;version='[2.30.0,2.30.1)',\
org.eclipse.emf.ecore;version='[2.36.0,2.36.1)',\
org.eclipse.emf.ecore.xmi;version='[2.37.0,2.37.1)',\
org.eclipse.equinox.common;version='[3.19.0,3.19.1)',\
org.eclipse.xtend.lib;version='[2.40.0,2.40.1)',\
org.eclipse.xtend.lib.macro;version='[2.40.0,2.40.1)',\
org.eclipse.xtext;version='[2.40.0,2.40.1)',\
org.eclipse.xtext.common.types;version='[2.40.0,2.40.1)',\
org.eclipse.xtext.util;version='[2.40.0,2.40.1)',\
org.eclipse.xtext.xbase;version='[2.40.0,2.40.1)',\
org.eclipse.xtext.xbase.lib;version='[2.40.0,2.40.1)',\
org.objectweb.asm;version='[9.8.0,9.8.1)',\
org.ops4j.pax.logging.pax-logging-api;version='[2.3.0,2.3.1)',\
org.ops4j.pax.web.pax-web-api;version='[8.0.33,8.0.34)',\
org.ops4j.pax.web.pax-web-jetty;version='[8.0.33,8.0.34)',\
org.ops4j.pax.web.pax-web-runtime;version='[8.0.33,8.0.34)',\
org.ops4j.pax.web.pax-web-spi;version='[8.0.33,8.0.34)',\
org.ops4j.pax.web.pax-web-tomcat-common;version='[8.0.33,8.0.34)',\
org.yaml.snakeyaml;version='[2.4.0,2.4.1)'
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.openhab.core.events.EventPublisher;
import org.openhab.core.i18n.UnitProvider;
import org.openhab.core.items.Item;
import org.openhab.core.items.ItemBuilderFactory;
import org.openhab.core.items.ItemRegistry;
import org.openhab.core.items.ItemStateConverter;
import org.openhab.core.items.Metadata;
Expand Down Expand Up @@ -78,6 +79,7 @@
import org.openhab.core.thing.type.ChannelTypeUID;
import org.openhab.core.types.Command;
import org.openhab.core.types.TimeSeries;
import org.osgi.framework.BundleContext;

/**
*
Expand All @@ -89,8 +91,9 @@
public class CommunicationManagerOSGiTest extends JavaOSGiTest {

private static class ItemChannelLinkRegistryAdvanced extends ItemChannelLinkRegistry {
public ItemChannelLinkRegistryAdvanced(ThingRegistry thingRegistry, ItemRegistry itemRegistry) {
super(thingRegistry, itemRegistry);
public ItemChannelLinkRegistryAdvanced(ThingRegistry thingRegistry, ItemRegistry itemRegistry,
ItemBuilderFactory itemBuilderFactory, BundleContext bundleContext) {
super(null, thingRegistry, itemRegistry, itemBuilderFactory, bundleContext);
}

@Override
Expand Down Expand Up @@ -152,15 +155,19 @@ protected void addProvider(Provider<ItemChannelLink> provider) {
private @Mock @NonNullByDefault({}) ThingHandler thingHandlerMock;
private @Mock @NonNullByDefault({}) ThingRegistry thingRegistryMock;
private @Mock @NonNullByDefault({}) TriggerProfile triggerProfileMock;
private @Mock @NonNullByDefault({}) ItemBuilderFactory itemBuilderFactoryMock;

private @NonNullByDefault({}) CommunicationManager manager;
private @NonNullByDefault({}) SafeCaller safeCaller;

private ItemChannelLinkRegistryAdvanced iclRegistry = new ItemChannelLinkRegistryAdvanced(thingRegistryMock,
itemRegistryMock);
private @NonNullByDefault({}) ItemChannelLinkRegistryAdvanced iclRegistry;

@BeforeEach
public void beforeEach() {
registerVolatileStorageService();

iclRegistry = new ItemChannelLinkRegistryAdvanced(thingRegistryMock, itemRegistryMock, itemBuilderFactoryMock,
bundleContext);

when(UNIT_PROVIDER_MOCK.getUnit(Temperature.class)).thenReturn(SIUnits.CELSIUS);
item5 = new NumberItem("Number:Temperature", ITEM_NAME_5, UNIT_PROVIDER_MOCK);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/*
* Copyright (c) 2010-2025 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.core.thing.link;

import static org.junit.jupiter.api.Assertions.*;

import java.io.ByteArrayInputStream;
import java.util.List;
import java.util.Set;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openhab.core.items.Item;
import org.openhab.core.items.ItemRegistry;
import org.openhab.core.model.ItemsStandaloneSetup;
import org.openhab.core.model.core.ModelRepository;
import org.openhab.core.model.thing.ThingStandaloneSetup;
import org.openhab.core.test.java.JavaOSGiTest;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingRegistry;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.builder.ChannelBuilder;
import org.openhab.core.thing.binding.builder.ThingBuilder;

/**
* Tests for {@link ItemChannelLinkRegistry} tagging.
*
* @author Andrew Fiddian-Green - Initial contribution
*/
@NonNullByDefault
public class ItemChannelLinkTaggingOSGiTest extends JavaOSGiTest {

private static final String ITEMS_MODEL_ID = "test.items";
private static final String ITEMS_MODEL = """
String Item_01 {channel="hue:device:dummy:color" }
String Item_02 {channel="hue:device:dummy:color" [useTags=false] }
String Item_03 {channel="hue:device:dummy:color" [useTags="false"] }
String Item_04 "Control, Color" {channel="hue:device:dummy:color" [useTags=true] }
String Item_05 "Control, Color" {channel="hue:device:dummy:color" [useTags="true"] }
String Item_06 "Control Color, Custom" ["Custom"] {channel="hue:device:dummy:color" [useTags=true] }
String Item_07 "'Control', Power, Custom" ["Power", "Custom"] {channel="hue:device:dummy:color" }
String Item_08 "'Control', Power, Custom" ["Power", "Custom"] {channel="hue:device:dummy:color" [useTags=true] }
String Item_09 "Switch, Custom" ["Switch", "Custom"] {channel="hue:device:dummy:color" }
String Item_10 "Switch, Custom" ["Switch", "Custom"] {channel="hue:device:dummy:color" [useTags=true] }
String Item_11 "Switch, Power, Custom" ["Switch", "Power", "Custom"] {channel="hue:device:dummy:color" }
String Item_12 "Switch, Power, Custom" ["Switch", "Power", "Custom"] {channel="hue:device:dummy:color" [useTags=true] }
String Item_13 "Alarm, LowBattery" {channel="hue:device:dummy:battery-low" [useTags=true] }
String Item_14 "Control, Color" {channel="hue:device:dummy:color" [useTags=true], channel="hue:device:dummy:battery-low" [useTags=true] }
String Item_15 "Alarm, LowBattery" {channel="hue:device:dummy:color" [useTags=false], channel="hue:device:dummy:battery-low" [useTags=true] }
""";

private @NonNullByDefault({}) ItemRegistry itemRegistry;
private @NonNullByDefault({}) ThingRegistry thingRegistry;
private @NonNullByDefault({}) ModelRepository modelRepository;
private @NonNullByDefault({}) ItemChannelLinkRegistry itemChannelLinkRegistry;

@BeforeEach
public void setup() {
registerVolatileStorageService();

ItemsStandaloneSetup.doSetup();
ThingStandaloneSetup.doSetup();

itemRegistry = getService(ItemRegistry.class);
assertNotNull(itemRegistry);

thingRegistry = getService(ThingRegistry.class);
assertNotNull(thingRegistry);

itemChannelLinkRegistry = getService(ItemChannelLinkRegistry.class);
assertNotNull(itemChannelLinkRegistry);

modelRepository = getService(ModelRepository.class);
assertNotNull(modelRepository);
}

@Test
public void assertTagsAreCorrect() {
ThingTypeUID thingTypeUID = new ThingTypeUID("hue", "device");
ThingUID thingUID = new ThingUID(thingTypeUID, "dummy");

Channel colorChannel = ChannelBuilder.create(new ChannelUID(thingUID, "color"), "Color")
.withDefaultTags(Set.of("Control", "Color")).build();
Channel batteryChannel = ChannelBuilder.create(new ChannelUID(thingUID, "battery-low"), "Switch")
.withDefaultTags(Set.of("Alarm", "LowBattery")).build();

Thing thing = ThingBuilder.create(thingTypeUID, thingUID) //
.withChannels(List.of(colorChannel, batteryChannel)).build();

thingRegistry.add(thing);
assertEquals(1, thingRegistry.getAll().size());

modelRepository.addOrRefreshModel(ITEMS_MODEL_ID, new ByteArrayInputStream(ITEMS_MODEL.getBytes()));
assertEquals(15, itemRegistry.getAll().size());
assertEquals(17, itemChannelLinkRegistry.getAll().size());

Item item;

item = itemRegistry.get("Item_01");
assertNotNull(item);
assertTrue(item.getTags().isEmpty());

item = itemRegistry.get("Item_02");
assertNotNull(item);
assertTrue(item.getTags().isEmpty());

item = itemRegistry.get("Item_03");
assertNotNull(item);
assertTrue(item.getTags().isEmpty());

item = itemRegistry.get("Item_04");
assertNotNull(item);
assertEquals(Set.of("Control", "Color"), item.getTags());

item = itemRegistry.get("Item_05");
assertNotNull(item);
assertEquals(Set.of("Control", "Color"), item.getTags());

item = itemRegistry.get("Item_06");
assertNotNull(item);
assertEquals(Set.of("Control", "Color", "Custom"), item.getTags());

item = itemRegistry.get("Item_07");
assertNotNull(item);
assertEquals(Set.of("Power", "Custom"), item.getTags());

item = itemRegistry.get("Item_08");
assertNotNull(item);
assertEquals(Set.of("Power", "Custom"), item.getTags());

item = itemRegistry.get("Item_09");
assertNotNull(item);
assertEquals(Set.of("Switch", "Custom"), item.getTags());

item = itemRegistry.get("Item_10");
assertNotNull(item);
assertEquals(Set.of("Switch", "Custom"), item.getTags());

item = itemRegistry.get("Item_11");
assertNotNull(item);
assertEquals(Set.of("Switch", "Power", "Custom"), item.getTags());

item = itemRegistry.get("Item_12");
assertNotNull(item);
assertEquals(Set.of("Switch", "Power", "Custom"), item.getTags());

item = itemRegistry.get("Item_13");
assertNotNull(item);
assertEquals(Set.of("Alarm", "LowBattery"), item.getTags());

item = itemRegistry.get("Item_14");
assertNotNull(item);
assertTrue(item.getTags().equals(Set.of("Control", "Color")) //
|| item.getTags().equals(Set.of("Alarm", "LowBattery")));

item = itemRegistry.get("Item_15");
assertNotNull(item);
assertEquals(Set.of("Alarm", "LowBattery"), item.getTags());
}
}