[RELEASE] Shelly Device Drivers (NO MQTT NEEDED)

Hey everyone! I've been working on some device drivers for Shelly devices that do not require running a server with an MQTT broker to function. They also do not use any sort of polling for state changes, everything is instant response.

You can find the drivers on HPM, just search for "shelly":

Or install them manually from the GitHub repo if you prefer.

These drivers do not (and will not) entirely replace the web UI for device administration. If you want to change some of the more obscure settings, you'll want to use the web UI for the device or the Shelly mobile app. Some of the more important settings will included in Hubitat, for things like setting motion sensitivity, auto-on/auto-off timers, etc. The Shelly Plug US driver has its settings available in HE already. The Motion 2 will be added soon.

Current list of drivers I've added to HPM:

Shelly Plug US
Shelly Button 1
Shelly H&T (gen2 and gen3)
Shelly Motion 2
Shelly H&T (gen 1)
Shelly BLE Gateway
Shelly Gas (WIP, needs valve activator control added)
Shelly Motion Blu
Shelly Door/Window Blu
Shelly Button 1 Blu

Yep, that's right, there's support for Shelly's line of Bluetooth devices. You need at least 1 device with Bluetooth Gateway capability. The Shelly BLE Gateway obviously has BLE support. As does the Plug US. There's an option in the config for BLE capable devices for "Enable Bluetooth Gateway for Hubitat" which will create a Shelly Script on the device that relays bluetooth events to Hubitat.

The second piece of this is installing the 'Shelly Bluetooth Helper App' included in HPM for these drivers. This app is mandatory for Bluetooth devices to work as it's what relays the events between the gateway(s) and the Blu device(s) in Hubitat. This app will write warning level messages in the log that includes the MAC address of the Bluetooth device when it "hears" one that doesn't have a corresponding device in HE. Alternatively, you can find the MAC address of your Blu devices on the Shelly mobile app.

The driver for Shelly Plug US uses websocket to get instant updates on device state, such as when you manually turn it on/off via the button on the plug. It supports power monitoring reports, also over websocket, so updates are instant. These plugs are 'chatty' over websocket, sending around 10,000 events per day, but I've heavily optimized the driver. On a Hubitat C7 it used 0.028% of the total CPU to process just shy of 10,000 events in the last 24 hours I tested it. It's absurdly efficient, so it shouldn't cause any CPU issues even if you have bunch of them.

The driver for the Button 1, H&T, and Motion 2 all use webhook "Actions" to inform Hubitat of state changes.

On the H&T, since it's Gen 2+, the webhook actions created by the HE driver during configuration are "named". The device driver creates webhooks with unique names, so unless you happen to have a webhook named "hubitat.humidity.change" it won't conflict with anything you might have set up.

On the Motion 2 and Button 1, these are Gen 1 devices, and they don't have "named" webhooks. Using these drivers will overwrite any webhook actions you may have set up. The driver creates webhooks at "index=0" for these devices and that will overwrite anything that might be set up. If you're not currently using custom actions, you have nothing to be concerned with here.

If you're using custom webhooks on these devices you have a few options. One, you can find an MQTT driver for them and run an MQTT server. I'm personally a fan of not running and maintaining an MQTT server, so I definitely wouldn't recommend that option. A second option, which I would suggest, is letting these device drivers overwrite whatever action you have set up, then using Rule Machine to perform the webhook action you previously had setup on the device. So if you had a webhook setup on your Motion 2 for " MOTION DETECTED", you'd instead set up a Rule in Rule Machine with "trigger: motion started" and an action of "Send HTTP GET". This way the Motion 2 can HTTP GET to Hubitat and inform it of "motion_on" and then you can have Hubitat relay that on via another HTTP GET using Rule Machine.

