Node-RED nodes for hubitat

More dashboard stuff.

Result: (balcony door not opened yet, since I did the colors) Blue = closed, Red = Open
image

Visual:

Code: (shove a HE contact sensor in front of each of the flows). I have not copied my contact sensors.

Summary
[{"id":"64190c5c.0aa904","type":"change","z":"ec8abfc3.b90c4","name":"unwrap payload","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.value","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1260,"y":680,"wires":[["d461e68.dfe5918"]]},{"id":"aa54a7b1.f67308","type":"change","z":"ec8abfc3.b90c4","name":"unwrap payload","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.value","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1260,"y":980,"wires":[["754c3a87.e2ae44"]]},{"id":"3a3b75d3.40f5aa","type":"change","z":"ec8abfc3.b90c4","name":"unwrap payload","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.value","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1260,"y":860,"wires":[["1b283887.db2117"]]},{"id":"593c7979.70e598","type":"change","z":"ec8abfc3.b90c4","name":"unwrap payload","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.value","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1260,"y":740,"wires":[["721920a6.38df6"]]},{"id":"e770577f.5cae68","type":"change","z":"ec8abfc3.b90c4","name":"unwrap payload","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.value","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1260,"y":920,"wires":[["2dcfe43a.2dd95c"]]},{"id":"76ebefab.ea4c6","type":"change","z":"ec8abfc3.b90c4","name":"unwrap payload","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.value","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1260,"y":1060,"wires":[["247fe4fa.d3ac4c"]]},{"id":"57d146d3.e68828","type":"change","z":"ec8abfc3.b90c4","name":"unwrap payload","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.value","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1260,"y":800,"wires":[["2a4a10aa.ffd9a"]]},{"id":"95ff292c.e10608","type":"change","z":"ec8abfc3.b90c4","name":"unwrap payload","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.value","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1260,"y":1120,"wires":[["d78dab9.88dfc58"]]},{"id":"4c6bcf1e.c346b","type":"ui_text","z":"ec8abfc3.b90c4","group":"fb26db16.195408","order":4,"width":3,"height":1,"name":"4. Front Screen","label":"<font color= {{msg.color}} ><b>Front Screen</b></font>","format":"","layout":"row-center","x":1620,"y":860,"wires":[]},{"id":"539fcf54.2f3be","type":"ui_text","z":"ec8abfc3.b90c4","group":"fb26db16.195408","order":7,"width":3,"height":1,"name":"8.Balcony","label":"<font color= {{msg.color}} ><b>Balcony</b></font>","format":"","layout":"row-center","x":1600,"y":1120,"wires":[]},{"id":"1847aa10.4f03a6","type":"ui_text","z":"ec8abfc3.b90c4","group":"fb26db16.195408","order":2,"width":3,"height":1,"name":"2. Front","label":"<font color= {{msg.color}} ><b>Front</b></font>","format":"","layout":"row-center","x":1600,"y":740,"wires":[]},{"id":"52b55033.876bb","type":"ui_text","z":"ec8abfc3.b90c4","group":"fb26db16.195408","order":5,"width":3,"height":1,"name":"5. Laundry","label":"<font color= {{msg.color}} ><b>Laundry</b></font>","format":"","layout":"row-center","x":1610,"y":920,"wires":[]},{"id":"7a105462.4b060c","type":"ui_text","z":"ec8abfc3.b90c4","group":"fb26db16.195408","order":3,"width":3,"height":1,"name":"6. Under Stairs","label":"<font color= {{msg.color}} ><b>Under Stairs</b></font>","format":"","layout":"row-center","x":1620,"y":980,"wires":[]},{"id":"598f06e2.fa9ee8","type":"ui_text","z":"ec8abfc3.b90c4","group":"fb26db16.195408","order":1,"width":3,"height":1,"name":"1. Garage","label":"<font color= {{msg.color}}><b>Garage</b></font>","format":"","layout":"col-center","x":1600,"y":680,"wires":[]},{"id":"4c87a8de.e54f58","type":"ui_text","z":"ec8abfc3.b90c4","group":"fb26db16.195408","order":6,"width":3,"height":1,"name":"7. Garage Side","label":"<font color= {{msg.color}} ><b>Garage Side</b></font>","format":"","layout":"row-center","x":1620,"y":1060,"wires":[]},{"id":"133ac60d.518a7a","type":"ui_text","z":"ec8abfc3.b90c4","group":"fb26db16.195408","order":3,"width":3,"height":1,"name":"3. Back","label":"<font color= {{msg.color}} ><b>Back</b></font>","format":"","layout":"row-center","x":1600,"y":800,"wires":[]},{"id":"d461e68.dfe5918","type":"function","z":"ec8abfc3.b90c4","name":"Set Color","func":"if (msg.payload == \"closed\" ) {\n    msg.color = 'DodgerBlue';\n}\nelse {\n    msg.color = 'Red'\n}\nreturn msg;\n","outputs":1,"noerr":0,"x":1440,"y":680,"wires":[["598f06e2.fa9ee8"]]},{"id":"721920a6.38df6","type":"function","z":"ec8abfc3.b90c4","name":"Set Color","func":"if (msg.payload == \"closed\" ) {\n    msg.color = 'DodgerBlue';\n}\nelse {\n    msg.color = 'Red'\n}\nreturn msg;\n","outputs":1,"noerr":0,"x":1440,"y":740,"wires":[["1847aa10.4f03a6"]]},{"id":"2a4a10aa.ffd9a","type":"function","z":"ec8abfc3.b90c4","name":"Set Color","func":"if (msg.payload == \"closed\" ) {\n    msg.color = 'DodgerBlue';\n}\nelse {\n    msg.color = 'Red'\n}\nreturn msg;\n","outputs":1,"noerr":0,"x":1440,"y":800,"wires":[["133ac60d.518a7a"]]},{"id":"1b283887.db2117","type":"function","z":"ec8abfc3.b90c4","name":"Set Color","func":"if (msg.payload == \"closed\" ) {\n    msg.color = 'DodgerBlue';\n}\nelse {\n    msg.color = 'Red'\n}\nreturn msg;\n","outputs":1,"noerr":0,"x":1440,"y":860,"wires":[["4c6bcf1e.c346b"]]},{"id":"2dcfe43a.2dd95c","type":"function","z":"ec8abfc3.b90c4","name":"Set Color","func":"if (msg.payload == \"closed\" ) {\n    msg.color = 'DodgerBlue';\n}\nelse {\n    msg.color = 'Red'\n}\nreturn msg;\n","outputs":1,"noerr":0,"x":1440,"y":920,"wires":[["52b55033.876bb"]]},{"id":"754c3a87.e2ae44","type":"function","z":"ec8abfc3.b90c4","name":"Set Color","func":"if (msg.payload == \"closed\" ) {\n    msg.color = 'DodgerBlue';\n}\nelse {\n    msg.color = 'Red'\n}\nreturn msg;\n","outputs":1,"noerr":0,"x":1440,"y":980,"wires":[["7a105462.4b060c"]]},{"id":"247fe4fa.d3ac4c","type":"function","z":"ec8abfc3.b90c4","name":"Set Color","func":"if (msg.payload == \"closed\" ) {\n    msg.color = 'DodgerBlue';\n}\nelse {\n    msg.color = 'Red'\n}\nreturn msg;\n","outputs":1,"noerr":0,"x":1440,"y":1060,"wires":[["4c87a8de.e54f58"]]},{"id":"d78dab9.88dfc58","type":"function","z":"ec8abfc3.b90c4","name":"Set Color","func":"if (msg.payload == \"closed\" ) {\n    msg.color = 'DodgerBlue';\n}\nelse {\n    msg.color = 'Red'\n}\nreturn msg;\n","outputs":1,"noerr":0,"x":1440,"y":1120,"wires":[["539fcf54.2f3be"]]},{"id":"fb26db16.195408","type":"ui_group","z":"","name":"Doors","tab":"1895180c.da6e38","order":1,"disp":true,"width":3,"collapse":true},{"id":"1895180c.da6e38","type":"ui_tab","z":"","name":"Mike","icon":"dashboard","disabled":false,"hidden":false}]
3 Likes

