Free NodeRed Plugin Implementation

My client (not Node-RED related) is downsizing, and I find myself with some free time on my hands over the next few weeks while I sort out what's next.

If anyone has an idea for a Node-RED integration or plugin they'd like developed or revised — feel free to pop me a message and I'll take a look. Happy to help where I can, no charge. Just bear in mind this is subject to my availability as things pick up.

If nobody else comes up with something better ...

Many years ago, I wrote node-red-contrib-moment to make date/time formatting and timezone handling easier. However, that is now well out-of-date and given that we are on the cusp of things supporting the new Temporal API, it might be really helpful to have a Temporal node to replace the old Moment node. Possibly with some help from the INTL API for locale-formatting.

There is, I believe, a pollyfill for Temporal. So a node could be written now using the pollyfill and later simply have the pollyfill removed once Node.js v26+ becomes the baseline.

Just a thought anyway. :smiley:

Love the attitude here @TacticalNudge :folded_hands:

If you want to get your hands on some Node Development, look at the Developing Nodes category, as there maybe some folk looking for reviews / help in their projects.

Including moving Julians moment Node away... from... well.... moment :rofl:
And lets not forget BETA Testing the cr*p out of NR5 :smile:

DB2 also springs to mind, which I think the team need help on

I have that sprinkled all over my flows!! Slowly moving to date.js and/or JSONATA using the moment library. Would love an easier/more permanent solution.

:smiley:

Even I rarely use it these days. But then, as I've now gotten rather more familiar with things like INTL, I'll tend to use that for specific formatted outputs. Most dates/times I keep in UTC/GMT/Zulu time anyway so I rarely have to deal direct with timezones. I very rarely might use JSONata's $moment, but I can't ever remember the parameters now so I can't often be bothered.

In fact, I mostly will only deal with date/time formats in the browser and I made sure that I have a uibuilder.formatDate(date, pattern, locale = navigator.language) function available in UIBUILDER's client library for easy use.


The client library also has formatNumber(value, decimalPlaces, intl, opts)

And I've snuck a simpler dp(inp, dp = 1, int = 'en-GB') function into RED.util.uib because formatting numbers to a specific set of decimal places with JavaScript is a pain and you don't always want to have to break into the relatively slow JSONata just to do something like that.

I threw a few hours of effort behind the idea and used your original plugin as a bit of inspiration.

It's built using a framework I've been toying with on the side that allows nodes and services to be built in TypeScript, taking a lot of the boilerplate effort out of the process. I specifically stayed away from moment.js, and used the Temporal polyfill and the Intl API as suggested; both worked really well for this.

A couple of notable improvements over the original: named formats are now centralized in a single backend section, which should make maintenance and additions a lot simpler. I've also introduced a small expression language for modifying temporal values, for example, +1y-2M+4d15m translates to "add one year, subtract 2 months, add 4 days, add 15 minutes". It's compact but readable once you get the hang of it.

Everything should be documented in the node's help page.
@theotherwillembotha/node-red-temporal

Happy to hear any feedback or ideas!

Could you point me at the team? I had a look at what is currently in the node repo and there are about 5 different DB2 plugins by the looks of it- with the latest one being about 2 years old. I haven't had the opportunity to work on DB2 yet, but there is always a first time.

Cool. I'll take a look as soon as I can.

It is built around VueJS and Vuetify front-end frameworks so you would need an understanding of those.

What are your front-end skills like? There is plenty of opportunities for uibuilder-related work too. :smiley:

The main Dashboard V2 repo is here

Feel free to have a look at the issues list.

Just found time to install. Getting a LOT of output on startup:

Welcome to Node-RED
===================

