Try typing in something like “/hello” for the URL field and see if that saves for you.
It is just a string/text input field. Nothing special.
Try typing in something like “/hello” for the URL field and see if that saves for you.
It is just a string/text input field. Nothing special.
/hello worked. ![]()
Any ideas why the full URL wouldn't? On two different hubs, different models, this seems unlikely to be a database corruption issue. Other things are all running normally. Weird.
Tried the full URL again and failed again. Totally confused here. ![]()
I cannot see the full URL in your screenshot. Just spitballing, can you double-check you are ending with a bracket and not a bracket plus a close parentheses?
E.g.
}
Not
})
might try it with a URLencode, i.e.
http://192.168.20.102/rpc/PLUGS_UI.SetConfig?config%3D%7B%22leds%22%3A%7B%22mode%22%3A%22switch%22%2C%22colors%22%3A%7B%22switch%3A0%22%3A%7B%22on%22%3A%7B%22rgb%22%3A%5B0.000%2C0.000%2C100.000%5D%2C%22brightness%22%3A100%7D%2C%22off%22%3A%7B%22rgb%22%3A%5B0.000%2C0.000%2C100.000%5D%2C%22brightness%22%3A100%7Dhttp%3A%2F%2F192.168.20.102%2Frpc%2FPLUGS_UI.SetConfig%3Fconfig%3D%7B%22leds%22%3A%7B%22mode%22%3A%22switch%22%2C%22colors%22%3A%7B%22switch%3A0%22%3A%7B%22on%22%3A%7B%22rgb%22%3A%5B0.000%2C0.000%2C100.000%5D%2C%22brightness%22%3A100%7D%2C%22off%22%3A%7B%22rgb%22%3A%5B0.000%2C0.000%2C100.000%5D%2C%22brightness%22%3A100%7D
Thanks for asking...ends in three brackets:
http://192.168.20.102/rpc/PLUGS_UI.SetConfig?config={"leds":{"mode":"switch","colors":{"switch:0":{"on":{"rgb":[0.000,0.000,100.000],"brightness":100},"off":{"rgb":[0.000,0.000,100.000],"brightness":100}},"power":{"brightness":100}},"night_mode":{"enable":false,"brightness":10,"active_between":["00:00","00:00"]}},"controls":{"switch:0":{"in_mode":"detached"}}}
Dan tried this I believe based on what he posted above.
/rpc/PLUGS_UI.SetConfig?config={"leds":{"mode":"switch","colors":{"switch:0":{"on":{"rgb":[0.000,0.000,100.000],"brightness":100},"off":{"rgb":[0.000,0.000,100.000],"brightness":100}
Try that and see if it saves
But saved without error? Just trying to get to the crux of the issue.
I'll give that a try. The problem may be that it will save, but it won't complete the necessary action on the Shelly plug. The URL including three brackets at the end does function properly when executed from a browser. Leaving the brackets off may end up with broken plug functionality even if Dan's momentary switch app can save it in that format. ![]()
Yup, saves but doesn't execute properly from @ogiewon's momentary switch app. No change in plug LED color, and errors in the logs.
I meant saved okay in Dan's app.
To summarize, the issue is that the GET URLs required by the Shelly plug have brackets in them that rule machine strips out. When that happens the Shelly GET URLs don't work.
There doesn't appear to be an easy workaround for the issue with Rule Machine stripping out the brackets, short of some sort of update of room machine from HE staff, who are understandably busy with the current platform beta. And so far, of the three apps I've tried that provide GET calls, none of them work with the Shelly URL either.
I know it’s frustrating right now, but I’m sure there’s a method that will work. It cannot be that hard. I’ll take a look at some past code that others have help me with and see if there’s a prospect.
If the UUEncoding didn't work have you tried escaping out the brackets? Probably won't work but it depends on how it is being interpreted.
"rgb":\[0.000,0.000,100.000\]
There might stiil be a different way, but one possiblity is webCoRE as discussed in this post.
Thanks for the suggestion, I tried using the escape approach and it didn't work...
I'm really not frustrated at all, I hope I didn't come across that way. I find these little adventures to be highly entertaining and I always learn useful and interesting things from them.
I used to do all my automations in webcore, haven't used it in a long time but if it will make this happen that's a very reasonable approach.
Also very interested to hear if @ogiewon has any ideas for a work around for the fact that his app didn't seem to like the three ending brackets in the URL I need to use) or if @thebearmay has any additional suggestions. ![]()
Not at all. I'm just trying to be a more empathetic person. ![]()
Embarrassing amount of time w/ChatGPT tonight got me a working driver...using POST commands as Chat could never get an HTTP GET command to work. Blamed it on Hubitat (and I believe them). Driver is focused on setting LED color.
Three colors/levels I'm using for my notifications are hard coded into the driver (Chat's recommendation).
Updated my rule w/the button actions and works!
Code below, if anyone wants to look/make fun of it. ![]()
metadata {
definition(
name: "Shelly RPC HTTP POST Multi-Config (FINAL - Dynamic Buttons)",
namespace: "custom",
author: "You"
) {
capability "Momentary"
capability "PushableButton"
command "applyConfig1"
command "applyConfig2"
command "applyConfig3"
command "applyConfig4"
command "applyConfig5"
}
preferences {
input name: "buttonCount",
type: "number",
title: "Number of enabled configs/buttons (1–5)",
defaultValue: 2,
range: "1..5",
required: true
input name: "enableReadBeforeWrite",
type: "bool",
title: "Read current config before writing",
defaultValue: false
input name: "logDesc",
type: "bool",
title: "Enable descriptive text logging",
defaultValue: true
input name: "logDebug",
type: "bool",
title: "Enable debug logging",
defaultValue: false
}
}
def installed() {
updateButtonCount()
}
def updated() {
updateButtonCount()
}
private void updateButtonCount() {
Integer count = (settings.buttonCount ?: 1) as Integer
sendEvent(name: "numberOfButtons", value: count)
if (logDesc) log.info "Configured for ${count} buttons"
}
/* =========================
Button handlers
========================= */
def push(buttonNumber) {
if (buttonNumber > settings.buttonCount) {
if (logDebug) log.debug "Ignoring push for disabled button ${buttonNumber}"
return
}
if (logDesc) log.info "Button ${buttonNumber} pushed"
applyConfig(buttonNumber)
}
def applyConfig1() { applyConfig(1) }
def applyConfig2() { applyConfig(2) }
def applyConfig3() { applyConfig(3) }
def applyConfig4() { applyConfig(4) }
def applyConfig5() { applyConfig(5) }
/* =========================
RPC SETTINGS
========================= */
private String getRpcUrl() {
return "http://192.168.20.102/rpc"
}
private String getSetMethod() {
return "PLUGS_UI.SetConfig"
}
private String getGetMethod() {
return "PLUGS_UI.GetConfig"
}
/* =========================
CONFIG DEFINITIONS
Edit/add configs here
========================= */
private Map getConfigForButton(Integer btn) {
switch (btn) {
case 1:
return [
leds: [
mode: "switch",
colors: [
"switch:0": [
on : [ rgb: [0.0, 0.0, 100.0], brightness: 100 ],
off: [ rgb: [0.0, 0.0, 100.0], brightness: 100 ]
]
]
]
]
case 2:
return [
leds: [
mode: "switch",
colors: [
"switch:0": [
on : [ rgb: [100.0, 0.0, 90.0], brightness: 100 ],
off: [ rgb: [100.0, 0.0, 90.0], brightness: 100 ]
]
]
]
]
case 3:
return [
leds: [
mode: "switch",
colors: [
"switch:0": [
on : [ rgb: [100.0, 100.0, 0.0], brightness: 100 ],
off: [ rgb: [100.0, 100.0, 0.0], brightness: 100 ]
]
]
]
]
default:
log.warn "No config defined for button ${btn}"
return null
}
}
/* =========================
RPC EXECUTION
========================= */
private void applyConfig(Integer buttonNumber) {
if (buttonNumber > settings.buttonCount) return
Map config = getConfigForButton(buttonNumber)
if (!config) return
if (enableReadBeforeWrite) {
readCurrentConfig()
}
def rpcBody = [
jsonrpc: "2.0",
id : now(),
method : getSetMethod(),
params : [
config: config
]
]
sendRpc(rpcBody, "Applied config ${buttonNumber}")
}
private void readCurrentConfig() {
def rpcBody = [
jsonrpc: "2.0",
id : now(),
method : getGetMethod(),
params : [:]
]
sendRpc(rpcBody, "Read current config")
}
private void sendRpc(Map rpcBody, String descText) {
def params = [
uri: getRpcUrl(),
requestContentType: "application/json",
contentType: "application/json",
body: rpcBody,
timeout: 10
]
try {
httpPost(params) { resp ->
if (logDesc) log.info descText
if (logDebug) {
log.debug "RPC request: ${rpcBody}"
log.debug "RPC response: ${resp.data}"
}
}
} catch (Exception e) {
log.error "RPC failed: ${e}"
}
}
Could be optimized a little and maybe abstracted a little in a couple of areas, but I've learned never to make fun of working code. So does this mean you're going start using a Developer title going forward?![]()
If you want to fully embrace the vibe coding workflow, you get Claude or Gemini to look/make fun of what ChatGPT helped write.
(Well done !)
EDIT:
Looking at this code, I’d say your friend and ChatGPT did a pretty reasonable job - it’s functional, reasonably organized, and doesn’t have any egregious issues. But since you asked me to look at it with a critical eye, here are some observations:
The Good:
∙ Clean structure with logical sections
∙ Proper error handling in the HTTP call
∙ Reasonable use of logging
∙ The dynamic button count approach is actually clever
∙ No obvious security issues (though hardcoding IPs isn’t great practice)
The “ChatGPT Tells”:
∙ That comment style with the ASCII box dividers screams AI generation
∙ The overly defensive if (buttonNumber > settings.buttonCount) return guards in multiple places
∙ The somewhat redundant command definitions (applyConfig1-5 could be eliminated if using push() directly)
∙ The private String getRpcUrl() pattern for constants - it works but is unconventional in Groovy
The Nitpicks:
∙ The config definitions are repetitive - a more elegant approach would parameterize the RGB values
∙ now() for the RPC ID is fine but UUID.randomUUID() would be more “correct”
∙ The “FINAL” in the driver name is already a bad omen for future maintenance
∙ No actual validation that the Shelly device responded successfully
∙ The enableReadBeforeWrite feature exists but doesn’t actually use the read data for anything
The Real Question:
What’s the actual use case here? If it’s just cycling through LED colors on a Shelly plug, this is over-engineered. The whole button abstraction layer adds complexity when you could just have direct “setBlue()”, “setPink()”, “setYellow()” commands.
Verdict: It’s perfectly cromulent code that works. Not elegant, not terrible. Typical of AI-assisted code where it’s functionally correct but lacks the refinement that comes from understanding why you’d do things a certain way in the Hubitat ecosystem.
Would I accept this in a code review? Sure, with minor suggestions. Would I show it as an example of excellent Hubitat driver development? Probably not.