Setting the drivers up is pretty simple. You only need to provide the IP address of the device, and username/password if using authentication on gen 1 devices, or password on Gen 2 (they don't allow setting a username). Authentication is supported on all drivers. When clicking on "Save Preferences" after adding the IP Address (and auth information, if applicable) you need to ensure any battery powered devices are 'awake'. So in the case of the Motion 2, it's always awake. The Button 1 needs to be plugged in via micro USB. The H&T devices have a button in the battery compartment that needs pressed.

If the device is awake, "Save Preferences" should then connect to the device and set the required webhooks up to have it connected to Hubitat directly. No MQTT needed. You can verify things are setup on the device itself if you want. For example, on the Motion 2, you'll see your Hubitat IP address under some of the Actions like so:

Summary

I'll be adding many more drivers here in the next few weeks. None of them will use or need MQTT.

12 Likes

Great idea using a websocket to receive e.g. power changes without polling! :+1:

As there is no Action URL for "power value changed", my own (quick hacked) Shelly Plug driver misuses over power and under power actions to simulate such an event - at the cost of setting the limits after every refresh... :man_shrugging:

BTW: Why are you still using the action URLs at all? :thinking:

Because websocket only works for mains powered devices. Can't have Hubitat maintaining a websocket connection to the Shelly H&T or Button 1 since they're asleep 99.9% of the time.

The Plug US driver I've added to HPM is (almost) purely websocket. It uses HTTP requests for commanding the switch on and off as those will work even if the websocket connection had died for some reason. It's just more reliable. There's some code in place that does a solid job of maintaining a live websocket connection, but really that logic needs to be handed at the Hubitat system level (it's currently not). Since the websocket connection is not quite 100% reliable, I only use it for power monitoring updates. Using HTTP requests for on/off ensures the most important thing that a plug can do, turning on and off, happens 100% of the time.

But the Plug US driver doesn't use any of the Action URLs like the other drivers I've added do. That's really only needed for battery powered devices, or older Gen 1 stuff that doesn't have inbound websocket support.

2 Likes

I swear...is sleep a thing?

Some of you guys are so bloomin creative & prolific software writers that you should be on contract with Hubitat.

2 Likes

Ah yes, right!
I hadn't thought of that as I use only main powered Shellys (and battery devices from other Zigbee brands).

Thanx a lot for the detailed explanation! :+1:

Updated on HPM for version 1.1.

Added support for:

Shelly H&T (gen 1)
Shelly BLE Gateway
Shelly Gas (WIP, needs valve activator control added)
Shelly Motion Blu
Shelly Door/Window Blu
Shelly Button 1 Blu

These drivers now support the various Bluetooth Shelly devices! See first post for more info on setting the Blu devices up on HE.

2 Likes

These are great - thanks. Im going to use these as part of a 'very long' learning curve to write my own Shelly Drivers.
Do you have a driver for 'Shelly Dimmer 2' and 'Shelly i4' ? I'm struggling to get either of these devices to work properly.
Fingers Crossed...

Not yet, no. But I'll be writing a full line of drivers for everything Shelly has. There's presently some 'serviceable but not ideal' drivers for most Shelly devices, as a large portion of them rely on MQTT. Since Hubitat doesn't have an MQTT broker this means you need to run an MQTT broker, and that's far from ideal.