18 May 13:35:12 - [info] Node-RED version: v4.1.10
18 May 13:35:12 - [info] Node.js  version: v24.14.1
18 May 13:35:12 - [info] Windows_NT 10.0.26200 x64 LE
18 May 13:35:12 - [info] Loading palette nodes
18 May 13:35:13 - [info] Node-RED Contrib Theme Collection version: v4.1.1
Deploying instance of: @theotherwillembotha/loggerservice
Deploying instance of: @theotherwillembotha/metricsservice
Deploying instance of: @theotherwillembotha/settingsservice
Deploying instance of: @theotherwillembotha/webhookserverservice
Deploying instance of: @theotherwillembotha/nodetypeservice
Deploying instance of: @theotherwillembotha/temporalservice
NodeTypeService installed!
registering node DelegatedConfigReferenceNode
registered node DelegatedConfigReferenceNode
registering node ConsoleLoggerConfigNode
registered node ConsoleLoggerConfigNode
registering node RestLoggerConfigNode
registered node RestLoggerConfigNode
registering node LokiLoggerConfigNode
registered node LokiLoggerConfigNode
registering node MetricsConfigNode
registered node MetricsConfigNode
registering node CounterMetricConfigNode
registered node CounterMetricConfigNode
registering node GaugeMetricConfigNode
registered node GaugeMetricConfigNode
registering node TimerMetricConfigNode
registered node TimerMetricConfigNode
registering node WebhookServerConfigNode
registered node WebhookServerConfigNode
NodeTypeService installed!
registering node TemporalTransformNode
registered node TemporalTransformNode
8 May 13:35:21 - [info] node-red-contrib-telegrambot version: v17.4.5
18 May 13:35:23 - [info] Worldmap version: 5.7.0
18 May 13:35:23 - [info] Dashboard version 3.6.6 started at /nr/ui
18 May 13:35:23 - [info] Settings file  : D:\src\nr\data\settings.js
18 May 13:35:23 - [info] HTTP Static    : D:\src\nr\data\public > /
18 May 13:35:23 - [info] Context store  : 'default' [module=memory]
18 May 13:35:23 - [info] Context store  : 'file' [module=localfilesystem]
18 May 13:35:23 - [info] User directory : D:\src\nr\data
18 May 13:35:23 - [info] Projects directory: D:\src\nr\data\projects
18 May 13:35:23 - [info] Server now running at https://127.0.0.1:1880/red/
18 May 13:35:24 - [info] Active project : uibuilder_next_gen
18 May 13:35:24 - [info] Flows file     : D:\src\nr\data\projects\uibuilder_next_gen\flow.json
18 May 13:35:24 - [info] +-----------------------------------------------------
18 May 13:35:24 - [info] | 🌐 uibuilder v7.7.0 initialised
18 May 13:35:24 - [info] | root folder: D:\src\uibRoot
18 May 13:35:24 - [info] | Using custom ExpressJS webserver at:
18 May 13:35:24 - [info] |   https://192.168.1.119:3001 or https://localhost:3001/
18 May 13:35:24 - [info] | Installed packages:
18 May 13:35:24 - [info] |   dompurify, markdown-it, vue, mermaid
18 May 13:35:24 - [info] |   chart.js, d3, @github/include-fragment-element, jquery
18 May 13:35:24 - [info] |   jquery2, @totallyinformation/web-components, plotly.js-dist, justgage
18 May 13:35:24 - [info] |   front-matter, gauge-hotnipi
18 May 13:35:24 - [info] +-----------------------------------------------------
STARTUP DEPLOYMENT
STARTUP DEPLOYMENT
STARTUP DEPLOYMENT
STARTUP DEPLOYMENT
STARTUP DEPLOYMENT
18 May 13:35:24 - [info] Starting flows
18 May 13:35:24 - [info] [ui-base:My Dashboard] Node-RED Dashboard 2.0 (v1.30.2) started at /dashboard
18 May 13:35:24 - [info] [ui-base:My Dashboard] Created socket.io server bound to Node-RED port at path /nr/dashboard/socket.io
Using shared settings from config node
Debug node not showing status
18 May 13:35:26 - [info] [worldmap:9864a699a77b49f2] started at /worldmap
18 May 13:35:26 - [info] 🌐🕸️[markweb] New URL "/markweb-test", source fldr "D:\src\nr\data\docs", config fldr "D:\src\nr\data\docsConfig"
18 May 13:35:26 - [info] 🌐🕸️[markweb] New URL "/markweb-demo", source fldr "D:\src\node-red-contrib-uibuilder\templates\markweb-demo", config fldr "D:\src\node-red-contrib-uibuilder\templates\.markweb-defaults"
18 May 13:35:26 - [info] Started flows

Which is really much too chatty. Best to change most of those outputs to be either debug or trace level.

I also got this error on installing the node via the palette manager - but it didn't come back on restart.

18 May 13:34:48 - [info]  - @theotherwillembotha/node-red-temporal:TemporalTransformNode : TypeError: Cannot read properties of undefined (reading 'instance') (line:14)

Also, the node colour is rather dark. Makes it hard to read the text.


And the default settings produce an error with the default inject - which is milliseconds since epoch.

