Adding `output` function to buttons designed in `template` node

Ok, food for thought - me talking about what I am doing.

As is you have posted a flow (block?) of code with a few buttons and a main node to handle the buttons.

I will expand the buttons to cover all the needs. That isn't here or there.

That all works nicely.
The problem happens when I want a second remote control with (say) the same buttons.

Simply copying them and I press a button on #1's part: both 1 and 2 get the signal.
Yes, you did mention topic setting. But that gets a bit long winded with 6 different devices.

What I did - and it is a lot easier now I think - is I copied the entire block of code:
the css node, all the templates and the bottom one which receives the messages.
As is, the name is: remote-button

I export it (formatted) and in my editor replace all the remote-button with another name
Copy it, go back to Node-Red and import.

Paste and it is a whole new block of code that is internal to itself.

All I need to do is do that for each device.

I know it is a bit wasteful, but it has clear demarcation between the devices.

I'll mess around with this for a while today to test what's what.

If good I think this will be a lot easier to migrate to new devices than the previous way.

(More posts from the Village idiot)

Here are some working blocks of code.
This one blinks the button in an easyish way and had little code in the button node:

[{"id":"88edaa29.60684","type":"ui_template","z":"8bb4de19.f72c88","group":"d3bcf885.d668a","name":"6","order":12,"width":1,"height":1,"format":"<style>\n.button {/*button styles*/}\n.B{ color: red;}\n.A{ color: lime;}\n</style>\n\n<button class=\"baseline {{msg.payload}}\" ng-mousedown=\"send({payload: 'Down'})\"  \nng-mouseup=\"send({payload: 'Up'})\">Press</button>\n","storeOutMessages":true,"fwdInMessages":false,"resendOnRefresh":true,"templateScope":"local","x":790,"y":1300,"wires":[["d08b68e5.aa949","76a653ec.ae4d34","576062c5.31c064"]]},{"id":"d08b68e5.aa949","type":"trigger","z":"8bb4de19.f72c88","op1":"Down","op2":"0","op1type":"str","op2type":"str","duration":"-350","extend":false,"units":"ms","reset":"Up","bytopic":"all","name":"Repeat","x":950,"y":1350,"wires":[["28a8ab64.3a4394"]]},{"id":"76a653ec.ae4d34","type":"switch","z":"8bb4de19.f72c88","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"Down","vt":"str"},{"t":"eq","v":"Up","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":940,"y":1390,"wires":[[],["28a8ab64.3a4394"]]},{"id":"576062c5.31c064","type":"debug","z":"8bb4de19.f72c88","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":960,"y":1300,"wires":[]},{"id":"28a8ab64.3a4394","type":"function","z":"8bb4de19.f72c88","name":"toggle","func":"let msg1 = {};\nlet y = context.get(\"pressed\") || 0;\nvar x = context.get(\"counter\") || 0;\nif (msg.payload == \"Up\")\n{\n    context.set(\"counter\",0);\n    msg.payload = \"A\";\n    context.set(\"pressed\",0);       //  Wipe count.\n//    msg1.colour = \"lime\";\n\n    return [msg,null];\n}\n\nif (x === 0)\n{\n    if (y === 0)\n    {\n        //  Send pressed message.\n        y = y + 1;\n        context.set(\"pressed\",y);\n        //  msg1 = {payload:\"Goo\"};\n        msg1 = {payload:\"Pressed\"};\n        node.send([null,msg1]);\n        //node.send([null,msg1]);\n        \n    }\n    msg.payload = \"B\";\n    msg1.colour = \"red\";\n} else\nif (x === 1)\n{\n    msg.payload = \"A\";\n    msg1.colour = \"lime\";\n}\n\nx = (x + 1) % 2;\n\ncontext.set(\"counter\",x);\n\nreturn [msg,null];","outputs":2,"noerr":0,"x":1100,"y":1350,"wires":[["af2e86ca.3546b","88edaa29.60684","a33d9067.50ce3"],["b6647fef.aa089"]]},{"id":"af2e86ca.3546b","type":"debug","z":"8bb4de19.f72c88","name":"PULSE OUTPUT","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1300,"y":1300,"wires":[]},{"id":"a33d9067.50ce3","type":"ui_text","z":"8bb4de19.f72c88","group":"d3bcf885.d668a","order":13,"width":2,"height":1,"name":"","label":"6 : ","format":"{{msg.payload}}","layout":"row-spread","x":1260,"y":1260,"wires":[]},{"id":"b6647fef.aa089","type":"debug","z":"8bb4de19.f72c88","name":"SINGLE OUTPUT","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":1300,"y":1350,"wires":[]},{"id":"d3bcf885.d668a","type":"ui_group","z":"","name":"Group 1","tab":"de5134a7.f0a0d","order":1,"disp":true,"width":"6","collapse":false},{"id":"de5134a7.f0a0d","type":"ui_tab","name":"Tab 6","icon":"dashboard","order":4}]

This is the template code:

<style>
.button {/*button styles*/}
.B{ color: red;}
.A{ color: lime;}
</style>
<button class="baseline {{msg.payload}}" ng-mousedown="send({payload: 'Down'})"  
ng-mouseup="send({payload: 'Up'})">Press</button>

Not too complicated.
If it gets an A it turns the button one colour. If it gets a B, it changes to another colour.
It sends a down and an up message.

Working on what Steve showed me, this is another button:

<div>
   <md-button class="md-button remote-button-2" 
        data-buttontype="repeater"
        data-interval="200"
        data-topic="volume"
        data-payload="up"
        aria-label="volume plus"
    >
    <span style="color:{{msg.colour}}" class="fa fa-plus remote-icon"> </span>
   </md-button>
</div>

Ok, let's try to combine them.

My effort:

<style>
.button {/*button styles*/}
.B{ color: red;}
.A{ color: lime;}
</style>
<md-button class="md-button remote-button-2"
ng-mousedown="send({payload: 'Down', topic:'volume'})"  
ng-mouseup=  "send({payload: 'Up', topic:'volume'})">

<span class="fa fa-plus remote-icon"> </span>
</md-button>

It doesn't work.
It doesn't work in that it doesn't accept the new colour inputs. A and B.
That is by the by as I am just using what I see as working.
When/if I get it working, I will change things.

Not a problem. I can't expect to just know how to do it.
I am not getting the structure of what goes inside what.
<style> <span> <md-button> and so forth.

I'll keep trying, but this is more of a throw enough mud and some will stick method which I accept I seem to be using.

But only because I still don't know any better. And I admit that.

You can see (from the screen shot) that it is sort of working. Just not quite as good as I would like.

There is no payload sent via the magic part. Well, it is sent: just not defined. I think.

Thats exactly why I parameterised the BUTTON_CLASS. In essence, you had two choices, have 1 code block and unique topics - OR - change the class. :+1:

And isn't that what I did?

I get you want me to have only one master template node and one template node at the bottom.

Is it wrong that I grouped the buttons together and set their class as the device they control?

So (eg) I would have TV-IR AMP-IR DVD-IR.

I get all the buttons, set up node and the bottom node, export them form the default settings.
Import them to an editor and replace the remote-button with (say) TV-IR and then import it to a new block.

That should be a block unto itself.

I think I have it working, but now I am seeing contamination between two different blocks and I can't see why.

I've checked all the names and they look correct and there is no mix up as far as I can see.

Not wanting to annoy you - but I have to learn to do by doing in some cases - but would you mind if I exported the two blocks and you have a look and tell me why they would be interfering with each other?

Updates

  • support touch screen events (touchstart, touchend)
  • fixed the repeater button getting stuck
  • making a button blink (CSS) (by adding/removing a class via a node-red msg)
  • disabling/enabling a button (CSS) (by adding/removing a class via a node-red msg)
  • repeater buttons that can send an event on release.
  • adding a maximum limit "send count" for repeater buttons (i.e. limit the number of repeat events)

Demo 1 - making a button disabled or blink by sending a msg

Demo 2 - limiting a repeat button and firing on release (pay attention to the .event propetry in the debug - you can use msg.event this to understand if a msg is an "down" or "up"

notes...

  • two new attributes added

    • data-max (optional) - set this to a number to limit how many times a repeater can repeat (see the vol+ button)
    • data-fireonup (optional) - set this to ="true" to have an "up" event fired when you release a "repeater" button
  • I had to add some classes for blinking and disabling (checkout the CSS template node)

  • you are NOT limited to "blinking" or "disabled"

    • Now that you have the ability to addclass, removeClass, toggleClass - the sky is your limit.
    • want to make a button spin on demand? add a class to your CSS that spins a button, then use toggleClass to turn it on or off
    • want to make a button disappear on demand? add a class to your CSS that sets display:none, then use toggleClass to turn it on or off

updated flow...

[{"id":"f4fac1e9.e93e4","type":"ui_template","z":"e1dfad68.fee2a","group":"be17d3d4.a92a6","name":"CSS only ","order":7,"width":0,"height":0,"format":"<style id=\"remote-buttons\">\n    :root {\n      --dashboard-unit-width: 48px;\n      --dashboard-unit-height: 48px;\n      --remote-button-background: black;\n      --remote-button-foreground: #cccccc;\n    }\n    .nr-dashboard-template {\n        padding: 0px;\n    }\n    \n    .remote-button.disabled{\n        cursor: not-allowed;\n        pointer-events: none;\n        color: #aaaaaa !important;\n    }\n    \n    .remote-button:not([disabled]):hover{\n         background-color: #232323 !important;\n    }\n\n    /*   This is the normal button definition  */\n    .remote-button{\n        background-color: var(--remote-button-background) !important;\n        color: var(--remote-button-foreground) !important;\n        height: var(--dashboard-unit-height);\n        width: 100%;\n        border-radius: 10px;\n        font-size:1.0em;\n        font-weight:normal;\n        margin: 0;\n        min-height: 36px;\n        min-width: unset;\n        line-height: unset;\n    }\n    /*  This is a sub-set which is invoked by */\n    /*  <md-button class=\"md-button remote-button bigger\"> */\n    /*  note the (space) \"bigger\" at the end.  */\n    .remote-button.bigger{\n        font-weight:bold;\n        font-size:1.5em;\n    }\n    /*  This is for buttons with a lot of text.  `font-size:0.7em` */\n    /*  makes the font 70% normal size  */\n    .remote-button.small{\n        font-size:0.7em;\n    }\n    /*  This is for buttons with just icons, to upsize the size */\n    /*  of the icon with the line: */\n    /*  <i class=\"fa fa-fw fa-plus remote-icon\"> in the other node  */\n    .remote-icon{\n        font-size:2.0em;\n    }\n    /*  This is the same as the other one, but it makes the icon smaller  */\n    .remote-iconS{\n        font-size:0.5em;\n    }\n\n    .remote-button.black{\n        background-color: var(--remote-button-background) !important;\n        color: var(--remote-button-foreground) !important;\n    }\n\n    .remote-button.red{\n        background-color: red !important;\n        color: var(--remote-button-foreground) !important;\n    }\n    .remote-button.red:not([disabled]):hover{\n         background-color: orange !important;\n    }\n\n    .remote-button.blinking{\n    \tanimation:blinkingAnim1 0.8s infinite;\n    }\n    @keyframes blinkingAnim1{\n    \t0%{\t\tbackground-color: var(--remote-button-background); color:var(--remote-button-foreground);}\n    \t50%{\tbackground-color: var(--remote-button-foreground); color:var(--remote-button-background);}\n    \t100%{\tbackground-color: var(--remote-button-background);\tcolor:var(--remote-button-foreground);}\n    }    \n     \n    .remote-button.red.blinking{\n    \tanimation:blinkingAnim2 0.8s infinite;\n    }\n    @keyframes blinkingAnim2{\n    \t0%{\t\tbackground-color: red; color:#cccccc;}\n    \t50%{\tbackground-color: #cccccc; color:red;}\n    \t100%{\tbackground-color: red;\tcolor:#cccccc;}\n    }     \n</style>","storeOutMessages":true,"fwdInMessages":true,"templateScope":"global","x":740,"y":80,"wires":[[]]},{"id":"bc691572.02ce88","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"NetFlix","order":20,"width":"1","height":"1","format":"<div>\n    <md-button \n        class=\"md-button remote-button\"\n        data-topic=\"netflix\"\n        data-payload=\"netflix\"\n        aria-label=\"Netflix\"\n    >\n        <img\n            class=\"remote-icon\"\n            style=\"width: 36px; padding-top: 2px\"\n            src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAE2klEQVR4Xu3bW4hVVRzH8c8ZE/GCtywry5qcarrhpbKLmoVl9FZ0s2zS0DIJrIceSl+EwIgIDCQCp4t2L4guBJUgTmnlXYtUirIpU9EZxyayqWbmxPKcARFn1hKDaW/7v64fM/v3Pf/1X2v/91oFx3kUjnP//gdwLBnQxMB2Hk75G81sreTNFO0CbioyKkX7Nwvnsz9FeyTNMWXAbip78kPKP29n++uMmkNzTL+AlzAtpgvjBSof48cU7b8O4Ckqp7G8B2elPMB2pl7KazFtZgA8wVkTWHI+V8dMhfE/eec0bolpMwWgNxtq6IeeMWM4sIzRU/i2K22mABTZPoUvB3BFAgD7mHcOC3IFoJKNkxmdAqCNTc9y2XxaO9NnLgPCUjKTnys4IwXCNm4Yxye5ARCMXEvduUxMAdBC7TDuyxWAPjTUMBAnJEBo/Jjqu2g4kjZzU6DDxJ2s7s/lCQA0cX8Vi3MFoIoNkxiTAqCV5UOZlCsABYoz2VnBsAQI7VsYM4HNh2szOwWCkUnUVSUWwwM8eQaP5gpAP/ZMZQgqYllQpP4Dqu+l5VBtpjMgGJnK2n5cFgMQxhu4+TzezRWAatZOTATQyttDuT1XACpon8meAqckZEFLPSPGsLNDm/kpEIxcT93ZicXwLx45ladzBWAAu6aUMiDadWpn8xBGh2U0QMhFBgQjd7OuL5cmTIOwMxxfxapcATifNVczNgVAO8+dxOxcAaigbSaNBU5OgNC0lTPH81tupkAwfSN1w9OL4bRTWZorAAPYMYXTEzIgVMDlQ5iUKwDB+D1s7J3WMise4LyXmZeJ7wKhLR6aorFf9yK+HJfYNG3n8cUMzxWAHrTO4NcCJ8Zg4ada6tqoSdB275eh1AwoF8MVw7kmxVQdn2xjcoq2Wz+NHQ2Awbx9G7em7Ax/5Ys3uDJXALBkVqlTdF2Csb+WcuCPUpO1y8hMBgQAD7CsyCsxU2H8az77nAkxbaYA1DC7D79gUMxYK989zzkxXaYAzGV6I89gTsxYGH+fbbuo7kqbOQD7uKh4MMPjsZvP3otMg8wBCLYbS6+9V8URaK6lVxu9OtNmEkAD0wu8mADAWj7f0AWsTALYSZ9epR7ggBiEFjYvYWSuMiCY2ceiIg/GAITxt9jR1MkbZSYzIJhqYmQ7m1IA/Ejdx530FDILoFwMV0tomRXZvZihxSM0WLMOYAZqU7JgOeu/45LDtZkGsId+PdildMqsy2hm9etHOHuQaQDlafAcZsUAoHUpzX8w+FBt5gHsZUwF6xMA+IZPVx52KDPzAMpL4vpiwsmSNr6vZUSuMqAMYFaRMBWi8SFbdnBBhzAXGdBIf6WdYd8Ygb2sfIfxuQJQLoZhOQzLYpdR5PcXqGildxDmIgOCkQbGFggbo2isY9V6xuUKQNjl7WOjLl58Osi08PUSLs4VgHIWPFhgUTQFSi9I9U2cmZspEEyX7yCFYnhwfncV9dR9xMRcASgXw9AomR4DUGRPLUOKjOi2O0NH82EktMVDUzRmrLHU/Tl4UiQWK1j7LbfnCkC5GIam6YUxAL+z5lXuyBWAcjGcUyi1z2PR9hVV13bXtbn5DOyZeHGywKa5h50I7czdfga18VDMfRivYOGg7ro4mfKA/3VN9Azff93AsT7fcQ/gH8HaMl8q26yhAAAAAElFTkSuQmCC\">\n        />\n    </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":730,"y":380,"wires":[[]]},{"id":"57de4e.f4cfb1b4","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"Home","order":21,"width":"1","height":"1","format":"<div>\n   <md-button class=\"md-button remote-button\" \n        data-topic=\"home\"\n        data-payload=\"home\" \n        aria-label=\"home\"\n    >\n    <i class=\"fa fa-home remote-icon\"> </i>\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":850,"y":380,"wires":[[]]},{"id":"a6df6e36.1d16b","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"Vid","order":22,"width":"1","height":"1","format":"<div>\n   <md-button class=\"md-button remote-button small\" \n        data-topic=\"video\"\n        data-payload=\"video\" \n    >Video\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":970,"y":380,"wires":[[]]},{"id":"2a646eff.3f7cf2","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"1","order":2,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button bigger\"\n    data-topic=\"1\"\n    data-payload=\"1\">1\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":730,"y":140,"wires":[[]]},{"id":"ef0701c1.ddb63","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"2","order":3,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button bigger\"\n    data-topic=\"2\"\n    data-payload=\"2\">2\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":850,"y":140,"wires":[[]]},{"id":"a8296eda.ec9d6","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"3","order":4,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button bigger\"\n    data-topic=\"3\"\n    data-payload=\"3\">3\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":970,"y":140,"wires":[[]]},{"id":"cf65f510.c80d68","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"4","order":5,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button bigger\"\n    data-topic=\"4\"\n    data-payload=\"4\">4\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":730,"y":180,"wires":[[]]},{"id":"84949bc8.2bd298","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"5","order":6,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button bigger\"\n    data-topic=\"5\"\n    data-payload=\"5\">5\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":850,"y":180,"wires":[[]]},{"id":"b341d1f1.adf42","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"6","order":7,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button bigger\"\n    data-topic=\"6\"\n    data-payload=\"6\">6\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":970,"y":180,"wires":[[]]},{"id":"76507e83.940e6","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"7","order":8,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button bigger\"\n    data-topic=\"7\"\n    data-payload=\"7\">7\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":730,"y":220,"wires":[[]]},{"id":"fbafce7d.80576","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"8","order":9,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button bigger\"\n    data-topic=\"8\"\n    data-payload=\"8\">8\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":850,"y":220,"wires":[[]]},{"id":"684b5568.bf5c6c","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"9","order":10,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button bigger\"\n    data-topic=\"9\"\n    data-payload=\"9\">9\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":970,"y":220,"wires":[[]]},{"id":"114192b6.67ea7d","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"0","order":12,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button bigger\"\n    data-topic=\"0\"\n    data-payload=\"0\">0\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":850,"y":260,"wires":[[]]},{"id":"84c69bfc.13faa8","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"info","order":11,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button\"\n    data-topic=\"info\"\n    data-payload=\"info\"\n    aria-label=\"info\"\n   >\n      <i class=\"fa fa-info-circle remote-icon\"></i>\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":730,"y":260,"wires":[[]]},{"id":"25910d61.070c82","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"prev","order":13,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button\"\n    data-topic=\"prev\"\n    data-payload=\"prev\"\n    aria-label=\"previous\"\n   >\n      <i class=\"fa fa-rotate-left remote-icon\"></i>\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":970,"y":260,"wires":[[]]},{"id":"787787b2.c80b88","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"Ch +","order":16,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button\" \n        data-topic=\"channel/up\"\n        data-payload=\"up\" \n        aria-label=\"channel up\"\n    >\n    <i class=\"fa fa-chevron-up remote-icon\"></i>\n   </md-button>\n</div>\n\n\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":970,"y":300,"wires":[[]]},{"id":"7eb81447.3ea8dc","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"mute","order":15,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button\" \n              data-payload=\"1\" \n              data-buttontype=\"toggle\"\n              data-topic=\"mute\"\n              data-icon0=\"volume_off\"\n              data-icon1=\"volume_mute\"\n              aria-label=\"volume mute\"\n              >\n      <i class=\"material-icons md-48\">volume_mute</i>\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":850,"y":300,"wires":[[]],"info":"  class=\"material-icons\"> volume_off"},{"id":"6eeb00d0.da35b","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"vol +  *","order":14,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button\" \n        data-buttontype=\"repeater\"\n        data-interval=\"200\"\n        data-topic=\"volume/plus\"\n        data-payload=\"volume/plus\"\n        aria-label=\"volume plus\"\n    >\n    <span class=\"fa fa-plus remote-icon\"> </span>\n   </md-button>\n</div>\n\n\n","storeOutMessages":true,"fwdInMessages":false,"templateScope":"local","x":730,"y":300,"wires":[[]],"info":"<div id=\"regular_plus\">\n   <md-button class=\"md-button remote-button\">\n      <i class=\"fa fa-plus remote-icon\"></i>\n   </md-button>\n</div>"},{"id":"c58bb5ab.ebc658","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"vol -  *","order":17,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button\"\n        data-buttontype=\"repeater\"\n        data-interval=\"200\"\n        data-topic=\"volume/minus\"\n        data-payload=\"volume/minus\"\n        aria-label=\"volume minus\"\n    >\n    <span style=\"color:{{msg.colour}}\" class=\"fa fa-minus remote-icon\"> </span>\n   </md-button>\n</div>\n\n","storeOutMessages":true,"fwdInMessages":false,"templateScope":"local","x":730,"y":340,"wires":[[]],"info":"<div id=\"regular_plus\">\n   <md-button class=\"md-button remote-button\">\n      <i class=\"fa fa-minus remote-icon\"></i>\n   </md-button>\n</div>\n"},{"id":"782351a7.0f3f6","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"ch list","order":18,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button\"\n    data-topic=\"channel/list\"\n    data-payload=\"list\"\n    aria-label=\"channel list\"\n   >\n      <i class=\"fa fa-list-alt remote-icon\"></i>\n   </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":850,"y":340,"wires":[[]]},{"id":"18ff979.4cf7768","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"Ch -","order":19,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button\" \n        data-topic=\"channel/down\"\n        data-payload=\"down\" \n        aria-label=\"channel down\"\n    >\n    <i class=\"fa fa-chevron-down remote-icon\"></i>\n   </md-button>\n</div>\n\n\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":970,"y":340,"wires":[[]]},{"id":"6b43ca3e.3b35a4","type":"inject","z":"e1dfad68.fee2a","name":"","topic":"mute","payload":"1","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":690,"y":440,"wires":[["c322da00.abb3a8"]]},{"id":"54ff0f5c.2703e","type":"inject","z":"e1dfad68.fee2a","name":"","topic":"mute","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":690,"y":480,"wires":[["c322da00.abb3a8"]]},{"id":"c322da00.abb3a8","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"script for all buttons with class remote-button","order":27,"width":"1","height":"1","format":"<div>\n<!--diliberately emtpy - only need the script below -->\n</div>\n\n<script>\n\n(function($scope) {\n//debugger\n\n    //cause a small delay while things load \n    //ideally this would be an init event or on all parts of document loaded\n    //(may not be necessary!)\n    setTimeout(function() {\n        //debugger\n        $scope.init();\n    },100);\n    \n    var BUTTON_CLASS = \".remote-button\";\n\n    /** \n     * Initialise all buttons with class BUTTON_CLASS\n    */\n    $scope.init = function () {\n        //debugger\n        console.log(\"$scope.init called. Adding event handlers to all buttons with class '\" + BUTTON_CLASS + \"'.\");\n        var clickButtons = $(BUTTON_CLASS + \":not([data-buttontype='repeater'])\") \n        clickButtons.click(function(e){\n            //debugger\n            var btn = $(this)\n            var type = btn.data(\"buttontype\");//get the button type from attribute data-buttontype=\"xxxxx\"\n            var topic = btn.data(\"topic\");//get the topic from attribute data-topic=\"xxxxx\"\n            var payload = btn.data(\"payload\");//get the payload from attribute data-payload=\"xxxxx\"\n            \n            if(type == \"toggle\"){\n                var newPayload = payload == 1 ? 0 : 1;\n                setButtonState(btn,newPayload)\n                $scope.send({\"topic\":topic,\"payload\":newPayload, \"event\": \"click\"})\n            } else {\n                $scope.send({\"topic\":topic,\"payload\":payload})\n            }\n        }); \n        \n\n        var repeatButtons = $(BUTTON_CLASS + \"[data-buttontype='repeater']\") \n        repeatButtons.on('mousedown touchstart',function(e) {\n            e.preventDefault();\n            e.stopPropagation();\n            console.log(e.type);//remove me after debugging\n            var btn = this;\n            var $btn = $(btn);\n            if(btn._intervalId) return; //already in operation\n            btn._topic = $btn.data(\"topic\");//get the topic from attribute data-topic=\"xxxxx\"\n            btn._payload = $btn.data(\"payload\");//get the payload from attribute data-payload=\"xxxxx\"\n            btn._interval = $btn.data(\"interval\");//get the desired repeat duration\n            if(isNumeric(btn._interval) == false || btn._interval < 1) btn._interval = 300;//prevent zero & non numeric timeout value\n            var max = $btn.data(\"max\");//get the max repeat count\n            if(isNumeric(max) && max > 0) \n                btn._max = parseInt(max);\n            else\n                btn._max = undefined;\n            btn._count = 1;\n            $scope.send({\"topic\":btn._topic,\"payload\":btn.payload,\"event\":\"down\", \"count\": btn._count})\n            btn._lastevent = \"down\";\n            //remove any existing timer\n            if(btn._intervalId){\n                clearInterval(btn._intervalId);\n                btn._intervalId = null;\n            }\n            //start the timer if conditions are ok\n            if(!btn._max || (btn._max && btn._count < btn._max)){\n                btn._intervalId = setInterval(function() {\n                    if(btn._max && btn._count >= btn._max){\n                        clearInterval(btn._intervalId);\n                        btn._intervalId = null;\n                        return;\n                    }                    \n                    btn._count = btn._count + 1;\n                    $scope.send({\"topic\":btn._topic,\"payload\":btn.payload,\"event\":\"down\", \"count\": btn._count})\n                },btn._interval); \n            }\n        }).on('mouseup blur focusout mouseout touchend',function(e) {\n            e.preventDefault();\n            e.stopPropagation();\n            console.log(e.type);//remove me after debugging\n            var btn = this;\n            var $btn = $(btn);\n            \n            //next, if data-fireonup == true, then fire up event\n            var sendUpEvent = $btn.data(\"fireonup\") == true;\n            if(sendUpEvent && btn._lastevent === \"down\"){\n                btn._lastevent = \"up\"\n                $scope.send({\"topic\":btn._topic,\"payload\":btn._payload,\"event\":\"up\"})\n            }\n            \n            //finally, if the timer id is still valid, clear it (stop repeater)\n            if(btn._intervalId){\n                clearInterval(btn._intervalId);//stop timer\n                btn._intervalId = null;//clear timer id\n            }\n        });\n           \n    };\n    \n    //watch for node-red msgs\n    $scope.$watch('msg', function(msg) {\n        //debugger\n        if(!msg){ //if no msg \n            console.log(\"$scope.$watch('msg', ...) - msg is empty\");\n            return;\n        }\n        if(!msg.topic){ //if no topic set found\n            console.log(\"msg.topic is empty - cannot match this to any button\")\n            return; //stop processing!\n        }\n\n        var buttonSelector =  BUTTON_CLASS + \"[data-topic='\" + msg.topic + \"']\" \n        var $btn = $(buttonSelector);//get the button\n        \n        if(!$btn.length){ //if no button found\n            console.log(buttonSelector + \" not found - cannot set state\")\n            return; //stop processing!\n        }\n        \n        if($btn.length > 1){ //if MORE than one button found\n            console.log(buttonSelector + \" found more than 1 button - is this intended? Do you have the same data-topic set on multiple buttons?\")\n        }\n        \n        //see if this is a command - if so, process the command\n        if(typeof msg.payload === \"object\" && msg.payload.command){\n            processCommand($btn, msg.payload)\n            return;\n        }        \n        \n        if($btn.data(\"buttontype\") === \"toggle\"){\n            if(msg.payload == \"1\"){\n                setButtonState($btn, 1);\n            } else if(msg.payload == \"0\"){\n                setButtonState($btn, 0);\n            } else {\n               console.log(\"Invalid toggle value in msg.payload, cannot set \" + buttonSelector + \". Ensure msg.payload is either 0 or 1\") \n            }\n        }\n\n    }); \n    \n    /** \n    * helper function to set the correct icon & update the \"data-payload\" memory \n    */\n    function setButtonState($btn, state){\n        \n        $btn.data(\"payload\", state);//set data-payload to new state value (used as a memory)\n        \n        //determine the opposite state\n        var oppositeState;\n        if(state == \"1\" || state === 1){\n            state = 1; //normalise to a number\n            oppositeState = 0;\n        } else {\n            state = 0; //normalise to a number\n            oppositeState = 1;\n        }\n        \n        var $icon = $btn.find(\"i\"); //get the <i> element\n        if(!$icon.length){\n            $icon = $btn.find(\"span\"); //get the <span> element instead!\n        }\n        if(!$icon.length){\n            console.log(\"<i> or <span> not found inside button - cant toggle the icon!\")\n            return;//exit this function - nothing to toggle!\n        }\n        \n        //get the old icon and new icon names\n        var oldIcon = $btn.data(\"icon\" + oppositeState); //get icon1 or icon2 depending on oppositeState\n        var newIcon = $btn.data(\"icon\" + state); //get icon1 or icon2 depending on newPayload\n       \n        //if we have newIcon and an actual DOM element ($icon) - update it...\n        if(newIcon && $icon.length){\n            if(newIcon.includes(\"fa-\")){ \n                $icon.removeClass(oldIcon).addClass(newIcon);  // fontawesome\n            } else { \n                $icon.text(newIcon); // MDI\n            }\n        }\n    }\n        \n    function processCommand($btn, payload){\n        //first check payload is correct format...\n        if(!payload || !payload.command || !payload.value){\n            console.log(\"Cannot process command. Expected a payload object with .command and .value. \")\n        }\n        var cmd = payload.command.trim();\n        switch(cmd){\n            case \"addClass\":\n                $btn.addClass(payload.value); //this calls the jquery function by name (specified in .command) on the $btn and passes in .value\n                break;\n            case \"toggleClass\":\n                $btn.toggleClass(payload.value); //this calls the jquery function by name (specified in .command) on the $btn and passes in .value\n                break;\n            case \"removeClass\":\n                $btn.removeClass(payload.value); //this calls the jquery function by name (specified in .command) on the $btn and passes in .value\n                break;\n            default:\n                console.log(\"command '\" + payload.command + \"' is not supported\")\n        }\n    }        \n        \n    /** \n    * helper function to determine a value is REALLY a number \n    */\n    function isNumeric(n){\n        if(n === \"\") return false;\n        if(n === true || n === false) return false;\n        return !isNaN(parseFloat(n)) && isFinite(n);\n    }\n   \n\n})(scope);\n</script>","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":850,"y":540,"wires":[["a90df8f.7eac108"]]},{"id":"a90df8f.7eac108","type":"debug","z":"e1dfad68.fee2a","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":910,"y":480,"wires":[]},{"id":"b5beb822.d8e4d8","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"lock","order":23,"width":"1","height":"1","format":"<div>\n   <md-button class=\"md-button remote-button bigger\" \n              data-payload=\"0\" \n              data-buttontype=\"toggle\"\n              data-topic=\"lock\"\n              data-icon0=\"fa-unlock\"\n              data-icon1=\"fa-lock\"\n              aria-label=\"lock\"\n              >\n      <span class=\"fa fa-unlock\" aria-hidden=\"true\"> </span>\n   </md-button>\n</div>","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":850,"y":420,"wires":[[]]},{"id":"d365b50.39acc48","type":"inject","z":"e1dfad68.fee2a","name":"addClass blinking, to lock","topic":"lock","payload":"{\"command\":\"addClass\",\"value\":\"blinking\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":730,"y":600,"wires":[["c322da00.abb3a8"]]},{"id":"fc9de415.5bf5d8","type":"inject","z":"e1dfad68.fee2a","name":"removeClass blinking, from lock","topic":"lock","payload":"{\"command\":\"removeClass\",\"value\":\"blinking\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":750,"y":640,"wires":[["c322da00.abb3a8"]]},{"id":"9c61b440.0fa398","type":"inject","z":"e1dfad68.fee2a","name":"toggleClass blinking, on lock","topic":"lock","payload":"{\"command\":\"toggleClass\",\"value\":\"blinking\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":740,"y":680,"wires":[["c322da00.abb3a8"]]},{"id":"a998da6c.f76f28","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"lock2 (red)","order":24,"width":"1","height":"1","format":"<div>\n   <md-button class=\"md-button remote-button bigger red\" \n              data-payload=\"0\" \n              data-buttontype=\"toggle\"\n              data-topic=\"lock2\"\n              data-icon0=\"fa-unlock\"\n              data-icon1=\"fa-lock\"\n              aria-label=\"lock\"\n              >\n      <span class=\"fa fa-unlock\" aria-hidden=\"true\"> </span>\n   </md-button>\n</div>","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":990,"y":420,"wires":[[]]},{"id":"4d9e7214.87ef8c","type":"inject","z":"e1dfad68.fee2a","name":"toggleClass blinking, on lock2","topic":"lock2","payload":"{\"command\":\"toggleClass\",\"value\":\"blinking\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":740,"y":740,"wires":[["c322da00.abb3a8"]]},{"id":"eaf12ef2.b4cf1","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"limited to 3 & fires on up :  vol +  *","order":25,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button\" \n        data-buttontype=\"repeater\"\n        data-interval=\"200\"\n        data-max=\"3\"\n        data-fireonup=\"true\"\n        data-topic=\"volume/plus2\"\n        data-payload=\"volume/plus2\"\n        aria-label=\"volume plus\"\n    >\n    <span class=\"fa fa-plus remote-icon\"> </span>\n   </md-button>\n</div>\n\n\n","storeOutMessages":true,"fwdInMessages":false,"templateScope":"local","x":1210,"y":420,"wires":[[]],"info":"<div id=\"regular_plus\">\n   <md-button class=\"md-button remote-button\">\n      <i class=\"fa fa-plus remote-icon\"></i>\n   </md-button>\n</div>"},{"id":"333eb8cb.c27dd8","type":"ui_template","z":"e1dfad68.fee2a","group":"a381801e.309e1","name":"limited to 1 & fires on up : vol -  *","order":26,"width":1,"height":1,"format":"<div>\n   <md-button class=\"md-button remote-button\"\n        data-buttontype=\"repeater\"\n        data-interval=\"200\"\n        data-max=\"1\"\n        data-fireonup=\"true\"\n        data-topic=\"volume/minus2\"\n        data-payload=\"volume/minus2\"\n        aria-label=\"volume minus\"\n    >\n    <span style=\"color:{{msg.colour}}\" class=\"fa fa-minus remote-icon\"> </span>\n   </md-button>\n</div>\n\n","storeOutMessages":true,"fwdInMessages":false,"templateScope":"local","x":1210,"y":460,"wires":[[]],"info":"<div id=\"regular_plus\">\n   <md-button class=\"md-button remote-button\">\n      <i class=\"fa fa-minus remote-icon\"></i>\n   </md-button>\n</div>\n"},{"id":"3da0cab9.8d22b6","type":"inject","z":"e1dfad68.fee2a","name":"toggleClass disabled, on home","topic":"home","payload":"{\"command\":\"toggleClass\",\"value\":\"disabled\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":750,"y":800,"wires":[["c322da00.abb3a8"]]},{"id":"be17d3d4.a92a6","type":"ui_group","z":"","name":"HOME","tab":"6af80cca.442cb4","order":1,"disp":true,"width":3,"collapse":false},{"id":"a381801e.309e1","type":"ui_group","z":"","name":"Full_Remote2","tab":"9e72c753.ebf048","order":3,"disp":false,"width":"3","collapse":false},{"id":"6af80cca.442cb4","type":"ui_tab","z":"","name":"TEST","icon":"dashboard","order":3,"disabled":false,"hidden":false},{"id":"9e72c753.ebf048","type":"ui_tab","z":"","name":"HDMI_TV_control","icon":"dashboard","order":7,"disabled":false,"hidden":false}]
1 Like

Yes, I was (in a round about way) saying - all good.

i have no more time now until later this evening (about 7pm UK time) - perhaps not until tomorrow. Sorry.

Post a summary reply before you finish up for the day. State any difficulties you have & I'll see what i can do later.

Again: Thanks @Steve-Mcl

So, would you mind looking at two blocks of code and find out why they are getting cross talk?

quickly - post those two nodes only

OK, sorry. I missed that while I was replying.

I don't want you to spoon feed me the code.

I'll download the new flow and see if I can get my head around it.

(Another problem is that all these flows are another tab on the machine. I am keeping them very separate just now while testing.)

But if they are covering all things, it is a bit pointless other than I can disable the other tabs.

It isn't that easy.

Don't fret. I'll play with the new code and see what mischief I can get up to in the mean time. :wink:

Until next time.

OK, speak later.

PS, dont forget to check the browsers console log - you might find a message that helps you (I did some console.log() entries to help you when you get duplicate topics & some other conditions)

Thanks again Steve.

But please remember: you are talking to someone who makes a rock look smart.

I honestly can't understand your examples.

I can get the home button to be locked. But that's about it.

I can't get the lock buttons blinking. Irrespective of what I do.

I admit I made a lot of hurt for myself, but that didn't change the fact that I can't get the button blinking.

I can't bridge the gap between what you are saying and how to actually use it.

The blinking is for the volume buttons (up and down).

As I can't even get the out of the box buttons flashing/blinking, I am not going to try another one.

The other thing that had me running in circles for 15 minutes is that the topic is used to determine which button is ........ attributed.

I was opening the inject node, seeing the { } and opening the line and pulling my hair out wondering what it was that determined which button was modified.

But as said: If I can't get the lock button blinking, I am wasting my time trying to get any other one working.

That ..... (F12) thingy.... It is a whole other bike this fish is trying to ride.

I can open it. "Look for errors." It is a page of squiggles to me. I wouldn't know an error on the page unless it (basically) jumped out and slapped me.

Just saying:
What you are showing me is great. It seems to have all these functions.

But you are showing an idiot magic and I can't work it out.
As I said, I can't make the connection between what you say and getting it done.

The structure is great. But I can't read it. I don't understand it and the more I look at it: it won't suddenly make sense. Well, not after 16 hours of being awake today.
And I hold little hope for tomorrow.

I never learnt this stuff. It is all Greek to me. Sure I can see patterns. But I have not seen these before.

Its 23:35 here now.

I'm off to bed.

Oh, sorry, one other thing:

Please put the nodes on a page: new/group1
Putting it on HDMI_TV_CONTROL/FULL_REMOTE (or what ever it is).... That loads right over the top of my existing flow and I spend 20 minutes cleaning up the dashboard and nodes.

Not really helping. Sorry.

Anyway, I hope I can make progress tomorrow, but I am not going to hold my breath.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.