Shelly Button1 or "How to get a MQTT switch with more than two states?"

Hi everybody,

I recently got myself a bunch of Shelly Button1 to control wallplugs without the need to use an app for that. The device itself is lovely but the integration in OH2 could be better. I’m integrating them (like most of my devices these days) using MQTT which is a fairly straight forward setup and the same as for other existing Shelly devices (power on, connect to WLAN, configure MQTT broker, done). Once set up, the Button1 knows four different input signals (event_cnt will increase if the same signal is being sent multiple times).

  1. Single short click: MQTT message {“event”:“S”,“event_cnt”:1})
  2. Double short click: MQTT message {“event”:“SS”,“event_cnt”:1})
  3. Triple short click: MQTT message {“event”:“SSS”,“event_cnt”:1})
  4. Long click: MQTT message {“event”:“L”,“event_cnt”:1})

To got the buttons working in my OH instance, I first set them up the following way (replacing the MAC with XXXXXXXXXXXX here):

// ===== mqtt.things =====
Bridge mqtt:broker:mqtt-broker [ host="10.0.0.1", secure=false, username="myUser", password="myPassword" , clientID="openhab-client" ]
  Thing topic shellybutton1-XXXXXXXXXXXX "ShellyButton1 XXXXXXXXXXXX" {
    Channels:
      Type switch : switch        "Switch"            [ stateTopic="shellies/shellybutton1-XXXXXXXXXXXX/input_event/0", transformationPattern="JSONPATH:$.event", postCommand="true", on="S", off="SS"]
      Type number : battery       "Battery"           [ stateTopic="shellies/shellybutton1-XXXXXXXXXXXX/sensor/battery" ]
  }
}

// ===== button.items =====
Switch        ShellyButton1_XXXXXXXXXXXX_Switch   "Shelly Button1 XXXXXXXXXXXX [%s]"       { channel="mqtt:topic:twilight-mqtt:shellybutton1-XXXXXXXXXXXX:switch" }
Number        ShellyButton1_XXXXXXXXXXXX_Battery  "Shelly Button1 XXXXXXXXXXXX [%d]"       { channel="mqtt:topic:twilight-mqtt:shellybutton1-XXXXXXXXXXXX:battery" }

// ===== default.sitemap ======
Frame label="Buttons" {
  Default item=ShellyButton1_XXXXXXXXXXXX_Switch
  Default item=ShellyButton1_XXXXXXXXXXXX_Battery
}

// ===== button.rules =====
rule "ShellyButton1_XXXXXXXXXXXX_Switch"
when
  Item ShellyButton1_XXXXXXXXXXXX_Switch received command
then
  Lighting_Switch.sendCommand(receivedCommand)
  sendTelegram("openHAB", "Automatic wallplugs changed to" + receivedCommand)
end  

With that setup, I was able to trigger something like one or more wallplugs (single click = ON, double click = OFF) or send me a telegram when battery of one of the Button1’s was getting low. While this was neat, I was not able to use this approach to implement the other input signals (“SSS” and “L”). On “human error”, I’m seeing something like this in the log:

2020-08-13 13:05:00.329 [WARN ] [ab.binding.mqtt.generic.ChannelState] - Command 'SSS' not supported by type 'OnOffValue': No enum constant org.eclipse.smarthome.core.library.types.OnOffType.SSS

It is clear that for a binary switch something besides On or Off does not make much sense so I worked around this by changing the channel type for Switch to string and updated the items accordingly. Next I changed the rules to react on different input signals. I could’ve done this in multiple rules that each react on a different input but did not want to scatter logic too much:

// ===== mqtt.things =====
Bridge mqtt:broker:mqtt-broker [ host="10.0.0.1", secure=false, username="myUser", password="myPassword" , clientID="openhab-client" ]
  Thing topic shellybutton1-XXXXXXXXXXXX "Shellybutton1 XXXXXXXXXXXX" {
    Channels:
      Type string: switch        "Switch"            [ stateTopic="shellies/shellybutton1-XXXXXXXXXXXX/input_event/0", transformationPattern="JSONPATH:$.event", postCommand="true"]
      Type number : battery       "Battery"           [ stateTopic="shellies/shellybutton1-XXXXXXXXXXXX/sensor/battery" ]
  }
}

// ===== button.items =====
String        ShellyButton1_XXXXXXXXXXXX_Switch   "Shelly Button1 XXXXXXXXXXXX"            { channel="mqtt:topic:twilight-mqtt:shellybutton1-XXXXXXXXXXXX:switch" }
Number        ShellyButton1_XXXXXXXXXXXX_Battery  "Shelly Button1 XXXXXXXXXXXX [%d]"       { channel="mqtt:topic:twilight-mqtt:shellybutton1-XXXXXXXXXXXX:battery" }

 // ===== default.sitemap =====
Frame label="Buttons" {
  Switch item=ShellyButton1_XXXXXXXXXXXX_Switch mappings=["S"="S","SS"="2*S","SSS"="3*S","L"="L"]
  Default item=ShellyButton1_XXXXXXXXXXXX_Battery
}

// ===== button.rules =====
rule "ShellyButton1_XXXXXXXXXXXX_Switch"
when
  Item ShellyButton1_XXXXXXXXXXXX_Switch received command
then
  if(receivedCommand == "S") {
    Lighting_Switch.sendCommand(ON)
    sendTelegram("openHAB", "Automatic wallplugs changed to ON")
  } else if(receivedCommand == "SS") {
    Lighting_Switch.sendCommand(OFF)
    sendTelegram("openHAB", "Automatic wallplugs changed to OFF")
  } else {
    sendTelegram("openHAB", "Unbound input signal: " + receivedCommand)
  }
end

This now works for all possible inputs and also shows the state in the sitemap but I would consider it a little hacky and I really dislike the if in my rules files. Adding additional states to the switch channel would’ve been great (e.g. ‘on=“S”, off=“SS”, custom1=“SSS”, custom2=“L”’) but this seems to be unsupported. So my question is: Is the above setup the right way to go or is there a better solution that I did not find so far?

BR Tilman

I’ve done pretty much exactly as you have on a similar button. The only thing I can suggest on the IF statements, is that you could use a SWITCH/CASE format instead (last example at this link)?

Better solution I would suggest is to wait until the official Shelly binding fully supports the Shelly Button, or try the DEV build, which already includes the button.

1 Like

@hmerk: Will this allow full local control or does it rely on the shelly cloud? Actually, I do like the way of MQTT integration. I have quite some different sensors and actors running on that broker and love the ease of that technology.

Edit: I just checked the docs of that plugin and it seems it will not work for me. All my IoT devices are in an isolated wireless and virtual LAN. So probably the mDNS auto discovery will not work at all for them.

Edit.2: Ah, n/m - read further and found out that I could configure IPs for the shelly devices. So this could indeed do the trick.

@hafniumzinc, thanks! Reading your thread it feels quite the same indeed. The switch would be something I could implement, yes. Another idea would be to implement individual rules like

  • Item ShellyButton1_XXXXXXXXXXXX_Switch received command "S"
  • Item ShellyButton1_XXXXXXXXXXXX_Switch received command "SS"
  • Item ShellyButton1_XXXXXXXXXXXX_Switch received command "SSS"
  • Item ShellyButton1_XXXXXXXXXXXX_Switch received command "L".

but that brings in more code.

It is fully local, no cloud connection needed. Other benefit is autodiscovery of Shelly devices attached to your network.