It would be good to at least have an input drop-down that takes millis input. Changing the input to millis and then back to something else, does indeed leave the default input format on millis and that does work correctly then.

However, you've labelled millis as "UNIX Timestamp (milliseconds)" and while this is technically correct, it may be confusing. It may be better to make it the same as the inject node "milliseconds since epoch" for clarity?

You are also missing "mm" and "ss" in your help table for formats.

While not strictly part of Temporal, the moment node also includes locale outputs which would be nice. The moment nodes package also includes the humaizer node which would also be nice. As would a duration node as that is part of the Temporal standard.


One final point - the log output indicates that many config nodes are being registered:

registering node DelegatedConfigReferenceNode
registered node DelegatedConfigReferenceNode
registering node ConsoleLoggerConfigNode
registered node ConsoleLoggerConfigNode
registering node RestLoggerConfigNode
registered node RestLoggerConfigNode
registering node LokiLoggerConfigNode
registered node LokiLoggerConfigNode
registering node MetricsConfigNode
registered node MetricsConfigNode
registering node CounterMetricConfigNode
registered node CounterMetricConfigNode
registering node GaugeMetricConfigNode
registered node GaugeMetricConfigNode
registering node TimerMetricConfigNode
registered node TimerMetricConfigNode
registering node WebhookServerConfigNode
registered node WebhookServerConfigNode

But none of these nodes appear in the palette manager under your package? And I can't see them anywhere.

Thanks for the feedback.

Perhaps it would be worthwhile to explain what is happening here. I have a library of around 40 or so plugins that I am trying to migrate into the public domain. At one point I was churning out 2 or 3 new ones every week but I very quickly ran into a couple of problems:

Sharing functionality between nodes:
There were primarily 3 types of shared functionality between nodes:

  • A configuration node (eg a http endpoint or database connection)
  • A backend service (eg some or other endpoint that is called from nodes in different plugins)
  • A "section" of node UI / node behaviour that is always the same (eg logging or metrics)

Repeating Patterns for common workarounds:
Some hard limitations on NodeRed requires workarounds that are doable, but too complex to be generally included in human-maintainable code, example:

  • Having a list of referenced config nodes as nodetype defaults and still have reference counting work so you don't end up with "unused" config nodes even though they clearly are being used.
  • Node inheritance and node subtypes (eg: LogConfigNode can be extended into RestLogConfigNode, ConsoleLogConfigNode and LokiLogConfigNode).
  • Registering nodes so they can be queried by other nodes and services based on some sort of criteria (eg tags)
  • Creating a monaco code editor that is not tainted by hardcoded nodered api extensions.

And Lastly:
Boilerplate:
Configuring a webhook manually, configuring a logging appender manually, configuring a metric endpoint manually. configure an input handler manually. More than half the actual code of my nodes just consisted of boilerplate and AintNobodyGotTimeForThat.

The umbrella solution was a core plugin that took care of most of this.

  • a couple of common / generic backend services and nodes that can be shared between nodes and other plugins.
  • templates that could inject / stack shared components into Editors
  • typescript decorators to take care of a lot of boilerplate.
  • an assembler to create the nodered deployable artifacts.

This kinda explains all the extra Nodes that are installed. They should be under the @theotherwillembotha/node-red-plugincore.


Even though they are not used, they are still installed by nodered because the plugin is referenced as a dependency. Note that apart from DelegatedConfigReferenceNode (a glorified seat-warmer to work around reference counting), all the others are ConfigNodes which mean that they can only be created from a node that references them. You can try installing @theotherwillembotha/node-red-telemetry if you want to play with it. A lot of my other nodes also use them via templates and decorators.

Agreed. its one of the leftovers from a previous debugging session. I'll remove it.

Long Story Short: When installing packages using palette manager the nodes of dependencies are not discovered · Issue #3529 · node-red/node-red · GitHub
Short Story Long: Because the temporal plugin references the core plugin as a dependency, it will install the core plugin, but the order in which they are resolved is temporal plugin first followed by then core plugin. That's why the issue disappears when you restart. There are two options: either install the temporal plugin and restart, or install the core plugin followed by the temporal plugin. I tried to put this in the documentation, but until node-red gets proper dependency resolution, its unfortunately going to be one of those things.

The colour actually changes when you restart and the core plugin is loaded first.
image

Makes sense. I'll get that changed.

I think those might have been hidden since I folded the table in on itself to keep it more compact.

