Flow/node to fade light in and out

I'm looking for something that will output a value from 0 to 100 and then back down to 0 and repeat

Anyone done/used/seen such a thing?

This function should do what you want. It limits the slew rate of the payload of incoming messages. Set the slew rate that you want and how often you want it to send an output. Then feed it alternating 100 and 0 at the appropriate rate and it will ramp up and down. Or you could put feedback round it so that when the output gets to 0 then it sends back 100 and when it gets to 100 it sends back 0.
Some of those lets should be consts I see, and vars should be let or const. I wrote this years ago.

// Limits the slew rate of incoming payload values
// optionally sending intermediate values at specified rate
let maxRate = 100;         // max slew rate units/minute
let sendIntermediates = true;   // whether to send intermediate values
let period = 1000;          // period in millisecs to send new values (if sendIntermediates)
let jumpThreshold = 1000;   // if the step asked for is more that this then goes immediately to that value

var newValue = Number(msg.payload);
var timer = context.get('timer') || 0;
// check the value is  a number
if (!isNaN(newValue) && isFinite(newValue)) {
    var target = msg.payload;
    context.set('target', target);
    // set last value to new one if first time through
    var lastValue = context.get('lastValue');
    if (typeof lastValue == "undefined" || lastValue === null) {
        lastValue = newValue;
        context.set('lastValue', newValue);
    }
    // calc new value
    msg.payload = calcOutput();
    // stop the timer
    if (timer) {
        clearTimeout(timer);
        context.set('timer', null);
    }
    // restart it if required to send intermediate values
    if (sendIntermediates) {
        timer = setInterval(function(){
            // the timer has run down calculate next value and send it
            var newValue = calcOutput();
            if (newValue != context.get('lastValueSent')) {
                context.set('lastValueSent', newValue);
                node.send({payload: newValue});
            }
        },period);
        context.set('timer', timer);
    }
    context.set('lastValueSent', msg.payload);
} else {
    // payload is not a number so ignore it
    // also stop the timer as we don't know what to send any more
    if (timer) {
        clearTimeout(timer);
        context.set('timer', null);
    }
    msg = null;
}
return msg;

// determines the required output value
function calcOutput() {
    var lastValue = context.get('lastValue');
    var target = context.get('target');
    // set to current value if first time through or step > threshold
    if (typeof lastValue == "undefined" || lastValue === null) lastValue = target;
    var now = new Date();
    var lastTime = context.get('lastTime') || now;
    // limit value to last value +- rate * time
    var maxDelta = (now.getTime() - lastTime.getTime()) * maxRate / (60 * 1000);
    if (Math.abs(target - lastValue) > jumpThreshold) {
        // step > threshold so go there imediately
        newValue = target;
    } else if (target > lastValue) {
        newValue = Math.min( lastValue + maxDelta, target);
    } else {
        newValue = Math.max( lastValue - maxDelta, target);
    }
    context.set('lastValue', newValue);
    context.set('lastTime', now);   
    return newValue;
}

Why not have a node that generates a random number between 1 and 100, feed that into

Have that output go to a switch node that checks to see if the value is zero and if it is, send it back to the random node to generate a new starting value.

Here is an example flow:

[{"id":"27072ed2d53f0956","type":"debug","z":"efe0e47bf458ed51","name":"debug 3","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":620,"y":360,"wires":[]}]

You might want to check the unaddressed issues on that though.

Simple flow

[
    {
        "id": "86cdea15ac0cb709",
        "type": "inject",
        "z": "75789e9e9600370f",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 160,
        "y": 100,
        "wires": [
            [
                "155c7202dd3f9eaa"
            ]
        ]
    },
    {
        "id": "155c7202dd3f9eaa",
        "type": "change",
        "z": "75789e9e9600370f",
        "name": "0 - 100",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "[0..100]",
                "tot": "jsonata"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 300,
        "y": 100,
        "wires": [
            [
                "f8892244521a6d7b"
            ]
        ]
    },
    {
        "id": "f8892244521a6d7b",
        "type": "split",
        "z": "75789e9e9600370f",
        "name": "",
        "splt": "\\n",
        "spltType": "str",
        "arraySplt": 1,
        "arraySpltType": "len",
        "stream": false,
        "addname": "",
        "property": "payload",
        "x": 430,
        "y": 100,
        "wires": [
            [
                "b5a83cf5310dee5a"
            ]
        ]
    },
    {
        "id": "b5a83cf5310dee5a",
        "type": "delay",
        "z": "75789e9e9600370f",
        "name": "1/0.05",
        "pauseType": "rate",
        "timeout": "5",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "0.05",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "allowrate": false,
        "outputs": 1,
        "x": 550,
        "y": 100,
        "wires": [
            [
                "74594c9574bbf6a1",
                "6ec212ee908a5006"
            ]
        ]
    },
    {
        "id": "11cd68443ce6756f",
        "type": "debug",
        "z": "75789e9e9600370f",
        "name": "debug 26",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 1200,
        "y": 160,
        "wires": []
    },
    {
        "id": "ea9e71f95e79af58",
        "type": "change",
        "z": "75789e9e9600370f",
        "name": "0 - 100 - reverse",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "$reverse([0..100])",
                "tot": "jsonata"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 840,
        "y": 100,
        "wires": [
            [
                "16b1183d25833b43"
            ]
        ]
    },
    {
        "id": "16b1183d25833b43",
        "type": "split",
        "z": "75789e9e9600370f",
        "name": "",
        "splt": "\\n",
        "spltType": "str",
        "arraySplt": 1,
        "arraySpltType": "len",
        "stream": false,
        "addname": "",
        "property": "payload",
        "x": 990,
        "y": 100,
        "wires": [
            [
                "67347edf52b98807"
            ]
        ]
    },
    {
        "id": "67347edf52b98807",
        "type": "delay",
        "z": "75789e9e9600370f",
        "name": "1/0.05",
        "pauseType": "rate",
        "timeout": "5",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "0.05",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "allowrate": false,
        "outputs": 1,
        "x": 1110,
        "y": 100,
        "wires": [
            [
                "11cd68443ce6756f"
            ]
        ]
    },
    {
        "id": "74594c9574bbf6a1",
        "type": "debug",
        "z": "75789e9e9600370f",
        "name": "debug 25",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 720,
        "y": 160,
        "wires": []
    },
    {
        "id": "6ec212ee908a5006",
        "type": "switch",
        "z": "75789e9e9600370f",
        "name": "100 ?",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "100",
                "vt": "num"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 690,
        "y": 100,
        "wires": [
            [
                "ea9e71f95e79af58"
            ]
        ]
    }
]

