Giter Site home page Giter Site logo

node-red-contrib-dynamic-dimmer's Introduction

node-red-contrib-dynamic-dimmer

Coveralls github platform

The Dynamic Dimmer node for Node-RED was build to mimic the behavior of a physical dimmer switch. A typical use case for this node is the dimming of light bulbs (e.g. Ikea TrΓ₯dfri bulbs) to a given brightness. In general, it allows a linear animation/easing of a value over a certain time frame.

Credits

How to use this node

Similar to a physical dimmer switch, you can specify the desired brightness, or any other parameter, with a input (msg.payload) between [0,1]. The node will then start to emit a series of values in a certain interval until the expected value is reached.

Node configuration

  • Minimum / Maximum value: the range of the the output values
  • Steps: the number of steps between the min and max
  • Event interval: the interval between the steps in ms

Example

Lets assume the following node configuration:

  • Minimum / Maximum value: 0 / 100
  • Steps: 10
  • Event interval: 200ms

When the node receives in the initial state on the input a message with e.g. msg.payload = 0.5 the node will emit 10, 20, 30, 40 and 50 on the output (to msg.payload) in a 200ms interval.

Advanced usage

Lets imagine that we want to make the dim speed of a light bulb depending on the time of the day. This use case would require to modify the node configuration (e.g. the event interval) at runtime. The dynamic dimmer node supports another input format to enable runtime modifications of the node config:

{
    "msg": {
        "payload":{
            "target": 0.5,
            "start": 0.1,
            "command": "DIM",
            "config": {
                "eventInterval": 600,
                "steps": 10,
                "minValue": 0,
                "maxValue": 100
            }
        }
    }
}

Please note that partial configuration updates are supported. Hence, you only need to provide the parameters which should be modified.

The command property

In general, the process of dimming has a very async behavior because one input event triggers a series of output events. For more control of ongoing operations the following commands were introduced:

  • DIM - this is the default operation and instructs the node to reach the target value. If there is already a dimming operation in progress, the node will switch to the new dim target value. The optional parameter start can be provided with values [0,1] to set the starting point of the dimming operation.
  • PAUSE - pause an ongoing dim operation (target should not be set)
  • SET - skips the dim operation and sets the dimmer immediately to the target value.
  • RESET - resets the node to it's initial configuration and sets the output to the minValue. If additional config properties are sent, it will merge them with the initial configuration.

Contribute

In case you want to improve this project please create a PR with your changes. Please make sure to add unit tests to verify your changes.

Local development and testing setup

Development scripts:

  • npm run build - obviously builds/transpiles the project
  • npm run test - runs the jest tests
  • npm run dev - at the time of writing a hot reloading of code changes is not supported by Node-RED. Hence, to test the node in a Node-RED instance npm run dev can be used to build the project and restart the docker container.

The node can be installed in the local Node-RED instance as follows:

# spin up node red
docker-compose up
mkdir data
# get the container id 
docker ps
# install the node in the container
docker exec -it <CONTAINER_ID> /bin/bash -c "cd /data && npm install ./node-red-contrib-dynamic-dimmer"

node-red-contrib-dynamic-dimmer's People

Contributors

