Parameter Playground

This UI widget is not a functional widget in that it is something you would want to put on your Pages. It is intended to provide examples of most of what is possible when defining properties on custom UI widgets and rule templates for reference and testing. It presents properties in all sorts of different ways and shows you what the property becomes when the user selects is. For example, the Multiple Items property shows how one can select more than one Item and the widget renders what that looks like (a comma separated list of Item names).

To use the widget, first install it from the marketplace.

Then Navigate to MainUI → Developer Tools → UI Widgets → parameterPlayground.

In the bottom left select Set Props, and you’ll be presented with a form showing how each parameter is displayed to the user to fill them out. On the right you will see exactly how that value will be passed into your widget once the parameter is selected.

I used numbering to help correlate the property with where it’s rendered in the widget. The order is not the same because the parameter Grouping will change the order the fields are shown to the user.

Some features demonstrated include:

  • grouping parameters so they are displayed together on the form
  • flagging parameters as advanced so they only appear when “Show Advanced” is selected
  • default values
  • selecting multiple (e.g. multiple Items)
  • filtering (does not work prior to OH 5.1 M3)
  • Item, Thing, Channel, rule/script pickers
  • Map picker
  • cron expression builder
  • Units
  • regex input checking
  • date and time pickers

For more details on what contexts are supported see ConfigDescriptionParameter (openHAB Core 5.1.0-SNAPSHOT API)

As of this writing the following contexts do not do anything so you can avoid them (I’ve removed them from the original version of this widget):

  • network-address
  • network-interface
  • serial-port
  • password-create
  • week
  • telephone
  • url
  • tag (but you can filter on tags)
  • group (is probably going to be removed, use item with filterCritera on type Group)
  • service
  • channel-type

Some notes on filterCriteria are needed.

  • You can have more than one criterion on the same parameter which can be helpful to narrow down the list based both on tag and Item type.
  • Filtering on Number dimensions (e.g. Number:Temperature) works, but it will also so plain Number Items without units. this also applies to Group’s (e.g. Group:Number:Temperature).
  • I recommend always showing the filter button so the end users can choose something else. They know better than we do what’s appropriate.

Screenshots

Changelog

Verison 0.2

  • removed contexts that don’t do anything
  • added more filterCritera examples
  • added headers to the rendered widget to make it easier to map the list item to the property
  • added more parameter groups for UI, numbers, and date time
  • added a numbering scheme to make mapping the list item to the property easier

Version 0.1

  • initial release

Resources

