OH create different items for the same config

  • Platform information:
    • Hardware: docker
    • OS: “openhab/openhab:4.3.5”
    • Java Runtime Environment: which java platform is used and what version
    • openHAB version: “openhab/openhab:4.3.5”
  • Issue of the topic: please be detailed explaining your issue
    I have test config in text format:

brocker.things

mqtt:broker:SNGMQTTBrocker [ host="0.0.0.0" ]

test.things

Thing mqtt:topic:SNG-IOT-RTL-01 "SNG-IOT-RTL-01" (mqtt:broker:SNGMQTTBrocker) {
    Channels:
    
    Type contact : SNG-IOT-RTL-01-CT-14 "Вхід 14" [ stateTopic="iot/sng-iot-rtl-01/event/14", on="0", off="1" ]
    Type contact : SNG-IOT-RTL-01-CT-15 "Вхід 15" [ stateTopic="iot/sng-iot-rtl-01/event/15", on="0", off="1" ]

    Type switch :  SNG-IOT-RTL-01-SW-14 "Вхід 14" [ stateTopic="iot/sng-iot-rtl-01/event/14", on="0", off="1", postCommand="true" ]
    Type switch :  SNG-IOT-RTL-01-SW-15 "Вхід 15" [ stateTopic="iot/sng-iot-rtl-01/event/15", on="0", off="1", postCommand="true" ]

    Type switch :  SNG-IOT-RTL-01-RL-02 "Реле 2" [ commandTopic="iot/sng-iot-rtl-01/command", on="{ \"pin\": 2, \"state\": 1 }", off="{ \"pin\": 2, \"state\": 0 }" ]
    Type switch :  SNG-IOT-RTL-01-RL-03 "Реле 3" [ commandTopic="iot/sng-iot-rtl-01/command", on="{ \"pin\": 3, \"state\": 1 }", off="{ \"pin\": 3, \"state\": 0 }" ]
}

test.items

Contact SNG_RTL_IOT_DEV_01_CT_14 "Вимикач коридор, права" <wallswitch> ["WallSwitch"] {channel="mqtt:topic:SNG-IOT-RTL-01:SNG-IOT-RTL-01-CT-14" }
Contact SNG_RTL_IOT_DEV_01_CT_15 "Вимикач коридор-ванна, права" <wallswitch> ["WallSwitch"] {channel="mqtt:topic:SNG-IOT-RTL-01:SNG-IOT-RTL-01-CT-15" }

Switch SNG_RTL_IOT_DEV_01_RL_02 "R2" <light> ["Equipment_Lightbulb", "Lightbulb"] {channel="mqtt:topic:SNG-IOT-RTL-01:SNG-IOT-RTL-01-SW-15", channel="mqtt:topic:SNG-IOT-RTL-01:SNG-IOT-RTL-01-RL-02"}
Switch SNG_RTL_IOT_DEV_01_RL_03 "R3" <light> ["Equipment_Lightbulb", "Lightbulb"] {channel="mqtt:topic:SNG-IOT-RTL-01:SNG-IOT-RTL-01-SW-14", channel="mqtt:topic:SNG-IOT-RTL-01:SNG-IOT-RTL-01-RL-03"}

As result I see 2 different items in UI. One as text, second as switch:

What I did wrong? Both channels look the same, difference only in ID/pins config.

“Equipment_Lightbulb” isn’t a semantic tag so I’m not sure what you are using that for.

“Lightbulb” is an Equipment tag. That’s usually only applied to a Group, not the individual Items that control things. Point and Property tags are applied to those Items. A normal structure in the semantic model would be something like

Kitchen (Group Item, tagged with "kitchen")
  |_Lights (Group Item, tagged with "Lightbulb")
    |_R2 (Switch Item, tagged with "Switch" and "Light")
    |_R3 (Switch Item, tagged witn "Switch" and "Light")

You should only ever use location tags and equipment tags with Group Items. MainUI is going to look at the tags to determine what sort of widget to show by default. But it is expecting Point and Property tags for a Switch Item, but it’s finding an Equipment tag, and clearly it’s getting confused,

I have removed tags from item config. As result - I don’t see Lights section in equipment tab. And this don’t resolve main issue:
R3 created as switch, and I see switch in item. I able to ON/OFF light from UI.
R2 created as strange switch - I see ON/OFF status as text and not able to On/Off light from UI. But at the same time all works as expected for both items on hardware level - changing state for physical switch leads to send command to on or off light to physical device. But I not able control state via UI only for R2.

“Equipment_Lightbulb” I got from production OH from item added via UI:

but I guess it is not related to issue.

I tried change ID for all thing channels like SNG-IOT-RTL-01-SW-14 => T-SW-14. This fix issue for this test example but don’t work for real config with 24 channels.

You should have a Group Item tagged with “Lightbulb”.

R2 and R3 should be members of this Group.

R2 and R3 should be tagged with “Switch” and “Light”.