We (and by we I mean one of you guys smarter than me) need to figure out a way to show pieces of a Node Red Dashboard on a HE dashboard. Then you could have some of the charting like I posted earlier and what @mike just posted show up within the HE Dashboard shell. I know its easy to create a link but that's just not the same if I have to make an extra click.

Just changed it to behave the same way.... :wink:

2 Likes

I'm telling you...

This new revelation (on my part) on how the device node works changes how I do quite a number of things.

I've been doing some tests redoing (really undoing) some of the traps I put in my nodes to ensure no 'duplicate hubitat maker api messages', and it is really cleaning things up nicely!

Well, there is a way. Here is my hack....

I have the following customer driver:

iFrame Driver
preferences {
        input("src", "text", title: "iFrame Url",  required: true)
        input ( name: 'pollInterval', type: 'enum', title: 'Update interval (in seconds)', options: ['10', '30', '60', '300'], required: true, displayDuringSetup: true, defaultValue: "60" )
    }
metadata {
    definition (name: "iFrame Tile", namespace: "srp", author: "srp") {
        capability "Switch"
        capability "Initialize"
        
        attribute "myFrame", "text"
    }
}
def on() {
    sendEvent(name: "switch", value: "on")
    sendEvent(name: "myFrame", value: "<iframe src='${src}' width='500' height='300' frameborder='0'></iframe>")
}
def off() {
    sendEvent(name: "switch", value: "off")
}