uid: parameterPlayground
tags: []
props:
  parameters:
    - context: item
      description: Only allow selection of Switch and Contact Items
      label: I-1 Switch or Contact Item
      name: switchContact
      required: false
      type: TEXT
      groupName: items
      filterCriteria:
        - value: Switch,Contact
          name: type
        - value: "true"
          name: filterToggle
    - context: item
      description: Only allow selection of Number and Number:Temperature Items
      label: I-2 Temperature Item
      name: numberItem
      required: false
      type: TEXT
      groupName: items
      filterCriteria:
        - value: Number:Temperature
          name: type
        - value: "true"
          name: filterToggle
    - context: item
      description: Only show Group Items
      label: I-3 Group
      name: group
      required: true
      type: TEXT
      groupName: items
      filterCriteria:
        - value: Group
          name: type
        - value: "true"
          name: filterToggle
    - context: item
      description: Only show Group Items of type Number
      label: I-4 Number Group
      name: groupTypeFilter
      required: true
      type: TEXT
      groupName: items
      filterCriteria:
        - value: Number
          name: groupType
        - value: Group
          name: type
        - value: "true"
          name: filterToggle
    - context: item
      default: not set
      description: Select more than one DateTime Item
      label: I-5 Multiple Items
      name: multi
      required: false
      type: TEXT
      multiple: true
      groupName: items
      filterCriteria:
        - value: DateTime
          name: type
    - context: item
      default: not set
      description: Select an Item from a list only showing Items with the Switch or
        Light tags.
      label: I-6 An Item with tag
      name: withTags
      required: false
      type: TEXT
      groupName: items
      filterCriteria:
        - value: Switch,Light
          name: tag
    - context: item
      description: Select an Item from a list only showing Number, Number:Temperature,
        and Items with the Setpoint tag
      label: I-7 A temperature setpoint Item
      name: setpoint
      required: false
      type: TEXT
      groupName: items
      filterCriteria:
        - value: Number:Temperature
          name: type
        - value: Setpoint
          name: tag
    - context: rule
      default: not set
      description: Select from Scenes, Scripts, and Rules
      label: R-1 Script to Call
      name: script
      required: false
      type: TEXT
      groupName: rules
    - context: script
      description: Create an inline script
      label: R-2 Inline script
      name: inlineScript
      required: false
      type: TEXT
      groupName: rules
    - context: thing
      default: not set
      description: Select a Thing
      label: T-1 Thing
      name: thing
      required: false
      type: TEXT
      groupName: things
    - context: channel
      description: Select an Event Channel
      label: T-2 Event Channel
      name: channel
      required: false
      type: TEXT
      groupName: things
    - context: date
      description: Choose a date using a calendar
      label: D-1 Date Picker
      name: date
      required: false
      type: TEXT
      groupName: datetime
    - context: datetime
      description: Choose a date and time using pickers
      label: D-2 Date and Time Picker
      name: datetime
      required: false
      type: TEXT
      groupName: datetime
    - context: month
      description: Choose a month of the year
      label: D-3 Month
      name: month
      required: false
      type: TEXT
      groupName: datetime
    - context: dayOfWeek
      description: Choose a day of the week
      label: D-4 Day of the Week
      name: day
      required: false
      type: TEXT
      groupName: datetime
    - context: time
      description: Select a time, 24 hour format
      label: D-5 Time
      name: time
      required: false
      type: TEXT
      groupName: datetime
    - default: not set
      description: Any arbitrary text
      label: M-1 Arbitrary Text
      name: text
      required: false
      type: TEXT
      groupName: input
    - default: "7"
      description: An integer > 0, defaults to 7
      label: N-1 Integer
      name: integer
      required: false
      type: INTEGER
      min: 0
      groupName: input
    - default: "8"
      description: An integer between 0 and 10 with a step of 2, defaults to 8
      label: N-2 Bound Integer
      name: boundInt
      required: false
      type: INTEGER
      min: 0
      max: 10
      groupName: input
    - default: "12.34"
      description: A decimal value
      label: N-3 Decimal
      name: decimal
      required: false
      type: DECIMAL
      groupName: input
    - default: "65"
      description: A decimal value with units
      label: N-4 Temperature
      name: temp
      required: false
      type: DECIMAL
      groupName: input
      unit: F
      unitLabel: °F
    - default: ==
      description: Select from a list, default is ==
      label: M-2 List Selection
      name: list
      required: false
      type: TEXT
      groupName: input
      limitToOptions: true
      options:
        - label: == equals
          value: ==
        - label: "!= not equals"
          value: "!="
        - label: < less than
          value: <
        - label: <= less than equal
          value: <=
        - label: "> greater than"
          value: ">"
        - label: ">= greater than equal"
          value: ">="
    - default: "true"
      description: A binary selection
      label: M-3 Boolean Option
      name: bool
      required: false
      type: BOOLEAN
      groupName: input
    - context: password
      default: not set
      description: Passwords or other secrets that should not be displayed
      label: M-4 Password
      name: password
      required: false
      type: TEXT
      groupName: input
    - context: color
      description: Choose a color using a color wheel
      label: M-5 Color Picker
      name: color
      required: false
      type: TEXT
      groupName: input
    - context: email
      description: Enforces email address formatting
      label: M-6 Email address
      name: email
      required: false
      type: TEXT
      groupName: input
    - context: location
      description: Map location picker
      label: M-7 Location
      name: location
      required: false
      type: TEXT
      groupName: input
    - context: cronexpression
      description: M-8 Cron Expression
      label: Cron Expression
      name: cron
      required: false
      type: TEXT
      groupName: input
    - context: persistenceService
      description: Persistence service picker
      label: M-9 Persistence Service
      name: persistence
      required: false
      type: TEXT
      groupName: input
    - context: page
      description: Page picker
      label: U-1 Page
      name: page
      required: false
      type: TEXT
      groupName: ui
    - context: widget
      description: Widget picker
      label: U-2 Widget
      name: widget
      required: false
      type: TEXT
      groupName: ui
    - description: Arbitrary text limited to IP address formatting
      label: M-10 Regex enforcing IP address formatting
      name: regex
      required: false
      type: TEXT
      pattern: \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}
      groupName: input
    - default: not set
      description: Advanced property, should be hidden until show advanced is checked
      label: A-1 Avanced property
      name: advanced
      required: false
      type: TEXT
      groupName: input
      advanced: true
    - default: not set
      description: Advanced property 1, should be hidden until show advanced is checked
      label: A-2 Avanced property 1
      name: advanced1
      required: false
      type: TEXT
      groupName: advanced
      advanced: false
    - default: not set
      description: Advanced property 2, should be hidden until show advanced is checked
      label: A-3 Avanced property 2
      name: advanced2
      required: false
      type: TEXT
      groupName: advanced
      advanced: false
  parameterGroups:
    - name: items
      advanced: false
      label: Item selectors
      description: Item related selectors, pickers, etc.
    - name: rules
      advanced: false
      label: Rule selectors
      description: Scene, Scripts, and Rules selectors, pickers, etc.
    - name: things
      advanced: false
      label: Thing selectors
      description: Thing and Channel related selectors, pickers, etc.
    - name: datetime
      advanced: false
      label: Date and time selectors
      description: Input fields and selectors for date time parameters
    - name: numbers
      advanced: false
      label: Numbers and units
      description: Number parameters with restrictions
    - name: ui
      advanced: false
      label: UI selectors
      description: Selectors for pages and widgets
    - name: input
      advanced: false
      label: Text input and selectors
      description: Input fields, selectors, etc. for text, numbers, locations, etc.
    - name: advanced
      advanced: true
      label: Group for advanced properties
      description: The whole group is hidden until show advanced is checked.