I guess it should works correct without tags. Tags is optional configuration. Main question - why with the same config I have items with 2 different behaviors? Why changing ID lead to change behavior?

It looks like some issue in MainUI - with the same config we have different control in UI. With manual reproducing this issue I can’t create switch when link item to channel from item. But when I link channel to item from channel, I can create switch but without guaranties. Sometimes it is becoming string, sometimes it is becoming switch.

It won’t show up in the MainUI Overview tabs without tags. Those tabs are populated strictly with Items that are tagged with semantic tags.

Because these are non-Group Items tagged with an Equipment tag, MainUI gets confused about which widget to choose to represent them. Without looking at the code I can’t say more. But I will say I’m surprised these Items showed up at all. Tagging them with an Equipment tag is semantically incorrect and an error.

The binding also will push semantic tags and other information which can change the behavior, but that’s not the case here since it’s the MQTT binding.

I not sure about that but I guess I found issue.
web/src/components/widgets/standard/default-standalone-item.js check stateDescription.readOnly to show switch but api return trye for one item and false for another item:

http://openhab-test/rest/items/SNG_RTL_IOT_DEV_01_RL_02?metadata=.+

{
    "link": "http://openhab-test/rest/items/SNG_RTL_IOT_DEV_01_RL_02",
    "state": "NULL",
    "stateDescription": {
        "pattern": "%s",
        "readOnly": true,
        "options": []
    },
    "metadata": {
        "semantics": {
            "value": "Equipment_Lightbulb"
        }
    },
    "editable": false,
    "type": "Switch",
    "name": "SNG_RTL_IOT_DEV_01_RL_02",
    "label": "R2",
    "category": "light",
    "tags": [
        "Equipment_Lightbulb",
        "Lightbulb"
    ],
    "groupNames": []
}

http://openhab-test/rest/items/SNG_RTL_IOT_DEV_01_RL_03?metadata=.+

{
    "link": "http://openhab-test/rest/items/SNG_RTL_IOT_DEV_01_RL_03",
    "state": "NULL",
    "stateDescription": {
        "pattern": "%s",
        "readOnly": false,
        "options": []
    },
    "metadata": {
        "semantics": {
            "value": "Equipment_Lightbulb"
        }
    },
    "editable": false,
    "type": "Switch",
    "name": "SNG_RTL_IOT_DEV_01_RL_03",
    "label": "R3",
    "category": "light",
    "tags": [
        "Equipment_Lightbulb",
        "Lightbulb"
    ],
    "groupNames": []
}

As result we have switch control only for one of them. Item has 2 links - one link readonly switch, another link writeonly switch. I need to check how OH-core calculate readOnly status.

OH core doesn’t. That’s a value pushed by the binding.

Yes, I did some debug and see that this value pushed by binding for channel but for 2 channels linked to item OH core get random channel and get readonly value from this channel:

  private @Nullable StateDescription getStateDescription(String itemName, @Nullable Locale locale) {
        Set<ChannelUID> boundChannels = itemChannelLinkRegistry.getBoundChannels(itemName);
        if (!boundChannels.isEmpty()) {
            ChannelUID channelUID = boundChannels.iterator().next();
            Channel channel = thingRegistry.getChannel(channelUID);
            if (channel != null) {
                StateDescription stateDescription = null;
                ChannelType channelType = thingTypeRegistry.getChannelType(channel, locale);
                if (channelType != null) {
                    stateDescription = channelType.getState();
                }
                StateDescription dynamicStateDescription = getDynamicStateDescription(channel, stateDescription,
                        locale);
                if (dynamicStateDescription != null) {
                    return dynamicStateDescription;
                }
                return stateDescription;
            }
        }
        return null;
    }

For R3 channel OH get value from mqtt:topic:SNG-IOT-RTL-01:SNG-IOT-RTL-01-RL-03 channel, it is not readonly channel and I see switch

