Profile to cycle through a list of values upon event trigger

All,

After a smooth upgrade to OpenHAB 4.2 I just discovered the Basic Profiles transformations bundle. It seems that I can get rid of several one-line rules, e.g. just toggling a switch item when a button was pressed.

I have some use cases though where I have a list of fixed values for a (say) String item and upon every press of a button (triggers an event) I assign the next value from the list to that String item.
At the moment I implemented this as a rule, like this:

switch (receivedEvent) {
  ...
  case "3001": {
    // Long press "Light" button
    switch (vSetLightConfig_Kitchen.state.toString) {
        case "NORMAL": { vSetLightConfig_Kitchen.sendCommand("REDUCED") }
        case "REDUCED": { vSetLightConfig_Kitchen.sendCommand("EVENING") }
        case "EVENING": { vSetLightConfig_Kitchen.sendCommand("NIGHT") }
        case "NIGHT": { vSetLightConfig_Kitchen.sendCommand("NORMAL") }
        default:  { vSetLightConfig_Kitchen.sendCommand("NORMAL") }
      }
  }
  ...
}

I wonder if it would be possible (and useful) to have this kind of logic covered by a (new) transformation profile. (Using a MAP transformation would certainly be another way to get rid of the coded rule…)

Thanks,
Dietmar

Map transformation would probably be the most straight forward.

Beyond that you could implement your rule as a Script transformation but you aren’t really saving anything. Same amount of code.Same amount of resources. It’s just somewhere else, not in rules.

Thanks for your feedback!

Yes, MAP transformation is better than hard coded switch statement, but still it can be triggered only from a rule/script.

My original question was triggered (sic!) by this statement in Transformations / Profiles | openHAB

Trigger profiles are powerful means to implement some immediate, straight-forward logic without the need to write any rules.

Never mind…

Regards,
Dietmar

Says who? You can use the Map transformation in a transform profile. If the binding supports it, you can use it in the Channel config.

Those are developer’s docs, not end user docs. But the transform profile is a trigger profile. And the transform profile can use any installed transformation add-on including the Map transform.

I’ve just opened a PR to support creating a trigger profile in JRuby. (State profiles are already supported).

Once it’s merged, you can create your own trigger profile and use it like this:

String vSetLightConfig_Kitchen {channel="mqtt:topic:test:test" [ profile="ruby:trigger_button_cycle", event="3001", values="NORMAL,REDUCED,EVENING,NIGHT" ], channel="otherchannel...."}

To create the profile in JRuby:

# frozen_string_literal: true

profile(:trigger_button_cycle) do |event, trigger:, item:, configuration:|
  if event == :trigger_from_handler && (configuration["event"].nil? || configuration["event"] == trigger)
    next unless (values = configuration["values"])

    values = values.split(",").map(&:strip).compact
    current = values.index(item.state.to_s) || -1
    new_value = values[current + 1] || values.first

    item.command new_value
  end
end

Essentially, this lets you create whatever profile you want to do whatever you wish, without needing to wait for someone else to come along and create a profile / addon for you. You can whip one up quickly using a jruby script.

PS The above ruby profile is only usable in file-based .items file. If you want to use it on UI based items, simply add a label and config description, e.g.:

# frozen_string_literal: true

config_description = config_description do
  parameter :event, :text, label: "Trigger Event",
                           description: "React when this event occurs. When not supplied, react to any event."
  parameter :values, :text, label: "Values", description: "A comma separated list of values to cycle through"
end

profile(:trigger_button_cycler,
        type: :trigger,
        label: "Cycle through states on trigger",
        config_description:) do |event, trigger:, item:, configuration:|
  if event == :trigger_from_handler && (configuration["event"].nil? || configuration["event"] == trigger)
    next unless (values = configuration["values"])

    values = values.split(",").map(&:strip).compact
    current = values.index(item.state.to_s) || -1
    new_value = values[current + 1] || values.first

    item.command new_value
  end
end

PR merged and released

1 Like

Yor are right, and my statement about “can be triggered only from a rule/script” was certainly misleading.

What I meant to say: Using MainUI I was not able to link an event channel to a string item using a MAP profile, the only profile choice is “Trigger Event String”.

Therefore my conclusion was that I still need a rule to determine the new item state with a MAP transformation.

Awesome!