timestamp: Dec 5, 2025, 10:17:40 AM
component: oh-list-card
config:
  footer: footer
  simpleList: true
  title: Set props to test!
slots:
  default:
    - component: oh-label-item
      config:
        title: "----Items----"
    - component: oh-label-item
      config:
        title: "='I-1 Switch or Contact Item: ' + props.switchContact"
    - component: oh-label-item
      config:
        title: "='I-2 Temperature Items: ' + props.numberItem"
    - component: oh-label-item
      config:
        title: "='I-3 Group: ' + props.group"
    - component: oh-label-item
      config:
        title: "='I-4 Group Type: ' + props.groupTypeFilter"
    - component: oh-label-item
      config:
        title: "='I-5 Multiple Items: ' + props.multi"
    - component: oh-label-item
      config:
        title: "='I-6 Items with tags: ' + props.withTags"
    - component: oh-label-item
      config:
        title: "='I-7 Items with type and tags: ' + props.setpoint"
    - component: oh-label-item
      config:
        title: "----Rules----"
    - component: oh-label-item
      config:
        title: "='R-1 Script to Call: ' + props.script"
    - component: oh-label-item
      config:
        title: "='R-2 Inline Script: ' + props.inlineScript"
    - component: oh-label-item
      config:
        title: "----Things----"
    - component: oh-label-item
      config:
        title: "='T-1 Thing: ' + props.thing"
    - component: oh-label-item
      config:
        title: "='T-2 Event Channel: ' + props.channel"
    - component: oh-label-item
      config:
        title: "----Datetime----"
    - component: oh-label-item
      config:
        title: "='D-1 Date Picker: ' + props.date"
    - component: oh-label-item
      config:
        title: "='D-2 Date Time Picker: ' + props.datetime"
    - component: oh-label-item
      config:
        title: "='D-3 Month: ' + props.month"
    - component: oh-label-item
      config:
        title: "='D-4 Day of the Week: ' + props.day"
    - component: oh-label-item
      config:
        title: "='D-5 Time: ' + props.time"
    - component: oh-label-item
      config:
        title: "----Numbers----"
    - component: oh-label-item
      config:
        title: "='N-1 Integer: ' + props.integer"
    - component: oh-label-item
      config:
        title: "='N-2 Bound Integer: ' + props.boundInt"
    - component: oh-label-item
      config:
        title: "='N-3 Decimal: ' + props.decimal"
    - component: oh-label-item
      config:
        title: "='N-4 Temperature: ' + props.temp"
    - component: oh-label-item
      config:
        title: "----UI----"
    - component: oh-label-item
      config:
        title: "='U-1 Page: ' + props.page"
    - component: oh-label-item
      config:
        title: "='U-2 Widget: ' + props.widget"
    - component: oh-label-item
      config:
        title: "----Miscellaneous----"
    - component: oh-label-item
      config:
        title: "='M-1 Arbitrary Text: ' + props.text"
    - component: oh-label-item
      config:
        title: "='M-2 List Selection: ' + props.list"
    - component: oh-label-item
      config:
        title: "='M-3 Boolean Option: ' + props.bool"
    - component: oh-label-item
      config:
        title: "='M-4 Password: ' + props.password"
    - component: oh-label-item
      config:
        title: "='M-5 Color Picker: ' + props.color"
    - component: oh-label-item
      config:
        title: "='M-6 Email: ' + props.email"
    - component: oh-label-item
      config:
        title: "='M-7 Location: ' + props.location"
    - component: oh-label-item
      config:
        title: "='M-8 Cron Expression: ' + props.cron"
    - component: oh-label-item
      config:
        title: "='M-9 Persistence Service: ' + props.persistence"
    - component: oh-label-item
      config:
        title: "='M-10 Regex enforcing IP address formatting: ' + props.regex"
    - component: oh-label-item
      config:
        title: "----Advanced----"
    - component: oh-label-item
      config:
        title: "='A-1 Advanced Properties: ' + props.advanced"
    - component: oh-label-item
      config:
        title: "='A-2 Advanced Properties 1: ' + props.advanced1"
    - component: oh-label-item
      config:
        title: "='A-3 Advanced Properties 2: ' + props.advanced2"

