Tasmota InfraRed + Android + Chromecast Binding = Convenient Volume Control

When watching videos on Chromecast I regularly see the message “Chromecast is at max volume. Still too quiet? Increase your TV’s volume”. Last night it dawned on me that if I could capture that max volume event, OpenHAB could respond to it and increase the volume of the TV using IR. That way I could just keep pressing the volume up button on my Android phone without needing to open another app. This is my second attempt but here is the solution so far:

Things, technologies and apps used:
Scenes
Tasmotised IR Bridge
OpenHAB
Tasker
AutoInput
Chromecast Binding

One of the scenes I have set up is called “Cinema” and it is triggered by the Chromecast appName channel changing from Backdrop or UNDEF to displaying a specific app (i.e. YouTube, Plex, LocalCast, Netflix, etc). If you want to know how to set up scenes, check out these great solution options.

The IR Bridge:

  • The Tasmota documentation covers how to flash the firmware.
  • Add a Thing to your things file that should look something like this:
    Thing topic irbridge "IR Bridge" @ "Postbox" {
        Channels:
            Type string : status        "Status"               [ stateTopic="tele/ir-bridge/LWT" ]
            Type string : recievedproto "Received Protocol"    [ stateTopic="tele/ir-bridge/RESULT", transformationPattern="JSONPATH:$.IrReceived.Protocol"]
            Type string : recievedbits  "Received Bits"        [ stateTopic="tele/ir-bridge/RESULT", transformationPattern="JSONPATH:$.IrReceived.Bits"]
            Type string : recieveddata  "Received Data"        [ stateTopic="tele/ir-bridge/RESULT", transformationPattern="JSONPATH:$.IrReceived.Data"]
            Type string : recievedhash  "Received Hash"        [ stateTopic="tele/ir-bridge/RESULT", transformationPattern="JSONPATH:$.IrReceived.Hash"]
            Type string : senddata      "Send"                 [ stateTopic="tele/ir-bridge/RESULT", commandTopic="cmnd/ir-bridge/IRsend"]
            Type number : rssi          "WiFi Signal Strength" [ stateTopic="tele/ir-bridge/STATE", transformationPattern="JSONPATH:$.Wifi.RSSI"]
    }
    
  • Then add lines to an items file that look something like these:
    Group  IR_Bridge                   "IR Bridge"           <ir_bridge>    (LivingRoom, InfraRed)
    String IR_Bridge_Status            "Status: [%s]"        <contactable>  (IR_Bridge) { channel="mqtt:topic:bridge:irbridge:status" }
    String IR_Bridge_Received_Protocol "Protocol: [%s]"      <none>         (IR_Bridge) { channel="mqtt:topic:bridge:irbridge:recievedproto" }
    String IR_Bridge_Received_Bits     "Bits: [%s]"          <none>         (IR_Bridge) { channel="mqtt:topic:bridge:irbridge:recievedbits" }
    String IR_Bridge_Received_Data     "Data: [%s]"          <none>         (IR_Bridge) { channel="mqtt:topic:bridge:irbridge:recieveddata" }
    String IR_Bridge_Received_Hash     "Hash: [%s]"          <none>         (IR_Bridge) { channel="mqtt:topic:bridge:irbridge:recievedhash" }
    String IR_Bridge_Send_Data         "Send: [%s]"          <none>         (IR_Bridge) { channel="mqtt:topic:bridge:irbridge:senddata" }
    Number IR_Bridge_RSSI              "WiFi Signal [%d %%]" <wifi>         (IR_Bridge) { channel="mqtt:topic:bridge:irbridge:rssi" }
    

The Chromecast setup is very straightforward:

  1. Install the Binding
  2. Add the Chromecast Thing using the PaperUI > Inbox
  3. Get the channels from PaperUI > Configuration > Things > Chromecast
  4. Create an items file with a String item and a Dimmer item in it that subscribe to the Chromecast appName and volume channels. i.e.:
    String ChromecastAppName "App Name [%s]" <text>        (ChromecastGroup) {channel="chromecast:chromecast:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:appName"}
    Dimmer ChromecastVolume  "Volume"        <soundvolume> (ChromecastGroup) {channel="chromecast:chromecast:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:volume"}
    

The Android setup:

  • Create items to represent the volume buttons on your phone:

    Group  Phone_Volume_Buttons     "Volume Buttons" <soundvolume>
    String Phone_Volume_Up_Button   "Button [%s]"    <soundvolume> (Phone_Volume_Buttons)
    String Phone_Volume_Down_Button "Button [%s]"    <soundvolume> (Phone_Volume_Buttons)
    
  • Create a Tasker variable:

    • %HomeWiFiSSID

    Set the value to - you guessed it - the SSID of your home WiFi.

  • Now set up a Tasker profile. Mine is called “Volume Up Button Pressed”. You’ll also need to have AutoInput installed. There are currently three context triggers:

    1. Event > Plugin > AutoInput > Key > Configuration > Edit > Keys (Volume Up) & Key Action (Key Down)
    2. State > Phone > Call > Type (Any) & Invert (checked)
    3. State > Net > WiFi Connected > SSID (%HomeWiFiSSID)

    These context triggers capture the volume up button press if I’m not on a call and am connected to my home WiFi.

  • Add a task to the profile:

    • Tell OpenHAB Volume Up Button Pressed:
      Net > Browse URL > URL (openhab://?i=Phone_Volume_Up_Button&s=%VOLM)

The rule setup:

  • Chromecast controlling a Scene:

    val String filename = "chromecast.rules"
    
    rule "Change Scene According to Chromecast Activity"
    when
        Item ChromecastAppName changed
    then
        logInfo(filename, "Change Scene According to Chromecast Activity: " + triggeringItem.state)
    
        if (triggeringItem.state == "YouTube" || triggeringItem.state == "Plex" || triggeringItem.state == "LocalCast" || triggeringItem.state == "Netflix") {
            CinemaScene.sendCommand(ON)
        }
        else {
            CinemaScene.sendCommand(OFF)
        }
    end
    
  • Phone button controlling IR Bridge:
    You can look up some known IR codes in the Tasmota documentation. The code shown in the rule here is for volume up on an LG TV. There is more detailed information about how to send and receive IR too. If you need to send IR codes that use an unknown protocol, there are ways around that but I won’t be expanding on that here.

    rule "Phone volume button pressed"
    when
        Member of Phone_Volume_Buttons received command
    then
        logInfo(filename, "Phone volume button pressed: " + triggeringItem.name + ":" + receivedCommand)
    
        if (CinemaScene.state == ON) {
            switch (triggeringItem) {
                case Phone_Volume_Up_Button: {
                    if (ChromecastVolume.state == 100) {
                        IRBridgeSendData.sendCommand("{\"Protocol\":\"NEC\",\"Bits\":32,\"Data\":\"0x20DF40BF\"}")
                    }
                }
                case Phone_Volume_Down_Button: {
                    // Do something else...
                }
            }
        }
    end
    

That’s it. OpenHAB now knows if I am watching something on the Chromecast and if the Chromecast volume reaches the maximum, I can keep mashing the volume button on my phone to increase the TV volume instead. Nifty. :sunglasses:

Anyone got suggestions/improvements?

1 Like

Updated the post to reflect some changes made after living with the first revision. It had some flaws. The new methodology has been far more reliable.