alex6o avatar dependabot[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

node-red-contrib-dynamic-dimmer's Issues

Feature request: Supply initial state

Hi,

I am using the dynamic-dimmer node for some of my more complicated light setups. Since I am only doing some controls through the dimmers and others directly, I am missing an option to supply an initial state to the node.

For instance, I want the temperature of my lights to change slowly to a warmer tone in the evening. If they were off before I can just set the temperature and then slow increase the brightness. However, if they were on before through another routine, they already have a specific tone set - so I would need the dimmer just to change the value from 0.7 to 0.3 for example.
However, when supplying the target through a payload the dimmer always starts at its minium value from the node configuration - which would be zero.

As far as I understand the documentation there is currently no way to supply an inital starting value...

Endless loop for pause command

Hi.

I have an flow which dimm a light over a period of 20minutes and add a switch after every dimm, to check if this dimm maybe should abort (manual switch the light of).

But when the switch send the PAUSE command to the dimmer, the dimmer again sends an output and the check is done again, the paus command also, and there is an endless loop.

I expect that after the PAUSE the dimmer stop working.

Here is a test flow I created, with the endlesse loop (1), a PAUSE from a different node with the dimm AFTER the pause (2) and a solution, but with 3 extra notes to create an additional flag and check this to exit the loop, which is not nice (3)

[{"id":"3c55e479d4d2c0dd","type":"tab","label":"Test Dimming","disabled":false,"info":"","env":[]},{"id":"56b6b1d681495d53","type":"dynamic-dimmer","z":"3c55e479d4d2c0dd","name":"10 loop","eventInterval":"1","steps":"10","minValue":0,"maxValue":"10","x":400,"y":180,"wires":[["6ec913cb91f0fb39","c7e5ebaeb6780f9d"]]},{"id":"6ec913cb91f0fb39","type":"change","z":"3c55e479d4d2c0dd","name":"Stop Dimmer","rules":[{"t":"set","p":"payload","pt":"msg","to":"{ \"command\": \"PAUSE\"}","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":410,"y":260,"wires":[["56b6b1d681495d53","c7e5ebaeb6780f9d"]]},{"id":"c7e5ebaeb6780f9d","type":"debug","z":"3c55e479d4d2c0dd","name":"debug","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":590,"y":180,"wires":[]},{"id":"42a67202f968a414","type":"inject","z":"3c55e479d4d2c0dd","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":265,"y":180,"wires":[["56b6b1d681495d53"]],"l":false},{"id":"9ef34ba8d8ff9504","type":"dynamic-dimmer","z":"3c55e479d4d2c0dd","name":"10 loop","eventInterval":"1000","steps":"10","minValue":0,"maxValue":"10","x":440,"y":380,"wires":[["e1d1ceaea0377240"]]},{"id":"aec9ed84088e7937","type":"change","z":"3c55e479d4d2c0dd","name":"Stop Dimmer","rules":[{"t":"set","p":"payload","pt":"msg","to":"{ \"command\": \"PAUSE\"}","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":390,"y":440,"wires":[["9ef34ba8d8ff9504","e1d1ceaea0377240"]]},{"id":"e1d1ceaea0377240","type":"debug","z":"3c55e479d4d2c0dd","name":"debug","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":610,"y":420,"wires":[]},{"id":"07e00611fcebf0ed","type":"inject","z":"3c55e479d4d2c0dd","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":275,"y":380,"wires":[["9ef34ba8d8ff9504"]],"l":false},{"id":"ed0662860a99a52c","type":"inject","z":"3c55e479d4d2c0dd","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":275,"y":440,"wires":[["aec9ed84088e7937"]],"l":false},{"id":"6199f535b3cc235f","type":"comment","z":"3c55e479d4d2c0dd","name":"endless loop with same payload","info":"","x":350,"y":120,"wires":[]},{"id":"282da34114912f2e","type":"comment","z":"3c55e479d4d2c0dd","name":"works, but sends a dimm outout after PAUSE","info":"works, but sends a dimm outout after PAUSE","x":410,"y":340,"wires":[]},{"id":"daaa28a3a08afe42","type":"dynamic-dimmer","z":"3c55e479d4d2c0dd","name":"10 loop","eventInterval":"1000","steps":"10","minValue":0,"maxValue":"10","x":420,"y":580,"wires":[["b8c6575a7618f884","1913396c6dc2588b"]]},{"id":"cac340583d29debc","type":"change","z":"3c55e479d4d2c0dd","name":"Stop Dimmer","rules":[{"t":"set","p":"payload","pt":"msg","to":"{ \"command\": \"PAUSE\"}","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":350,"y":680,"wires":[["0c97b3e47eefbc73"]]},{"id":"b8c6575a7618f884","type":"debug","z":"3c55e479d4d2c0dd","name":"debug","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":790,"y":640,"wires":[]},{"id":"b17fe25ce3374d26","type":"inject","z":"3c55e479d4d2c0dd","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":285,"y":580,"wires":[["daaa28a3a08afe42"]],"l":false},{"id":"3c5ee22763e4340d","type":"comment","z":"3c55e479d4d2c0dd","name":"loop with added marker","info":"","x":340,"y":520,"wires":[]},{"id":"0c97b3e47eefbc73","type":"change","z":"3c55e479d4d2c0dd","name":"add marker","rules":[{"t":"set","p":"stop_dimming","pt":"msg","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":550,"y":680,"wires":[["daaa28a3a08afe42","b8c6575a7618f884"]]},{"id":"1913396c6dc2588b","type":"switch","z":"3c55e479d4d2c0dd","name":"check marker","property":"stop_dimming","propertyType":"msg","rules":[{"t":"true"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":660,"y":580,"wires":[[],["cac340583d29debc"]]}]

Feature Request - ability to pass through topic and other values

The output message at the moment is very minimal. I am trying to maximise reuse of nodes by making things parameter-driven. At the moment the dynamic dimmer breaks the chain as the output message doesn't contain any kind of reference back to the source. Would it be possible to allow the topic on the output message to be a copy of the topic from the input, or in some way user-settable? Or allow some user-defined reference in the input payload to be copied to the output?

Feature Request - Enable setting of current value to max

I have started to use this node all over my workflows, it is a rather handy tool, instead of playing with loops in NR. It does need a function to similar to RESET, say SET, which can be used to set the current value of the node. Need this to keep the value updated, in-case light is manually turned on by someone, turn off is covered by RESET.

25 Steps results in 96% or 4% brightness!

When I use 25 steps, the resultant brightness stops at 96% or 4% depending upon 1 or 0 as input.

[{"id":"bcb0e7be.6026d8","type":"dynamic-dimmer","z":"f871eeaa.558fa","name":"TheaterDimmer","eventInterval":"400","steps":"25","minValue":0,"maxValue":"100","x":740,"y":740,"wires":[["5e3d35a8.f394cc","adf45974.269498"]]}]

Is this a bug or is it me?

Hey!

thank you for making this node!

i'm trying to get a fan to dim to 0

i have my fan properties set to: {"percentage":"{{payload}}"}
that works when i use you sample buttons to inject 0 or 100%

but when i make a function with: msg.payload = 0;

it only works when i use the button to first set it to 100 then it works 1x

this is my flow for the fan in the bathroom:

[ { "id": "9ac1d73af9509270", "type": "tab", "label": "Badkamer", "disabled": false, "info": "", "env": [] }, { "id": "32c50907.2cde1e", "type": "stoptimer", "z": "9ac1d73af9509270", "duration": "5", "units": "Minute", "payloadtype": "num", "payloadval": "0", "name": "Wait 5 Minutes", "x": 840, "y": 120, "wires": [ [ "cdfbf50a.3eecc8" ], [] ] }, { "id": "cdfbf50a.3eecc8", "type": "api-current-state", "z": "9ac1d73af9509270", "name": "High Humidity?", "server": "51041573183f2685", "version": 3, "outputs": 2, "halt_if": "65", "halt_if_type": "num", "halt_if_compare": "gt", "entity_id": "sensor.tado_badkamer_humidity", "state_type": "str", "blockInputOverrides": false, "outputProperties": [ { "property": "payload", "propertyType": "msg", "value": "", "valueType": "entityState" }, { "property": "data", "propertyType": "msg", "value": "", "valueType": "entity" } ], "for": 0, "forType": "num", "forUnits": "minutes", "x": 320, "y": 220, "wires": [ [ "7e082343.a7f13c" ], [ "187c858b7dbd7e72" ] ] }, { "id": "c5c47556.bb3f8", "type": "api-call-service", "z": "9ac1d73af9509270", "name": "Turn off fan", "server": "51041573183f2685", "version": 5, "debugenabled": false, "domain": "fan", "service": "set_percentage", "areaId": [], "deviceId": [], "entityId": [ "fan.nrg_itho_3564_fan" ], "data": "{\"percentage\":\"{{payload}}\"}", "dataType": "json", "mergeContext": "", "mustacheAltTags": false, "outputProperties": [], "queue": "none", "output_location": "", "output_location_type": "none", "x": 830, "y": 460, "wires": [ [ "c982004.28e78" ] ] }, { "id": "7e082343.a7f13c", "type": "stoptimer", "z": "9ac1d73af9509270", "duration": "1", "units": "Minute", "payloadtype": "num", "payloadval": "0", "name": "Wait 1 min", "x": 830, "y": 180, "wires": [ [ "cdfbf50a.3eecc8" ], [] ] }, { "id": "43927abd.48ee2c", "type": "server-state-changed", "z": "9ac1d73af9509270", "name": "High Humidity", "server": "51041573183f2685", "version": 4, "exposeToHomeAssistant": false, "haConfig": [ { "property": "name", "value": "" }, { "property": "icon", "value": "" } ], "entityidfilter": "sensor.tado_badkamer_humidity", "entityidfiltertype": "exact", "outputinitially": false, "state_type": "str", "haltifstate": "70", "halt_if_type": "num", "halt_if_compare": "gt", "outputs": 2, "output_only_on_state_change": true, "for": "0", "forType": "num", "forUnits": "minutes", "ignorePrevStateNull": false, "ignorePrevStateUnknown": false, "ignorePrevStateUnavailable": false, "ignoreCurrentStateUnknown": false, "ignoreCurrentStateUnavailable": false, "outputProperties": [ { "property": "payload", "propertyType": "msg", "value": "", "valueType": "entityState" }, { "property": "data", "propertyType": "msg", "value": "", "valueType": "eventData" }, { "property": "topic", "propertyType": "msg", "value": "", "valueType": "triggerId" } ], "x": 130, "y": 100, "wires": [ [ "595cf5bf.3e5e34" ], [] ] }, { "id": "595cf5bf.3e5e34", "type": "api-call-service", "z": "9ac1d73af9509270", "name": "Turn on fan", "server": "51041573183f2685", "version": 5, "debugenabled": false, "domain": "fan", "service": "set_percentage", "areaId": [], "deviceId": [], "entityId": [ "fan.nrg_itho_3564_fan" ], "data": "{\"percentage\":100}", "dataType": "json", "mergeContext": "", "mustacheAltTags": false, "outputProperties": [], "queue": "none", "output_location": "", "output_location_type": "none", "x": 350, "y": 100, "wires": [ [ "32c50907.2cde1e" ] ] }, { "id": "07b49201e4ae59d4", "type": "inject", "z": "9ac1d73af9509270", "name": "", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 100, "y": 260, "wires": [ [ "cdfbf50a.3eecc8" ] ] }, { "id": "bd25fca4.82f73", "type": "dynamic-dimmer", "z": "9ac1d73af9509270", "name": "", "eventInterval": "2000", "steps": 10, "minValue": "20", "maxValue": 100, "x": 630, "y": 460, "wires": [ [ "c5c47556.bb3f8" ] ] }, { "id": "c982004.28e78", "type": "debug", "z": "9ac1d73af9509270", "name": "output", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "statusVal": "", "statusType": "auto", "x": 830, "y": 400, "wires": [] }, { "id": "4f1e61c5.be096", "type": "inject", "z": "9ac1d73af9509270", "name": "simple dim 100%", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "1.0", "payloadType": "num", "x": 150, "y": 540, "wires": [ [ "bd25fca4.82f73" ] ] }, { "id": "1b13342.fc3a9cc", "type": "inject", "z": "9ac1d73af9509270", "name": "simple dim 0%", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "0", "payloadType": "num", "x": 160, "y": 480, "wires": [ [ "bd25fca4.82f73" ] ] }, { "id": "187c858b7dbd7e72", "type": "function", "z": "9ac1d73af9509270", "name": "Fan Off", "func": "msg.payload = 20;\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 460, "y": 340, "wires": [ [ "bd25fca4.82f73" ] ] }, { "id": "51041573183f2685", "type": "server", "name": "Home Assistant", "version": 2, "addon": false, "rejectUnauthorizedCerts": true, "ha_boolean": "y|yes|true|on|home|open", "connectionDelay": true, "cacheJson": true, "heartbeat": false, "heartbeatInterval": "30" } ]

is it me? or is something wrong?

Dim operations sometimes reset to 0 then dim to the target

I'm not sure how to debug this but playing around with a testing setup and some triggers sending a number of say, 0.35 to the dimmer, when the previous target was 1.00 will result in it starting from 0 and then counting up to the target amount. Other times it will behave how I'd expect where it dims from 1.00 down to .35.

Any ideas on how to debug this?

flow stopped due to missing node types

Hey!

First of all thanks for creating this node!

The current version I have installed is 1.1.0 and I installed it via the palette.
My flow is not deploying correctly with error "flow stopped due to missing node types: dynamic-dimmer".

Any clue what is wrong here? Bug or problem on my side?

Thanks in advance

Option for rounding output

Hi, I was thinking of contributing to this node, but I've never worked on any before and I am thinking this might work best as a suggestion for improvement, since I can't imagine this being particularly hard.

I am wondering if it would be possible to have an option for automatically rounding the output, since some other nodes only take ints

post flow

I'm confused as to how to replicate your advanced inject node that you demo in the gif. will you post that flow so that it can be imported?

thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.