6 Likes

It’s amazing how you find the time and dedication to post examples in addition to providing so many support answers.

Thank you so much for everything you do for openHAB :+1:

6 Likes

Great to publish these examples. It’s maybe worth to also add examples for the extra UI specific parameters added to filterCriteria for the item context (groupType and filterToggle). See Item picker: Implement filtering by type, groupType, tags by mherwege · Pull Request #3487 · openhab/openhab-webui · GitHub

I definitely plan on that, but I’ve not yet updated to get those and I’m hesitant to implement them blindly without testing. As soon as I get that update I will be updating the widget with examples of all the filterCritera stuff.

Now that I’ve done a bit of work with the Number dimension filtering I wonder if it needs to be adjusted. I don’t think it makes sense to show the plain Number Items, particularly when we have the ability to turn off the filter now with the icon.

Consider this example. I have only two Items in my configuration that are of type Group:Number:Dimensionless. However, this is what I see when I set the filter to groupType Number:Dimensionless.

That’s basically all my Groups and because of the semantic model I have a lot of Groups. It really doesn’t narrow the list down in a useful way as a result.

Would it make sense to change that behavior?

I see your point. I am not sure about the best approach though.

The idea was to offer all possible groups for an item with Number:Dimensionless. When an item has a type, you should be able to only use groups with a compatible type or without any type at all. If you only show group items with a compatible dimension, I think you lose the main use case.

If you use type equal to Number:Dimensionless it will get you all items with compatible dimension, so also the groups with a compatible type, but not the groups without type.

One way could be to make both filters work together: if you set a type and a group type, only shows groups with a compatible dimension. Of course the type and group type should be set equal then.

What is the practical use case for only wanting groups with a specific dimension?

It’s more than a specific dimension. It’s the type too. If I want to get a Group of type Group:Switch, I also get the full list of all regular Groups.

  • Trigger a rule when the minimum humidity/temperature/some other temperature changes
  • Skip a rule through a condition if the maximum sensor reading is above a certain point
  • Send ON to all the lights
  • Dim all then lights to a certain level

In the latter two cases, the rule template wouldn’t even work if a regular Group Item were selected instead of a Group:Switch or Group:Dimmer/Color respectively.

While I agree with all that, shouldn’t you just be using a regular type constraint instead of a group type constraint in all these cases? The rule will still work. It will not force you to pick a group, but the rule can work with a regular item as well.

From what I can tell, this extra constraint that it should be a group item is only relevant in rule templates.

what about my suggestion to use both group type and type at the same time?

Why would I use a regular Number:Dimensionless Item plus a rule when I can use a Group:Number:Dimensionless:MIN without a rule?

