Skip to content

Commit 4f4bab4

Browse files
committed
[yamlcomposer] New Yaml Composer add-on
Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
1 parent d06980d commit 4f4bab4

65 files changed

Lines changed: 10102 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,7 @@
465465
/bundles/org.openhab.io.metrics/ @pravussum
466466
/bundles/org.openhab.io.neeo/ @morph166955
467467
/bundles/org.openhab.io.openhabcloud/ @kaikreuzer
468+
/bundles/org.openhab.io.yamlcomposer/ @jimtng
468469
/bundles/org.openhab.persistence.dynamodb/ @ssalonen
469470
/bundles/org.openhab.persistence.influxdb/ @lujop
470471
/bundles/org.openhab.persistence.inmemory/ @J-N-K
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
This content is produced and maintained by the openHAB project.
2+
3+
* Project home: https://www.openhab.org
4+
5+
== Declared Project Licenses
6+
7+
This program and the accompanying materials are made available under the terms
8+
of the Eclipse Public License 2.0 which is available at
9+
https://www.eclipse.org/legal/epl-2.0/.
10+
11+
== Source Code
12+
13+
https://github.com/openhab/openhab-addons
Lines changed: 329 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,329 @@
1+
# YAML Composer
2+
3+
YAML Composer introduces extended YAML features that make openHAB configuration more modular, reusable, and maintainable. These features let you structure configuration as composable building blocks rather than large, repetitive files.
4+
5+
The add-on loads enhanced-syntax YAML files from `OPENHAB_CONF/yamlcomposer/` and compiles them into fully resolved plain YAML written to `OPENHAB_CONF/yaml/composed/`.
6+
7+
[[toc]]
8+
9+
## Feature Summary
10+
11+
YAML Composer adds several enhancements on top of standard YAML.
12+
Each feature addresses a different kind of reuse, composition, or abstraction to help you build cleaner and more maintainable YAML.
13+
14+
| Feature | Purpose | Typical Use |
15+
|--------------------------------------------|-----------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|
16+
| **Variables and Substitution (`${..}`)** | Insert dynamic values or evaluate expressions | Build labels, topics, IDs, or computed values |
17+
| **Conditionals (`!if`)** | Conditionally include or exclude YAML blocks | Enable or disable features when using packages or template flags |
18+
| **Include (`!include`)** | Insert the contents of another file | Reuse YAML across files; parameterize reusable blocks |
19+
| **Templates (`!insert`)** | Reuse YAML defined within the same file | Local parameterized blocks; reusable channel or item fragments |
20+
| **Packages** | Bundle multiple top-level sections into one reusable unit | Define reusable device structures containing things, items, metadata; sourced from external files or templates |
21+
| **Anchors and Aliases (`&name`, `*name`)** | Define small, reusable YAML fragments | Static defaults, shared fields |
22+
| **Merge Keys (`<<:`)** | Combine mappings from multiple sources | Layer defaults, override fields, compose structures |
23+
24+
Each feature has a dedicated documentation page:
25+
26+
- [Variables and Substitution](doc/variables.md)
27+
- [Conditionals](doc/conditionals.md)
28+
- [Include](doc/include.md)
29+
- [Templates](doc/templates.md)
30+
- [Packages](doc/packages.md)
31+
- [Anchors and Aliases](doc/anchors.md)
32+
- [Merge Keys](doc/merge-keys.md)
33+
34+
These features can be used independently, but they become especially powerful when combined.
35+
36+
For a general introduction to YAML, see [YAML Basics](doc/basics.md).
37+
38+
## Packaging Example
39+
40+
**CONF/yamlcompose/LivingRoom.yaml:**
41+
42+
```yaml
43+
version: 1
44+
45+
variables:
46+
# Captures "LivingRoom" from the filename automatically
47+
location: ${__FILE_NAME__} # => LivingRoom
48+
49+
packages:
50+
Light1: !include
51+
file: $pkg/zigbee_light.inc.yaml
52+
vars: &LIGHT_VARS
53+
color_temperature: {} # Include color temperature feature
54+
power: # Customize the power item
55+
groups:
56+
- gInsideLights
57+
- gSmartLights
58+
59+
Light2: !include
60+
file: $pkg/zigbee_light.inc.yaml
61+
vars:
62+
<<: *LIGHT_VARS
63+
```
64+
65+
**CONF/yamlcompose/pkg/zigbee_light.inc.yaml:**
66+
67+
```yaml
68+
# This is the package file, i.e. the template for a zigbee light
69+
variables:
70+
id: ${location}_${package_id}
71+
thingid: ${id | lower | replace("_", "-")}
72+
equipment: ${id}_Equipment
73+
label: ${id | label}
74+
75+
# Set defaults
76+
power: &DEFAULTS
77+
groups: []
78+
dimmer:
79+
<<: *DEFAULTS
80+
81+
things:
82+
mqtt:topic:${thingid}:
83+
bridge: mqtt:broker:mosquitto
84+
channels:
85+
power:
86+
type: switch
87+
config:
88+
stateTopic: zigbee2mqtt/${thingid}/state
89+
commandTopic: zigbee2mqtt/${thingid}/set/state
90+
91+
dimmer:
92+
type: dimmer
93+
config:
94+
stateTopic: zigbee2mqtt/${thingid}/brightness
95+
commandTopic: zigbee2mqtt/${thingid}/set/brightness
96+
97+
<<: !if
98+
if: VARS.containsKey('color_temperature')
99+
then:
100+
color-temperature: !sub
101+
type: dimmer
102+
config:
103+
stateTopic: zigbee2mqtt/${thingid}/color_temp
104+
commandTopic: zigbee2mqtt/${thingid}/set/color_temp
105+
106+
items:
107+
${equipment}:
108+
type: Group
109+
label: ${label} Equipment
110+
tags: [Lightbulb]
111+
groups: ${[location]}
112+
113+
${id}:
114+
type: Switch
115+
label: ${label}
116+
tags: [Control, Light]
117+
groups: ${[equipment] + power.groups}
118+
channel: mqtt:topic:${thingid}:power
119+
120+
${id}_Dimmer:
121+
type: Dimmer
122+
label: ${label} Brightness
123+
tags: [Control, Level]
124+
groups: ${[equipment] + dimmer.groups}
125+
channel: mqtt:topic:${thingid}:dimmer
126+
127+
<<: !if
128+
if: VARS.containsKey('color_temperature')
129+
then:
130+
${id}_CT:
131+
type: Dimmer
132+
label: ${label} Color Temperature
133+
tags: [Control, ColorTemperature]
134+
groups: ${[equipment] + color_temperature.groups}
135+
channel: mqtt:topic:${thingid}:color-temperature
136+
```
137+
138+
<details>
139+
<summary><b>Output in CONF/yaml/composed/LivingRoom.yaml:</b></summary>
140+
141+
```yaml
142+
# ==============================================================================
143+
# Generated by openHAB 5.2.0 (Build #5196) YAML Composer, DO NOT EDIT
144+
# Source: yamlcomposer/LivingRoom.yaml
145+
# Generated: 2026-03-06T16:25:52.975308240+10:00[Australia/Brisbane]
146+
# ==============================================================================
147+
148+
version: 1
149+
150+
things:
151+
mqtt:topic:livingroom-light1:
152+
bridge: mqtt:broker:mosquitto
153+
channels:
154+
power:
155+
type: switch
156+
config:
157+
stateTopic: zigbee2mqtt/livingroom-light1/state
158+
commandTopic: zigbee2mqtt/livingroom-light1/set/state
159+
dimmer:
160+
type: dimmer
161+
config:
162+
stateTopic: zigbee2mqtt/livingroom-light1/brightness
163+
commandTopic: zigbee2mqtt/livingroom-light1/set/brightness
164+
color-temperature:
165+
type: dimmer
166+
config:
167+
stateTopic: zigbee2mqtt/livingroom-light1/color_temp
168+
commandTopic: zigbee2mqtt/livingroom-light1/set/color_temp
169+
170+
mqtt:topic:livingroom-light2:
171+
bridge: mqtt:broker:mosquitto
172+
channels:
173+
power:
174+
type: switch
175+
config:
176+
stateTopic: zigbee2mqtt/livingroom-light2/state
177+
commandTopic: zigbee2mqtt/livingroom-light2/set/state
178+
dimmer:
179+
type: dimmer
180+
config:
181+
stateTopic: zigbee2mqtt/livingroom-light2/brightness
182+
commandTopic: zigbee2mqtt/livingroom-light2/set/brightness
183+
color-temperature:
184+
type: dimmer
185+
config:
186+
stateTopic: zigbee2mqtt/livingroom-light2/color_temp
187+
commandTopic: zigbee2mqtt/livingroom-light2/set/color_temp
188+
189+
items:
190+
LivingRoom_Light1_Equipment:
191+
type: Group
192+
label: Living Room Light 1 Equipment
193+
tags:
194+
- Lightbulb
195+
groups:
196+
- LivingRoom
197+
198+
LivingRoom_Light1:
199+
type: Switch
200+
label: Living Room Light 1
201+
tags:
202+
- Control
203+
- Light
204+
groups:
205+
- LivingRoom_Light1_Equipment
206+
- gInsideLights
207+
- gSmartLights
208+
channel: mqtt:topic:livingroom-light1:power
209+
210+
LivingRoom_Light1_Dimmer:
211+
type: Dimmer
212+
label: Living Room Light 1 Brightness
213+
tags:
214+
- Control
215+
- Level
216+
groups:
217+
- LivingRoom_Light1_Equipment
218+
channel: mqtt:topic:livingroom-light1:dimmer
219+
220+
LivingRoom_Light1_CT:
221+
type: Dimmer
222+
label: Living Room Light 1 Color Temperature
223+
tags:
224+
- Control
225+
- ColorTemperature
226+
groups:
227+
- LivingRoom_Light1_Equipment
228+
channel: mqtt:topic:livingroom-light1:color-temperature
229+
230+
LivingRoom_Light2_Equipment:
231+
type: Group
232+
label: Living Room Light 2 Equipment
233+
tags:
234+
- Lightbulb
235+
groups:
236+
- LivingRoom
237+
238+
LivingRoom_Light2:
239+
type: Switch
240+
label: Living Room Light 2
241+
tags:
242+
- Control
243+
- Light
244+
groups:
245+
- LivingRoom_Light2_Equipment
246+
- gInsideLights
247+
- gSmartLights
248+
channel: mqtt:topic:livingroom-light2:power
249+
250+
LivingRoom_Light2_Dimmer:
251+
type: Dimmer
252+
label: Living Room Light 2 Brightness
253+
tags:
254+
- Control
255+
- Level
256+
groups:
257+
- LivingRoom_Light2_Equipment
258+
channel: mqtt:topic:livingroom-light2:dimmer
259+
260+
LivingRoom_Light2_CT:
261+
type: Dimmer
262+
label: Living Room Light 2 Color Temperature
263+
tags:
264+
- Control
265+
- ColorTemperature
266+
groups:
267+
- LivingRoom_Light2_Equipment
268+
channel: mqtt:topic:livingroom-light2:color-temperature
269+
```
270+
271+
</details>
272+
273+
## Processing Overview
274+
275+
YAML Composer reads enhanced-syntax YAML files and performs a compilation pass that expands all extended features into a single, fully resolved YAML document that openHAB can load.
276+
277+
During compilation, YAML Composer performs the following steps:
278+
279+
1. **YAML Parsing**: The source file is parsed into an internal structure.
280+
2. **Variable Substitution (`${..}`)**: Expressions are evaluated and injected.
281+
3. **Conditionals (`!if`)**: Conditional logic determines which blocks remain.
282+
4. **Template and Include Expansion**: `!insert` and `!include` bring in referenced content, often using resolved variables.
283+
5. **Package Expansion**: External or local packages are loaded and expanded into their component sections.
284+
6. **Recursive Merging**: Merge keys and package structures are combined into the main document.
285+
7. **Hidden Key Removal**: Keys beginning with `.` are removed from the final output.
286+
287+
The resulting YAML contains:
288+
289+
- all variables resolved
290+
- all conditionals evaluated
291+
- all templates and includes expanded
292+
- all anchors and merges applied
293+
- all packages integrated
294+
- all hidden keys removed
295+
296+
This final compiled YAML is written to `CONF/yaml/composed/`, where openHAB loads it as Things, Items, Metadata, and other configuration elements as defined by the Core YAML Configuration structure.
297+
298+
## Hidden Keys
299+
300+
Keys beginning with a dot (`.`) are treated as hidden. They:
301+
302+
- exist only during compilation
303+
- are ideal for storing anchors, templates, or shared structures
304+
- keep visible configuration clean
305+
- are removed from the final output
306+
307+
**Example:**
308+
309+
```yaml
310+
.base-switch: &BASE_SWITCH
311+
type: Switch
312+
autoupdate: false
313+
314+
items:
315+
Light1:
316+
<<: *BASE_SWITCH
317+
label: Light One
318+
```
319+
320+
## File Structure and Conventions
321+
322+
YAML files can be organized freely, but the following conventions improve clarity and maintainability:
323+
324+
- Place `variables:` and `templates:` near the top of the file.
325+
- Group reusable structures under hidden keys.
326+
- Use anchors for static fragments and includes for parameterized ones.
327+
- Keep packages in separate files when they represent reusable device or feature definitions.
328+
329+
These conventions are optional but help keep complex configurations predictable and easy to navigate.

0 commit comments

Comments
 (0)