npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@lnowakowski/node-red-contrib-shutter

v1.0.2

Published

Roller shutter control node with position tracking, timed movement, and manual override detection

Downloads

520

Readme

node-red-contrib-shutter

Node-RED Node.js License: MIT

A Node-RED node for controlling roller shutters (blinds) via two relay outputs (up/down), with time-based position tracking, percentage-based targeting, and live status reporting.

Features

  • Two-relay motor control (separate up/down relays)
  • Time-based position estimation (no hardware feedback required)
  • Percentage-based positioning (move to 0–100%)
  • Skips movement when already at the requested position
  • Live position reporting every 200ms while moving
  • State coordination across multiple shutters (flow or global context)
  • "Unlimited" mode for calibration
  • Configurable relay payloads (number, string, or boolean)
  • Device, duration, and identifier support dynamic sources (str/num, msg, flow, global, env)
  • No external dependencies

Installation

Install via the Node-RED Manage Palette menu, or from your Node-RED user directory:

npm install @lnowakowski/node-red-contrib-shutter

Restart Node-RED after installation.

Configuration

| Property | Type | Default | Description | |----------|------|---------|-------------| | Identifier | string | (required) | Unique name for this shutter (used as its key in the States context) | | Device up | string | (required) | Relay device identifier for the "open" direction | | Device down | string | (required) | Relay device identifier for the "close" direction | | Duration up | number | 1000 | Time in milliseconds for a full open cycle | | Duration down | number | 1000 | Time in milliseconds for a full close cycle | | Payload on | number | string | bool | 1 | Value sent on output 1 to energize the relay | | Payload off | number | string | bool | 0 | Value sent on output 1 to release the relay | | States | flow | global | shutters (flow) | Context variable holding the persistent position map | | Runtime | flow | global | shutters_runtime (flow) | Context variable holding runtime coordination state | | Logging | boolean | false | Enable debug logging to Node-RED debug sidebar |

The Device and Duration properties support dynamic value sources via typed inputs:

| Source | Description | |--------|-------------| | str / num | Static string or number value | | msg | Read from a message property | | flow | Read from flow context | | global | Read from global context | | env | Read from an environment variable |

The Identifier is a plain string. The Payload on / off values accept a static number, string, or boolean. States and Runtime are each selected as a flow or global context variable.

How It Works

                   ┌──────────────────────────────────┐
                   │            shutter               │
    payload:75  ──▶│  Status: opening (42% open)      │──▶ Output 1: relay cmd
                   │                                  │──▶ Output 2: status
                   └──────────────────────────────────┘

Position Tracking

Since typical roller shutters don't provide position feedback, this node estimates position by timing:

  • Position 0 = fully closed
  • Position 1 = fully open
  • The node tracks elapsed time vs. configured duration to calculate current position

Movement Modes

Position mode

Send msg.payload as an integer percentage (0–100):

{ "payload": 75 }

The node calculates the required direction and movement time automatically, and does nothing if the shutter is already at the requested position. Non-integer payloads are ignored with a warning.

Status query

Send a message with get_status property (any value) to get current status without moving:

{ "get_status": true }

Interrupting a movement

If a command arrives while the shutter is already moving, the current relay is turned off and the estimated position is updated based on elapsed time. Send a new target position afterwards to continue moving.

Outputs

Output 1 — Relay Command

| Property | Type | Description | |----------|------|-------------| | msg.topic | string | Device identifier (up or down relay) | | msg.payload | number | string | bool | Configurable Payload on (energize) / Payload off (release) values, default 1 / 0 | | msg.info | string | e.g. "device_up=true" |

Output 2 — Status

| Property | Type | Description | |----------|------|-------------| | msg.payload.status | string | "opening", "closing", "closed", "fully_opened", or "opened" | | msg.payload.position | number | Current position 0 (closed) to 1 (fully open) |

While moving, status messages are emitted every 200ms with live position estimates.

Context

The node maintains shared state for coordination across multiple shutter nodes, stored in two context variables configured per node: States (persistent position map) and Runtime (runtime coordination state). Each is a flow or global context variable. Nodes that point at the same variables coordinate with each other.

States (default shutters, persistent)

Position map for all shutters:

{
    "living_room": { "position": 0.75, "changed": 1700000000000 },
    "bedroom": { "position": 0, "changed": 1700000001000 }
}

Runtime (default shutters_runtime)

Runtime coordination state:

{
    "unlimited": false,
    "active": ["relay_up_1"]
}

Set unlimited: true to disable position limits (useful for calibration or shutters without end stops).

Example Flow

An example flow is included in the examples/ folder and available in the Node-RED editor under ImportExamples@lnowakowski/node-red-contrib-shutter.

[
    { "id": "i1", "type": "inject", "payload": "100", "payloadType": "num", "wires": [["s1"]] },
    { "id": "i2", "type": "inject", "payload": "50", "payloadType": "num", "wires": [["s1"]] },
    { "id": "s1", "type": "shutter", "identifier": "living_room", "deviceUp": "relay_up_1", "deviceDown": "relay_down_1", "durationUp": "20000", "durationDown": "18000", "wires": [["mqtt1"], ["debug1"]] },
    { "id": "mqtt1", "type": "mqtt out", "topic": "" },
    { "id": "debug1", "type": "debug", "complete": "payload" }
]

License

MIT

Links