Push Button / Momentary Switch for Infrared (IR) control

I have a fan with an Infrared (IR) remote control.

Therefore this fan can be controlled from a home automation system with an IR Bridge / IR Blaster. I am using a generic wifi IR bridge (e.g. YTF IR bridge) with Tasmota for MQTT control of the IR bridge.

Tasmota uses JSON with lots of " and , which poses some difficulties.
Example MQTT command to get Tasmota IR bridge to send a command: {“Protocol”:“NEC”,“Bits”:32,“Data”:“0x5D0FC23D”,“DataLSB”:“0xBAF043BC”,“Repeat”:0}

My fan has:
IR code for fan on/off (same code, just toggles)
IR code for increase fan speed
IR code for decrease fan speed
IR code for light on/off (same code, just toggles)
IR code for increase light brightness
IR code for decrease light brightness
and some others I don’t need / use

There is no feedback from the fan, communication is one way. This means the usual Openhab toggle switch with a known state is not appropriate. When I tried a toggle switch, it had unsatisfactory behaviour, with turning it on sending a command, but then turning it off would do nothing. I.e. 4 presses were required to go from off to on and then back to off (instead of 2 presses, On and off).

Instead a push button / momentary switch is appropriate. Openhab does not have a default / simple way of doing this (which is frustrating and there are multiple other threads of people wanting a momentary button.

My solution:
OpenHab 3.4
MQTT binding installed and MQTT broker setup
Implemented via the MainUI interface - I want to be able to easily see and manage all aspects of my automation through the openhab GUI, rather than having to dig through individual text files via a file editor.

How it works:
Label or List items on your page send a string (text) command to a string item. When that string item receives a command a rule is triggered. That rule uses a javascript script to check what the command string is, and then sends the appropriate JSON via MQTT.

  1. Add a string item (Creating a Thing or a Channel is not necessary for this method)
    Items → + → Create New Item
    Give it a sensible name (mine is “ir_study_string”)
    Leave Type as String

  2. Add buttons to your page
    Settings → Pages → “yourpage” → Add a widget.
    I used the following widgets:

component: oh-label-card
config:
  action: command
  actionItem: ir_study_string
  actionCommand: fanpower
  label: Study Fan

component: oh-list-item
config:
  title: Fan Up
  action: command
  actionItem: ir_study_string
  actionCommand: fanup
  icon: f7:arrow_up
component: oh-list-item
config:
  title: Fan Down
  action: command
  actionItem: ir_study_string
  actionCommand: fandown
  icon: f7:arrow_down
component: oh-label-card
config:
  action: command
  actionItem: ir_study_string
  actionCommand: lightpower
  label: Study Light
component: oh-list-item
config:
  title: Light Up
  action: command
  actionItem: ir_study_string
  actionCommand: lightup
  icon: f7:arrow_up
component: oh-list-item
config:
  title: Light Down
  action: command
  actionItem: ir_study_string
  actionCommand: lightdown
  icon: f7:arrow_down

The “actionCommand” text is important. We need these values to put in our script.
I used: fanpower, fanup, fandown, lightpower, lightup, lightdown

  1. INSTALL Javascript to get ECMAScript 262 Edition 11 option
    Settings → Automation → Javascript Scripting (square yellow icon with black JS text)
    (There is already ECMAScript 262 Edition 5.1 without installing this, but I could not get any code to work on the Edition 5.1 option, and eventually after ages of bashing my head on the table found that installing the JavaScript Scripting option and using Edition 11 worked.

  2. Create the Rule
    Settings → Rules → +
    Give it a sensible Unique ID and Name
    When:

  • Item Event → Select your item (tick SHOW NON-SEMANTIC at the bottom) → Pick
    “received a command” (leave command empty/any)
    Then:
  • Run Script
  • ECMAScript ***ECMAScript-2021 / ECMAScript 262 Edition 11 option (I could not get any code to work on the Edition 5.1 option)
    Put in the following code (which has console logging for debugging, you can remove all the console.log lines if working fine):
if (event.itemCommand.toString() == "lightpower") {
  console.log("LIGHT POWER", items.getItem("ir_study_string").state); //logging
  
  //light on/off
  actions.get("mqtt", "mqtt:broker:mqtt").publishMQTT("ir/IRBlaster/cmnd/IRSend", "{\"Protocol\":\"NEC\",\"Bits\":32,\"Data\":\"0x5D0FC23D\",\"DataLSB\":\"0xBAF043BC\",\"Repeat\":0\}", true);
}

if (event.itemCommand.toString() == "lightup") {
  console.log("LIGHT UP", items.getItem("ir_study_string").state); //logging
  
  //light on/off
  actions.get("mqtt", "mqtt:broker:mqtt").publishMQTT("ir/IRBlaster/cmnd/IRSend", "{\"Protocol\":\"NEC\",\"Bits\":32,\"Data\":\"0x5D0F42BD\",\"DataLSB\":\"0xBAF042BD\",\"Repeat\":0}", true);
}

if (event.itemCommand.toString() == "lightdown") {
  console.log("LIGHT DOWN", items.getItem("ir_study_string").state); //logging
 
  //light on/off
  actions.get("mqtt", "mqtt:broker:mqtt").publishMQTT("ir/IRBlaster/cmnd/IRSend", "{\"Protocol\":\"NEC\",\"Bits\":32,\"Data\":\"0x5D0F8A75\",\"DataLSB\":\"0xBAF051AE\",\"Repeat\":0}", true);
}


if (event.itemCommand.toString() == "fanpower") {  
  console.log("FAN POWER", items.getItem("ir_study_string").state); //logging
  
  //fan on/off
  actions.get("mqtt", "mqtt:broker:mqtt").publishMQTT("ir/IRBlaster/cmnd/IRSend", "{\"Protocol\":\"NEC\",\"Bits\":32,\"Data\":\"0x5D0FC03F\",\"DataLSB\":\"0xBAF003FC\",\"Repeat\":0}", true);

}

if (event.itemCommand.toString() == "fanup") {  
  console.log("FAN UP", items.getItem("ir_study_string").state); //logging
  
  //fan on/off
  actions.get("mqtt", "mqtt:broker:mqtt").publishMQTT("ir/IRBlaster/cmnd/IRSend", "{\"Protocol\":\"NEC\",\"Bits\":32,\"Data\":\"0x5D0F0AF5\",\"DataLSB\":\"0xBAF050AF\",\"Repeat\":0}", true);

}

if (event.itemCommand.toString() == "fandown") {  
  console.log("FAN DOWN", items.getItem("ir_study_string").state);  //logging
  
  //fan on/off
  actions.get("mqtt", "mqtt:broker:mqtt").publishMQTT("ir/IRBlaster/cmnd/IRSend", "{\"Protocol\":\"NEC\",\"Bits\":32,\"Data\":\"0x5D0F827D\",\"DataLSB\":\"0xBAF041BE\",\"Repeat\":0}", true);

}

Notes on the script:
" (double quotes) in the JSON must be escaped with a , otherwise the " is seen as the end of the value (when it is part of it)
The JSON that Tasmota expects is:
{"Protocol":"NEC","Bits":32,"Data":"0x5D0FC23D","DataLSB":"0xBAF043BC","Repeat":0}
The escaped version is:
{\"Protocol\":\"NEC\",\"Bits\":32,\"Data\":\"0x5D0FC23D\",\"DataLSB\":\"0xBAF043BC\",\"Repeat\":0}

event.itemCommand.toString() - this looks at the value of the command that triggered the rule (e.g. “fanpower”).
(I know nothing about javascript, however the openhab manual specifies that you should use .toString() when comparing to avoid unexpected behaviour).
Then the if matches for that command e.g. “fanpower” and then uses .publishMQTT to send the appropriate MQTT command / JSON

***The code would be different for rules created in a file. This code is for a rule created in MainUI.

5. Your page should now have items that behave as momentary buttons and allow you to use MQTT to control an IR bridge.

2 Likes