If I want to be able to control a bunch of lights, how do I manage identifying those lights without listing each one individually in a rule?

That doesn’t make it any less worthy of being supported.

If I understand it correctly then I should be able to narrow down to just Group:Switch (for example) by putting Group:Switch for both the type and groupType, correct? That would work though it’s a bit counterintuitive.

If I were to design it, given the ability to turn off the filterCriteria, I would have made the filter more strict rather than less strict (i.e. not show the plain number Items if a dimension was specified as part of the filter or a type were specified for the Group). But I don’t have strong feelings about that. But as it is right now, it’s pretty much pointless to filter and anything more specific than Group.

A suggestion: it’s a niche feature but you might want to add it anyway.

You can add context: action to a parameterGroup and it will expand to the dynamic parameters relevant to a widget action, see the TIP box at the bottom of Building Pages - Components & Widgets | openHAB (and the expanded explanation).

Then some supported widgets like oh-button have a actionPropsParameterGroup parameter you can set to the name of the parameterGroup and it will perform the action as defined.

This is not what I meat at all. Clearly, using a group is the most logical and common thing to do. But it is not the only way. Someone might have a reason to use a standard item because they get the min from a rule ore a linked channel?

Anyway, if you select the item type to be Number:Dimensionless, it will get you all the items and groups that are compatible (i.e. Number and Number:Dimensionless) and no other groups. Anything it lists will be compatible with the rule.

I agree it is not ideal if you want to force it to being a group, but the question is if this is better or worse then showing all the groups that are compatible, including the ones without a type.

I didn’t say otherwise. But I don’t want to break the main use case I created this for in the first place.

I don’t like to rely too much on turning of the filter. Then I am back to the old situation, where when you want to add an item to a group, it also listed incompatible groups (because they had a type that was not compatible with the item type). If I only list the groups with a compatible type, I will miss most. If I then turn off the filter, I again get all incompatible ones. I think this is a much more common use case, already in configuration in the UI, and I don’t want to break that.

Turning the filter off, to me is something that is relevant for using profiles, where you end up with item types that are different from the channel type and it cannot be predicted in advance. In most cases, I want to avoid it and not open the possibility to have illegal options.

In summary, current behaviour:

  • type = some item type: will list all items and groups with a compatible type, no groups without type.
  • type = group: will list all group items.
  • group type = some item type: will list all groups with a compatible type or without a type. This always leads and type will be ignored if set.

The most logicial way forward for me without introducing extra parameters (and we can debate on the appropriate combinations), use all of the above, but add one extra treatment: if type = group and group type = some item type only list the groups with compatible type, not the groups without type. The inverse is a possibility as well (i.e. in that case it would also list the groups without type when type = group but ignore the ones not compatible with group type = some item type). I don’t have a preference.

I will give that a shot. It seems like it could be useful for UI Widgets for sure.

While I’m not aiming to be 100% comprehensive, I do want to try to include examples for every context at least.

One question though is where is that context handled? It’s not among those listed in ConfigDescriptionParameter (openHAB Core 5.1.0-SNAPSHOT API). Are there other contexts that are handled outside of that class that should be represented?

Sure, and we have the new cancel filter button you added to get to those.

But pretty much everywhere else in MainUI we have design patterns that promote the use of UoM through defaults and such. This would be the one exception where not using UoM becomes the default and encouraged behavior.

For Groups, I say it’s worse because you will always get all your semantic model Groups in the list and there will always be a lot of those. I’d assert there will be more semantic model Groups than any other type of Group, perhaps by as much as an order of magnitude.

If it were not for the semantic model I wouldn’t have a problem. But the semantic model makes the filter unusable. I’m no better off than if I didn’t apply a filterCriteria at all because I still have to scroll through dozens of entries or search.

I think this is where I struggle. If I want to see all my Groups I can use type group. But if I expressed a desire to only see Groups of a given type by using the group type, I still see pretty much all of my Groups because most of my Groups are defining the semantic model and don’t have a type. If I have 40 Group Items, specifying the group type on the filter gives me 38 instead.

This makes the most sense. The root problem is by showing the Groups without a type the filter becomes useless because of all the Groups that define the semantic model. Having a way to exclude those in the filter is needed or else the filter is kind of pointless.

When I wrote standard item, I meant a non-group item. It has nothing to do with UoM.