2025-06-02 18:51:30.561 [DEBUG] [rnal.ChannelStateDescriptionProvider] - getStateDescription, boundChannels: [mqtt:topic:SNG-IOT-RTL-01:SNG-IOT-RTL-01-RL-03, mqtt:topic:SNG-IOT-RTL-01:SNG-IOT-RTL-01-SW-14]
2025-06-02 18:51:30.562 [DEBUG] [rnal.ChannelStateDescriptionProvider] - Channel channel: org.openhab.core.thing.binding.builder.ChannelBuilder$ChannelImpl@1f4a8b47
2025-06-02 18:51:30.562 [DEBUG] [rnal.ChannelStateDescriptionProvider] - ChannelType channelType: mqtt:switch
2025-06-02 18:51:30.562 [DEBUG] [rnal.ChannelStateDescriptionProvider] - StateDescription stateDescription: null
2025-06-02 18:51:30.562 [DEBUG] [rnal.ChannelStateDescriptionProvider] - Channel channel: org.openhab.core.thing.binding.builder.ChannelBuilder$ChannelImpl@8d2e62ae
2025-06-02 18:51:30.562 [DEBUG] [rnal.ChannelStateDescriptionProvider] - ChannelType channelType: mqtt:switch
2025-06-02 18:51:30.562 [DEBUG] [rnal.ChannelStateDescriptionProvider] - StateDescription stateDescription: null
2025-06-02 18:51:30.563 [DEBUG] [rnal.ChannelStateDescriptionProvider] - getDynamicStateDescription, provider org.openhab.binding.mqtt.generic.MqttChannelStateDescriptionProvider@2215a54c, channel: mqtt:topic:SNG-IOT-RTL-01:SNG-IOT-RTL-01-RL-03
2025-06-02 18:51:30.563 [DEBUG] [rnal.ChannelStateDescriptionProvider] - getDynamicStateDescription, result StateDescription [minimum=null, maximum=null, step=null, pattern=%s, readOnly=false, channelStateOptions=[]], dynamicStateDescription: false
2025-06-02 18:51:30.563 [DEBUG] [.service.StateDescriptionServiceImpl] - stateDescriptionFragmentProvider: org.openhab.core.thing.internal.ChannelStateDescriptionProvider@55d03374, class org.openhab.core.thing.internal.ChannelStateDescriptionProvider
2025-06-02 18:51:30.563 [DEBUG] [.service.StateDescriptionServiceImpl] - Create fragment for item: 'SNG_RTL_IOT_DEV_01_RL_03', fragment: 'StateDescription [minimum=null, maximum=null, step=null, pattern=%s, readOnly=false, channelStateOptions=[]]', result: StateDescription [minimum=null, maximum=null, step=null, pattern=%s, readOnly=false, channelStateOptions=[]]

But for R2 channel OH core get state from read only switch channel mqtt:topic:SNG-IOT-RTL-01:SNG-IOT-RTL-01-SW-15, as result I see text

2025-06-02 18:51:29.592 [DEBUG] [rnal.ChannelStateDescriptionProvider] - getStateDescription, boundChannels: [mqtt:topic:SNG-IOT-RTL-01:SNG-IOT-RTL-01-SW-15, mqtt:topic:SNG-IOT-RTL-01:SNG-IOT-RTL-01-RL-02]
2025-06-02 18:51:29.592 [DEBUG] [rnal.ChannelStateDescriptionProvider] - Channel channel: org.openhab.core.thing.binding.builder.ChannelBuilder$ChannelImpl@f6c4dc8b
2025-06-02 18:51:29.592 [DEBUG] [rnal.ChannelStateDescriptionProvider] - ChannelType channelType: mqtt:switch
2025-06-02 18:51:29.592 [DEBUG] [rnal.ChannelStateDescriptionProvider] - StateDescription stateDescription: null
2025-06-02 18:51:29.592 [DEBUG] [rnal.ChannelStateDescriptionProvider] - Channel channel: org.openhab.core.thing.binding.builder.ChannelBuilder$ChannelImpl@b8339307
2025-06-02 18:51:29.592 [DEBUG] [rnal.ChannelStateDescriptionProvider] - ChannelType channelType: mqtt:switch
2025-06-02 18:51:29.592 [DEBUG] [rnal.ChannelStateDescriptionProvider] - StateDescription stateDescription: null
2025-06-02 18:51:29.592 [DEBUG] [rnal.ChannelStateDescriptionProvider] - getDynamicStateDescription, provider org.openhab.binding.mqtt.generic.MqttChannelStateDescriptionProvider@2215a54c, channel: mqtt:topic:SNG-IOT-RTL-01:SNG-IOT-RTL-01-SW-15
2025-06-02 18:51:29.592 [DEBUG] [rnal.ChannelStateDescriptionProvider] - getDynamicStateDescription, result StateDescription [minimum=null, maximum=null, step=null, pattern=%s, readOnly=true, channelStateOptions=[]], dynamicStateDescription: true
2025-06-02 18:51:29.593 [DEBUG] [.service.StateDescriptionServiceImpl] - stateDescriptionFragmentProvider: org.openhab.core.thing.internal.ChannelStateDescriptionProvider@55d03374, class org.openhab.core.thing.internal.ChannelStateDescriptionProvider
2025-06-02 18:51:29.593 [DEBUG] [.service.StateDescriptionServiceImpl] - Create fragment for item: 'SNG_RTL_IOT_DEV_01_RL_02', fragment: 'StateDescription [minimum=null, maximum=null, step=null, pattern=%s, readOnly=true, channelStateOptions=[]]', result: StateDescription [minimum=null, maximum=null, step=null, pattern=%s, readOnly=true, channelStateOptions=[]]

I guess it is bug. Is it correct?

Possilbly, a bug. I don’t know under what circumstances the MQTT binding sends read only stateDescription metadata to the Item.

Fix merged