def installed() {
    initialize()
}

def initialize() {
    updated()
}

def updated() {
    configure()
}

def configure() {
    unschedule()
    def pollInt = settings["pollInterval"]?.toInteger()
    // If change polling options in UI, may need to modify some of these cases:
    switch (pollInt ?: 0) {
        case 0:
            break
        case 1..59:
            schedule("${Math.round(Math.random() * pollInt)}/${pollInt} * * ? * * *", "on")
            break
        case 60..259:
            runEvery1Minute("on")
            break
        case 300..1800:
            runEvery5Minutes("on")
            break
        default:
            runEvery1Hour("on")                
    }
    on()
}

In this driver, I can set a URL as source.
I hardcoded the width and height for my application, but you can change that in the code line here:
sendEvent(name: "myFrame", value: "<iframe src='${src}' width='500' height='300' frameborder='0'></iframe>")
just change the width and height

Then, on my dashboard, I have a tile that shows the attribute "myFrame".

It's not elegant but it works....

2 Likes

I am with you. My head is :exploding_head: ... Going through my flows myself right now...

@dan.t just proved my point. Thank you.

I don't consider myself smart. I am lazy.... I will do anything for making my life easier... That's how I got hooked on home automation.....

3 Likes

Lol...this exactly. Lazy breeds ingenuity. That's my motto.

1 Like

Thanks for the iFrame driver! That works great. I am not asking you to do it but I could modify your driver so that the width and height is in the preferences correct? Then, instead of having multiple device drivers with a device corresponding to each, I could have one device driver and a device corresponding to each size I want correct?

1 Like

Hi @mike, so how can I show temperature of few devices on dashboard? Which palette should I use?

You asked me by not asking me????? :crazy_face:

Here you go:

iFrame Driver
preferences {
        input("src", "text", title: "iFrame Url",  required: true)
        input("width", "number", title: "iFrame width in pixel",  required: true, default: 500)
        input("height", "number", title: "iFrame height in pixel",  required: true, default: 300)
        input ( name: 'pollInterval', type: 'enum', title: 'Update interval (in seconds)', options: ['10', '30', '60', '300'], required: true, displayDuringSetup: true, defaultValue: "60" )
    }