All of the drivers I'm working on use a combination of websocket and webhooks to function. No MQTT needed. Gen 1 stuff is 100% webhook since they don't have websocket, and gen 2+ stuff uses websocket if available (ie, if it's a mains powered device), otherwise they use webhooks as well.

Feel free to look at the updates I'm making on the ShellyUSA repository, but keep in mind that this is under heavy development. For instance, I'm currently working on adding support in my library for 'input' on Gen2+ stuff. That's going to be the bulk of what's needed for the i4. Last night I did a refactor of my library to have it dynamically support multiple 'switch' entities, creating child devices if there's 2+ switches, and just using the switch capability of the parent device otherwise.

This was needed to properly support the Uni Plus, as previously I'd only written a driver for the Plug US which has only the one switch component. I'll be adding input today using the same dynamic setup as I did for switch. But if you look at what's up on GitHub right now there's a complete lack of anything related to 'input'.

Most of the code lives in my library, and I'll be doing a pretty heavy refactor and cleanup on everything once I have a few more drivers written. When done there'll be 50ish lines of code on each device driver, mostly just the 'metadata' stuff, then the library will auto configure and dynamically set up the rest. But really, there shouldn't be a need for anyone to have to write their own Shelly drivers. I'll have drivers for all devices here in the near future.

1 Like

Daniel, you are a hero... I'm really looking forward to taking on all your drivers as they come online.

I will still play with my own versions because I want to learn how its done, but I'll use yours in 'production' as it were.

If you need any help testing, I'd be happy to help.

Hi @daniel.winks

I have just tried this on my new Shelly H&T Gen3, and so far it's behaving nicely.
This is so much easier than faffing about with a separate MQTT server, thank you very much!

1 Like

Glad to hear it. The whole line of drivers I'm working on are going to be the same no-MQTT design. It's not terribly difficult getting the devices to 'auto-configure' a couple webhooks to have them just send Hubitat the necessary data rather than sending it to an MQTT broker. Or use websocket for things that are AC powered.

My home is 100% run from a single Hubitat C8-Pro. I like things simple, and that means not running a server, MQTT broker, Home Assistant, etc. My 'Sonos Advanced' app was created so I could finally ditch HA and have all the functionality I needed right in Hubitat. Now I'm working on Shelly drivers too, with the same "doesn't need anything other than a Hubitat hub" model for them.

3 Likes

Hi @daniel.winks, are you planning on adding support for the gen1 UNI ?

Yep! Right now I'm doing a lot of work on the library code, which will mean each driver will be a few lines of metadata, maybe a few lines of device-specific things, and a reference to the library. Lately I've been working on getting it to auto-detect what settings are available for a device and populate them on child-devices.

It's spring here, which means I've got a lot to do off the computer too, like planting my garden, cleaning gutters, etc, so I don't have a ton of time for programming. But it should be soon.

2 Likes

Same here, take your time, just wanted to see if I keep working on this older UNI or just buy a new Plus version to replace the few older ones I have. Thanks for your work.

I've got a Gen 1 Uni here waiting for my driver library to be complete so I can get it working for my own use too. 100% for sure, there's Gen 1 (and Gen 2) Uni support planned. Just need to work in some coding time on a fairly busy schedule for the next few weeks here.

2 Likes

@daniel.winks

I am going to try Shelly BLE Buttons with Shelly BLE Gateway (Shelly i4 as a BLE Gateway). I already downloaded two drivers (BLE Button and BLE Gateway Helpers) but I am a bit confused what exactly should I install? Is it two Separate Devices with appropriate user diver attached or something else?

UPDATE

I tried to install BLE Gateway. As soon as I assigned its IP Address the log became fast populated with gazillions of error messages:

dev:27462024-04-15 04:42:47.453 PMerrorjava.lang.ArrayIndexOutOfBoundsException: Index 1 out of bounds for length 1 on line 87 (method parse)
dev:27462024-04-15 04:42:47.231 PMerrorjava.lang.ArrayIndexOutOfBoundsException: Index 1 out of bounds for length 1 on line 87 (method parse)
dev:27462024-04-15 04:42:46.962 PMerrorjava.lang.ArrayIndexOutOfBoundsException: Index 1 out of bounds for length 1 on line 87 (method parse)
dev:27462024-04-15 04:42:46.680 PMerrorjava.lang.ArrayIndexOutOfBoundsException: Index 1 out of bounds for length 1 on line 87 (method parse)
dev:27462024-04-15 04:42:46.395 PMerrorjava.lang.ArrayIndexOutOfBoundsException: Index 1 out of bounds for length 1 on line 87 (method parse)
dev:27462024-04-15 04:42:45.916 PMerrororg.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object '[2, [[79:6a:71:c6:8b:1e, -66, AgEaG/9MAAwOAFfPp0/bdNB6mBXEUFYQBkAdV353aA==, ], [7e:a5:b3:9f:21:2a, -71, AgEaAgoMC/9MABAGTx25Zf5I, ], [74:05:81:b0:61:38, -78, AgECAwKv/gYJTlVNWlE=, ]]]' with class 'java.util.ArrayList' to class 'java.util.LinkedHashMap' due to: groovy.lang.GroovyRuntimeException: Could not find matching constructor for: java.util.LinkedHashMap(java.lang.Integer, java.util.ArrayList) on line 641 (method parse)
dev:27462024-04-15 04:42:45.734 PMerrororg.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object '[2, [[60:a4:23:8f:de:1a, -74, AgEGEQfVXdFdj9cuqYpHiup/lnbi, ], [d6:35:86:cd:ca:de, -59, AgEGDv9pCdY1hs3K3tsfADEE, ], [cb:0a:57:d2:d7:32, -62, AgEGC/9pCcsKV9LXMgHgBwlXb1MxTUI=, ], [d6:29:92:92:59:1f, -81, B/9MABICAAE=, ], [74:e1:0c:17:8e:cd, -65, AgEaAgoMC/9MABAGTx25Zf5I, ]]]' with class 'java.util.ArrayList' to class 'java.util.LinkedHashMap' due to: groovy.lang.GroovyRuntimeException: Could not find matching constructor for: java.util.LinkedHashMap(java.lang.Integer, java.util.ArrayList) on line 641 (method parse)
dev:27462024-04-15 04:42:45.375 PMerrororg.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object '[2, [[a6:d7:3c:44:d3:e1, -92, AgEGBv9AAABsAhEGWcFKSu0rc7VZTvROAAAqgA==, ], [70:09:71:75:eb:cf, -93, G/91AEIEAYBmcAlxdevPcglxdevOAfQAAAAAAA==, ]]]' with class 'java.util.ArrayList' to class 'java.util.LinkedHashMap' due to: groovy.lang.GroovyRuntimeException: Could not find matching constructor for: java.util.LinkedHashMap(java.lang.Integer, java.util.ArrayList) on line 641 (method parse)
dev:27462024-04-15 04:42:45.209 PMerrororg.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object '[2, [[d4:9d:c0:8a:05:6f, -92, AgEaG/91AEIEAQFn1J3AigVv1p3AigVuAQncAAAAAA==, ], [50:4c:62:65:03:bd, -73, AgEaDf9MABYIAHYHSoy8Lng=, ], [c9:9a:4c:89:69:71, -77, B/9MABICAAM=, ], [40:cb:c0:d2:9b:f1, -95, AgEaAgoMEf9MAA8IwAqn2VsAAQwQAgEA, ], [db:72:c5:32:d9:d2, -72, AgEGDv9pCdtyxTLZ0jIfATEE, ]]]' with class 'java.util.ArrayList' to class 'java.util.LinkedHashMap' due to: groovy.lang.GroovyRuntimeException: Could not find matching constructor for: java.util.LinkedHashMap(java.lang.Integer, java.util.ArrayList) on line 641 (method parse)
dev:27462024-04-15 04:42:44.875 PMerrororg.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object '[2, [[1d:8c:21:1d:2e:84, -88, Hv8GAAEJICKXl/6/MaEav77+Xm1iLofTkL8t04ew/w==, ], [7e:37:53:83:70:4f, -77, AgEaDf9MABYIAJPfRAYmiFs=, ], [f4:4e:fd:00:1e:21, -83, , ], [d4:9d:c0:8a:05:6f, -90, AgEaG/91AEIEASBnGQ0AAAE6AAAAAAAAAAAAAAAAAA==, ], [bc:7e:8b:1a:67:d9, -81, G/91AEIEAYBmvH6LGmfZvn6LGmfYAUvqAAAAAA==, ], [47:e3:bf:7b:01:3b, -77, AgEaAgoMDP9MABAHeh/TXk4VaA==, ], [35:f8:d7:f3:f8:a7, -86, AgEGG/9MAAMWEQAAAnfAqAQwAAAAAAAAAAAAAAAACw==, ]]]' with class 'java.util.ArrayList' to class 'java.util.LinkedHashMap' due to: groovy.lang.GroovyRuntimeException: Could not find matching constructor for: java.util.LinkedHashMap(java.lang.Integer, java.util.ArrayList) on line 641 (method parse)

Top portion of the log related to when I tried to assign a DEVICE driver attempting to stop all that flood. This did not help and I had to delete a device all together.
Please advice what I am doing wrong?

Thank you.