Cool... I'll look into those. What did you have in mind for the duration node? Subtract two temporal values from one another? Off the cuff, I am thinking 2 "input" sections where you can define your inputs (from, format, timezone) and then an output section where the specifics related to the duration's output is configured.

OK, I think I sort of get where you are going here. It feels a very complex approach to me though that might simply be me not fully cognizant of what is happening under the skin. But I would have put all my common stuff into a separate package and made that a normal dependency. I wouldn't have relied on Node-RED's config nodes in that package though, I would use something like singleton class instances similar to how I've structured things in UIBUILDER. To make development easier, the extra package could be a workspace in another repo and you could, if needed, make all your packages under a single monorepo.

Anyway, quite possibly you've already considered all this and found it wanting for some reason. All I can say is that I did, at one point, with uibuilder have an external package that was shared. But in the end, I found a way to get rid of that. The main UIBUILDER package is my core, it is absolutely possible to create additional "external" packages that utilise uibuilder features thanks to the singleton class instances and the editor and runtime plugins.

  • I decided not to use config nodes and haven't really missed them. Some common configuration is either in settings.js or in a config folder (which I'm slowly deprecating).
  • All my backend services (e.g. Express endpoints and Socket.IO connections mainly but also common configuration and common code) all reside in singleton class instances. This means that it doesn't matter if a node that relies on the class starts before another.
  • I use the plugins for this. With hooks and middleware overrides available from settings.js or a common folder. Plugins are always executed before nodes so this makes them ideal. Indeed, in the next release of uibuilder, I've moved a whole load of the common, early config and setup into the runtime plugin. The Editor plugin already has all of the common config and setup for the Editor side of things. There is also a common CSS stylesheet that I use to tidy up some of the inherited oddities built into the Editor styling.

I don't think I have quite the same issue. However, I do have to keep track of used URL's which is not dissimilar I think. Again, that is done partly in the Editor plugin (to prevent you reusing a URL when setting up a node and having a list of available URL's) and partly by having an Editor-focused API service (another singleton class instance).

Agreed. More common services. But I have the advantage of having a single package of nodes as my central service. But other packages can also use them as needed.

Ah, OK. Confusing but perhaps noted in the documentation that I absolutely failed to read! :smiley:

Yes, can't have everything!

No, afraid not - this after 2 restarts and Editor reloads:

Two timestamps or a timestamp and a duration (such as you already have in the main node 2d 5h etc.) - both would be valid. Then the usual add/subtract. So, I might have 2 timestamps: Now and Christmas, the duration would be how many between them. Somethings being any date/time duration measure, either technical - e.g. 2.164 months, or human - e.g. 2m 13d 5hrs 43 minutes - or whatever.

Might even be worth having a repeat option similar to the inject node so that you could get updates on a set basis?

I had some more time to work on this. There is now a Temporal Duration node:

It can calculate the duration between messages.

And it has a "Human Readable" output mode as well:

I also updated the naming for Milliseconds since epoch and added support for a Javascript Date Object (similar to the input node)

I also stripped out a couple of the additional config nodes that are installed by default and cleaned up some of the overzealous logging.

Sounds good. I had to remove your node from my dev instance because, during development of UIBUILDER, I often have to restart node-red to check things are working correctly and the output was too distracting. I'll give it another go.

PS: You probably should put a try/catch if you can around the error on install?

26 May 12:25:23 - [info]  - @theotherwillembotha/node-red-temporal:TemporalTransformNode : TypeError: Cannot read properties of undefined (reading 'instance') (line:14)

PPS: Personally, I would prefer it if you used an existing palette category rather than a new one. This is because the palette can get very long if lots of nodes are installed. The moment node uses "formats" (I tried to use something meaningful but generic enough that others could use it, it was written a long time ago in a galaxy far away!) but the core "function" might also be appropriate?


Unfortunately, still 2 issues.
Ignore that, weirdly, when I re-installed it put the old version back and then when I checked to make sure I had the right version, it told me there was an update.

However, unfortunately, the colours are still wrong in the palette:


Looks like you've picked up some formatting oddities in the config panels as well. At the default panel width, a lot of your inputs are wrapping to a new line:


I've struggled with this myself in the past, getting all of the panel inputs aligned, especially when using NR's typed input. To be honest, I tend to use an editor plugin to apply my own styles and then add a div wrapper to everything with a custom id so that I can easily tweak things should I need to. The core node examples tend to have far too much manual styling in the HTML for comfort (and too much px sizing is used) which I've removed in my own nodes.