metadata {
    definition (name: "iFrame Tile", namespace: "srp", author: "srp") {
        capability "Switch"
        capability "Initialize"
        
        attribute "myFrame", "text"
    }
}
def on() {
    sendEvent(name: "switch", value: "on")
    sendEvent(name: "myFrame", value: "<iframe src='${src}' width='${width}' height='${height}' frameborder='0'></iframe>")
}
def off() {
    sendEvent(name: "switch", value: "off")
}

def installed() {
    initialize()
}

def initialize() {
    updated()
}

def updated() {
    configure()
}

def configure() {
    unschedule()
    def pollInt = settings["pollInterval"]?.toInteger()
    // If change polling options in UI, may need to modify some of these cases:
    switch (pollInt ?: 0) {
        case 0:
            break
        case 1..59:
            schedule("${Math.round(Math.random() * pollInt)}/${pollInt} * * ? * * *", "on")
            break
        case 60..259:
            runEvery1Minute("on")
            break
        case 300..1800:
            runEvery5Minutes("on")
            break
        default:
            runEvery1Hour("on")                
    }
    on()
}
2 Likes

NO!!! I am seriously going to figure this out. I am not looking!!!!

I modified your driver to make the tile 1000x1400 to accommodate my temperature chart so when i first created a device, the Current State myFrame was so big it pushed everything so far over you couldn't enter anything in the device page. Oops.

EDIT: I promise I didn't look first. :sunglasses:

One of these days I am going to break down and try to learn Groovy.

1 Like

Worst feeling in the world, you plug in the power and that activity light just never turns green. I had this happen not too long ago due to power failure. Had to totally rebuild my RPi that ran my DIYHue bridge, my Assistant Relay Server, my Cast-Web-API server, my Email/Text server, my Motiioneye Server, and my VPN server. It was WEEKS before i had everything rebuilt. I will definitely be picking up on of these!

I have to take some time to make an image backup again. But it takes like 2 hours to do it and I lose all that other stuff while it's running. lol

1 Like

Yeah, it definitely stinks!

Where I don't use rpi-clone, I manually back up over the network... Pretty easy to do from Windows WSL, mac terminal, or *nix machine - and it can be done online without taking the rpi down.

I do it manually, but could probably be scripted, too.

Example from Windows WSL2 backing up to D:\backup:
ssh user@ip "sudo dd if=/dev/mmcblk0 bs=1M" | gzip | dd of=/mnt/d/backup/file.gz

1 Like

Huh....I didn't know you could do that while it was running. I always shut down and imaged on my desktop via Win32DiskImager.
:exploding_head:
mind blown!

It took me a while but I did finally find a method to shrink those images too...so I can save more than one without taking up ALL my storage space. It doesn't work all the time but I've had good luck with it.

Well, I now have a new project to do this week...this is wonderful!

1 Like

You know... To be slightly more technically correct I really should have said to do a "-t" on the ssh... Should work without it, but could fail in some scenarios if it isn't specified.

ssh -t user@ip "sudo dd if=/dev/mmcblk0 bs=1M" | gzip | dd of=/mnt/d/backup/file.gz

I was going to automate with a bash script in my pi run on a cron entry anyway, so wouldn't have even noticed.

But do you really need pseudo -tty for that command? I wouldn't think that command would be affected but I am no ssh expert. :man_shrugging:

No, I really don't think you need it.

For some reason, though, I have one rpi that if I don't use it, it gives me the old "sudo: no tty present and no askpass program specified" error.

Not sure why, but I am sure that specifying -t works around it. Probably a band-aid more than a real fix, though, admittedly.

So, you're right. Probably better to leave -t off.

Got it running now, so it should be done in about 9 hours. So much more convenient than shutting down my Pi for 3-4 hours.