Yamlcomposer: pass empty map to channels definition (bug?)

I’d like to link 2 channel definitions to an item, one with an empty config and the other with a follow-profile. The reason is because I want a radiator valve to use the temperature measured by an external temperature sensor. I’m using yamlcomposer to create my items. My code:

  ${property}_T:
    type: Number
    label: Temperature
    icon: temperature
    groups: ${[equipment] + temperature.groups}
    tags: [Measurement,Temperature]
    format: '%.1f °'
    channels:
      mqtt:topic:${thingid}:temperature: {}
      mqtt:topic:${thingid | replace("C", "R")}:external_temperature_input:
        profile: system:follow

The first channel is completely missing in the composed yaml file. Is that because of the empty map ({}) and is it a bug then? Or am I doing something wrong?

Can you paste the relevant parts of the composed yaml file?

The composed part is:

  pFF_BE1_C_T:
    type: Number
    label: Temperature
    icon: temperature
    groups:
      - eFF_BE1_C
      - gPIDController_Temperatures
      - gPersist_GraphInflux
      - gPersist_RestoreOnStartup
    tags:
      - Measurement
      - Temperature
    format: '%.1f °'
    channels:
      mqtt:topic:tZB_FF_BE1_R:external_temperature_input:
        profile: system:follow

while I expected it to be:

  pFF_BE1_C_T:
    type: Number
    label: Temperature
    icon: temperature
    groups:
      - eFF_BE1_C
      - gPIDController_Temperatures
      - gPersist_GraphInflux
      - gPersist_RestoreOnStartup
    tags:
      - Measurement
      - Temperature
    format: '%.1f °'
    channels:
      mqtt:topic:tZB_FF_BE1_C:temperature: {}
      mqtt:topic:tZB_FF_BE1_R:external_temperature_input:
        profile: system:follow

It’s strange. I cannot reproduce this issue on 5.2.1.

Here’s my test:

variables:
  property: Test
  thingid: ThingID_C
  equipment: equipment
  temperature:
    groups: temp_group


items:
  ${property}_T:
    type: Number
    label: Temperature
    icon: temperature
    groups: ${[equipment] + temperature.groups}
    tags: [Measurement,Temperature]
    format: '%.1222f °'
    channels:
      mqtt:topic:${thingid}:temperature: {}
      mqtt:topic:${thingid | replace("C", "R")}:external_temperature_input:
        profile: system:follow

The output:

# ==============================================================================
# Generated by openHAB 5.2.1 (Release Build) YAML Composer, DO NOT EDIT
# Source:    yamlcomposer/main.yaml
# Generated: 2026-09-09T07:54:47.140460642+10:00[Australia/Brisbane]
# ==============================================================================

items:
  Test_T:
    type: Number
    label: Temperature
    icon: temperature
    groups:
      - equipment
      - temp_group
    tags:
      - Measurement
      - Temperature
    format: '%.1222f °'
    channels:
      mqtt:topic:ThingID_C:temperature: {
        }
      mqtt:topic:ThingID_R:external_temperature_input:
        profile: system:follow

Can you show the surroundings of the source yaml block? Is there a !remove involved?

I don’t use !remove. The construction I use is as follows, I can reproduce it with these files:

<OH_PATH>/yamlcomposer/testcase.yaml:

version: 1

variables:
  instance: myinstance
  room: ${__FILE_NAME__}
  shortname: TESTCASE

packages:
  C: !include
    file: $pkg/testcase.inc.yaml
    vars:
      temperature:
        groups:
          - gPIDController_Temperatures

<OH_PATH>/yamlcomposer/pkg/testcase.inc.yaml:

variables:
  id: ${shortname}_${package_id}
  thingid: tZB_${id | upper}
  topic: ${id | lower | replace("_", "-")}
  location: l${room}
  equipment: e${id}
  property: p${id}
  label: ${id | label}

  etemperature: &DEFAULTS
    default_groups: [gPersist_GraphInflux,gPersist_RestoreOnStartup]
  humidity:
    <<: *DEFAULTS

  ${property}_T:
    type: Number
    label: Temperatuur
    icon: temperature
    groups: ${[equipment] + temperature.groups + etemperature.default_groups}
    tags: [Measurement,Temperature]
    format: '%.1f °'
    channels:
      mqtt:topic:${thingid}:temperature: {}
      mqtt:topic:${thingid | replace("C", "R")}:external_temperature_input:
        profile: system:follow

This results in the following composed <OH_PATH>/yaml/composed/testcase.yaml:

# ==============================================================================
# Generated by openHAB 5.2.1 (Release Build) YAML Composer, DO NOT EDIT
# Source:    yamlcomposer/testcase.yaml
# Generated: 2026-09-09T08:40:07.468242374+02:00[Europe/Amsterdam]
# ==============================================================================

version: 1

items:
  pTESTCASE_C_T:
    type: Number
    label: Temperatuur
    icon: temperature
    groups:
      - eTESTCASE_C
      - gPIDController_Temperatures
      - gPersist_GraphInflux
      - gPersist_RestoreOnStartup
    tags:
      - Measurement
      - Temperature
    format: '%.1f °'
    channels:
      mqtt:topic:tZB_TESTRASE_R:external_temperature_input:
        profile: system:follow

I can confirm this appears to be a bug.

Current workaround:

    channels:
      mqtt:topic:${thingid}:temperature: 
        profile: default

Thanks, workaround seems to be doing the trick for now

I’ve also created a backport patch: [yamlcomposer] Fix missing empty maps in the package output by jimtng · Pull Request #21636 · openhab/openhab-addons · GitHub

I originally wanted to clean up the package output so I deliberately stripped away empty maps and lists. However there’s obviously a need to preserve them in the case of item channels exactly in this situation.

So the fix simply removes the code that strips the empty maps and lists.