you can put a switch node at the end: if payload 0, connect it back to the first 0-100 node. Set the inject node to 'inject once' and enjoy forever.

Reducing the number of nodes involved (and the maximum value to 10) ...

[{"id":"b52f663826069a7b","type":"change","z":"0e81d37389e6ac14","name":"","rules":[{"t":"set","p":"increment","pt":"msg","to":"payload >= 10 ? -1 : payload <= 0 ? 1 : increment","tot":"jsonata"},{"t":"set","p":"payload","pt":"msg","to":"payload + increment","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":440,"y":100,"wires":[["7be2a7d5918696f4","30b191f7e43e028e"]]},{"id":"30b191f7e43e028e","type":"delay","z":"0e81d37389e6ac14","name":"","pauseType":"rate","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":270,"y":100,"wires":[["b52f663826069a7b"]]},{"id":"7be2a7d5918696f4","type":"debug","z":"0e81d37389e6ac14","name":"debug 24","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":620,"y":100,"wires":[]},{"id":"21f71ecf937cdbc1","type":"inject","z":"0e81d37389e6ac14","name":"Start","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"0","payloadType":"num","x":110,"y":100,"wires":[["30b191f7e43e028e"]]}]

It doesn't have a stop button though - maybe add a switch node testing a context variable?

1 Like

Or maybe this node ?

Thanks for all the replies and suggestions

Currently trying out a modification of @bakman2 and I'm stepping in 10s

[{"id":"f672f1b835ac0581","type":"link out","z":"520ed7a87fb5cf51","name":"dim out","mode":"link","links":["e7c27a62a6199b7e"],"x":885,"y":520,"wires":[]},{"id":"96997ade1f740c23","type":"inject","z":"520ed7a87fb5cf51","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"0","payloadType":"num","x":570,"y":520,"wires":[["f3d0931cc2cb821d","2571c34137f60f80"]]},{"id":"86cdea15ac0cb709","type":"inject","z":"520ed7a87fb5cf51","name":"","props":[{"p":"payload"},{"p":"delay","v":"400","vt":"num"},{"p":"rate","v":"delay","vt":"msg"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":110,"y":500,"wires":[["155c7202dd3f9eaa"]]},{"id":"155c7202dd3f9eaa","type":"change","z":"520ed7a87fb5cf51","name":"10 - 100 - 21","rules":[{"t":"set","p":"payload","pt":"msg","to":"[10,20,30,40,50,60,70,80,90,100,90,80,70,60,50,40,30,21]","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":130,"y":560,"wires":[["f8892244521a6d7b"]]},{"id":"f8892244521a6d7b","type":"split","z":"520ed7a87fb5cf51","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","property":"payload","x":270,"y":560,"wires":[["b5a83cf5310dee5a"]]},{"id":"b5a83cf5310dee5a","type":"delay","z":"520ed7a87fb5cf51","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":true,"outputs":1,"x":410,"y":560,"wires":[["2571c34137f60f80","09ec81183b363c25"]]},{"id":"09ec81183b363c25","type":"switch","z":"520ed7a87fb5cf51","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"21","vt":"num"}],"checkall":"true","repair":false,"outputs":1,"x":560,"y":590,"wires":[["b4135e0886558a1f"]]},{"id":"ddb75aba4855a69e","type":"debug","z":"520ed7a87fb5cf51","name":"debug 13","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1010,"y":560,"wires":[]},{"id":"4a9cb5281aba5bb5","type":"template","z":"520ed7a87fb5cf51","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"id\":1,\"method\":\"setState\",\"params\":{\"dimming\":{{{payload}}}}}","output":"str","x":780,"y":560,"wires":[["ddb75aba4855a69e","f672f1b835ac0581"]]},{"id":"2571c34137f60f80","type":"junction","z":"520ed7a87fb5cf51","x":660,"y":560,"wires":[["4a9cb5281aba5bb5","f3d0931cc2cb821d"]]},{"id":"b4135e0886558a1f","type":"junction","z":"520ed7a87fb5cf51","x":40,"y":590,"wires":[["155c7202dd3f9eaa"]]}]

Note - turns out the lights only dim down to 10 hence the 10-100-21 sequence
[edit] flow editied to stop msg queue at delay node just growing and growing by changing last value to 21 and only restarting when that value is generated