I actually think I will go the other way around. If group type = some item type restrict it to compatible group types, exclude groups without type, unless type = group is set as well. I have that prepared already.

Looking at the discussion, I think the real question becomes if we should create a filter to exclude semantic group items?

That works for me. In the end I mainly just want to get the list down to something reasonable.

Is that feasible? I wasn’t sure if doing so would be worth the extra call to the REST API to get the list of tags so I didn’t dare ask for it. I don’t think we can hard code the list since users can create their own. But that would be awesome!

While you are in that general area, would it be feasible to filter on semantic tags hierarchically? For example, if I filter on “Room” it gives all the Items with a tag that inherits from Room (e.g. Bathroom, Bedroom, Kitchen, etc). If you already have to pull the semantic tags, that seems like something that should be feasible and it could be useful.

I think it is. The items list in the UI used for filtering has semantics included in its data structure.

I think it would be possible. Looking at the internal item data structure used to feed the items in the item picker, I have something like the example below for each item:

{
	"52": {
		"link": "http://localhost:8080/rest/items/Overloop_Batterijniveau",
		"stateDescription": {
			"pattern": "%.0f %unit%",
			"readOnly": false,
			"options": []
		},
		"metadata": {
			"semantics": {
				"value": "Point_Measurement",
				"config": {
					"relatesTo": "Property_Energy",
					"isPointOf": "Overloop"
				},
				"editable": false
			}
		},
		"editable": true,
		"type": "Number:Dimensionless",
		"name": "Overloop_Batterijniveau",
		"label": "Batterijniveau",
		"category": "Battery",
		"tags": [
			"Measurement",
			"Energy"
		],
		"groupNames": [
			"Overloop"
		]
	}
}

So, metadata.semantics.value tells me what I need without requiring an extra REST call. It is a question about checking the tag you filter on is part of that.

The question now becomes how to best expose this:

  1. A flag to exclude semantic groups.
  2. An extra filter, semantic child, which will only return items that are children of the specific semantic tag. I guess this would only apply for Location, Equipment or Point tags, not for Property tags.

Also, there always is the pick from model option in the item picker. For a number of these use cases, that is a lot easier as it graphically shows where you are picking. The pick from model link does not use the same filter.

Both seem reasonable. I’d call the extra filter something like “semantic” and by default it will search for the given tag(s) and below. That should capture any custom tags a user may create.

I’m not sure that we should exclude Property tags though. I could definitely see wanting to do stuff like limit the list to Setpoint/Temperature but exclude Measurement/Temperature. Without the Property tag I’d get all the setpoints, not just Temperature. This may not be the best example as the tag also matches a dimension, but there isn’t a one-to-one mapping between dimensions and semantic Property tags. One cannot always use the type for filtering like this.

Note that I’m seeing use cases wider than just eliminating the Semantically tagged Groups. Using the semantic model to help filter I think could be quite useful, particularly for stuff like semanticHomeMenu Part 3 - Security [4.0.0.0;5.0.0.0].

I was wondering about that. How do I use the pick from model from a property like this? I could only figure out how to get the list of Items, so I focused on that. But being able to pick from the model would be a really nice option. I’m not sure if there is a need to filter with the model picker. Everything is presented hierarchically so the need to narrow the list down isn’t as important.

I think this is related to the question I had for @ysc above. I think there are contexts that I don’t know about built into MainUI. I don’t know where to look to find them.

It is a standard part of the item picker functionality. Before opening the picker, if you click the icon on the left, you pick from model instead of the classic item picker. It can be disabled in code if it really does not make sense, but is enabled by default.

I never realized it behaved differently based on where you click on the widget. I didn’t realize the icon on the left brought up a different picker.

I’ve attempted to set up an example for a context: action and I’m not getting it to do anything so I might be missing something. I assume the type needs to be TEXT. But it’s rendering as just a plain text filed instead of a selector.

    - context: action
      description: U-3 Widget Action
      label: Choose from among possible MainUI Widget Actions
      name: action
      required: false
      type: TEXT
      groupName: ui

(Yes, I have the label and descriptions swapped, I’ll fix that later).

Implementation of the suggestions is here: [MainUI] Item picker group filter refinement and semantic filter by mherwege · Pull Request #3564 · openhab/openhab-webui · GitHub

2 Likes