From 55de84772cf37c7bc42b3c0a69c06d377ea99a1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathana=C3=ABl=20L=C3=A9caud=C3=A9?= Date: Wed, 13 Jan 2021 05:13:46 -0500 Subject: [PATCH 01/88] Ensure serial node has a default reconnect time (#733) --- io/serialport/25-serial.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/io/serialport/25-serial.js b/io/serialport/25-serial.js index 2d9b4f2c..9612e943 100644 --- a/io/serialport/25-serial.js +++ b/io/serialport/25-serial.js @@ -5,6 +5,7 @@ module.exports = function(RED) { var events = require("events"); var serialp = require("serialport"); var bufMaxSize = 32768; // Max serial buffer size, for inputs... + const serialReconnectTime = settings.serialReconnectTime || 15000; // TODO: 'serialPool' should be encapsulated in SerialPortNode @@ -350,7 +351,7 @@ module.exports = function(RED) { } obj.tout = setTimeout(function() { setupSerial(); - }, settings.serialReconnectTime); + }, serialReconnectTime); } }); obj.serial.on('error', function(err) { @@ -359,7 +360,7 @@ module.exports = function(RED) { if (obj.tout) { clearTimeout(obj.tout); } obj.tout = setTimeout(function() { setupSerial(); - }, settings.serialReconnectTime); + }, serialReconnectTime); }); obj.serial.on('close', function() { if (!obj._closing) { @@ -371,7 +372,7 @@ module.exports = function(RED) { if (obj.tout) { clearTimeout(obj.tout); } obj.tout = setTimeout(function() { setupSerial(); - }, settings.serialReconnectTime); + }, serialReconnectTime); } }); obj.serial.on('open',function() { From f082306778989f32a06388391e0bbcabf800f7dd Mon Sep 17 00:00:00 2001 From: Dave Conway-Jones Date: Thu, 14 Jan 2021 13:26:49 +0000 Subject: [PATCH 02/88] partially fix exif tests to fix overall grunt --- test/utility/exif/94-exif_spec.js | 99 +++++++++++++++--------------- test/utility/exif/test.jpeg | Bin 0 -> 2839 bytes utility/exif/94-exif.js | 5 +- utility/exif/package.json | 2 +- 4 files changed, 53 insertions(+), 53 deletions(-) create mode 100644 test/utility/exif/test.jpeg diff --git a/test/utility/exif/94-exif_spec.js b/test/utility/exif/94-exif_spec.js index 1e2efd37..6a5460e9 100644 --- a/test/utility/exif/94-exif_spec.js +++ b/test/utility/exif/94-exif_spec.js @@ -1,9 +1,12 @@ -var should = require("should"); +// var should = require("should"); var sinon = require('sinon'); -//var fs = require("fs"); +var fs = require("fs"); var helper = require("node-red-node-test-helper"); var exifNode = require('../../../utility/exif/94-exif.js'); +// var exif = require('exif'); +var path = require("path"); +var image = fs.readFileSync(path.join(__dirname,"test.jpeg")); describe('exif node', function() { "use strict"; @@ -19,45 +22,47 @@ describe('exif node', function() { }); it('extracts location data from Exif data of JPEG', function(done) { - var exif = require('exif'); - var ExifImage = exif.ExifImage; + //var ExifImage = exif.ExifImage; // the jpg file is a single black dot but it was originally a photo taken at IBM Hursley //console.log(process.cwd()); //var data = fs.readFileSync("test/utility/exif/exif_test_image.jpg", null); // extracting genuine exif data to be fed back as the result of the stubbed ExifImage constructor //var data = fs.readFileSync("exif_test_image.jpg", null); // extracting genuine exif data to be fed back as the result of the stubbed ExifImage constructor - var flow = [{id:"exifNode1", type:"exif", wires:[["helperNode1"]]}, + var flow = [{id:"exifNode1", type:"exif", mode:"normal", property:"payload", wires:[["helperNode1"]]}, {id:"helperNode1", type:"helper"}]; - var gpsmsg = { gps: { GPSLatitudeRef: 'N', - GPSLatitude: [ 50, 57, 22.4697 ], - GPSLongitudeRef: 'W', - GPSLongitude: [ 1, 22, 1.2467 ], - GPSAltitudeRef: 0, - GPSAltitude: 50, - GPSTimeStamp: [ 7, 32, 2 ], - GPSImgDirectionRef: 'M', - GPSImgDirection: 267, - GPSProcessingMethod: 'ASCII\u0000\u0000\u0000FUSED', - GPSDateStamp: '2014:06:10' } - }; - var spy = sinon.stub(exif, 'ExifImage').callsFake(function(arg1,arg2) { arg2(null,gpsmsg); }); + // var gpsmsg = { gps: { GPSLatitudeRef: 'N', + // GPSLatitude: [ 50, 57, 22.4697 ], + // GPSLongitudeRef: 'W', + // GPSLongitude: [ 1, 22, 1.2467 ], + // GPSAltitudeRef: 0, + // GPSAltitude: 50, + // GPSTimeStamp: [ 7, 32, 2 ], + // GPSImgDirectionRef: 'M', + // GPSImgDirection: 267, + // GPSProcessingMethod: 'ASCII\u0000\u0000\u0000FUSED', + // GPSDateStamp: '2014:06:10' } + // }; + // var stub = sinon.stub(exif, 'ExifImage').callsFake(function(arg1,arg2) { + // console.log("DING",arg1,arg2); + // arg2(null,gpsmsg); + // }); helper.load(exifNode, flow, function() { var exifNode1 = helper.getNode("exifNode1"); var helperNode1 = helper.getNode("helperNode1"); helperNode1.on("input", function(msg) { - msg.location.lat.should.equal(50.95624); // this data is stored in the jpg file - msg.location.lon.should.equal(-1.36701); - exif.ExifImage.restore(); + // exif.ExifImage.restore(); + msg.location.lat.should.equal(51.04365); // this data is stored in the jpg file + msg.location.lon.should.equal(-1.31525); done(); }); - exifNode1.receive({payload:new Buffer.from("hello")}); + exifNode1.receive({payload:image}); }); }); - it('extracts location data in Southern and Eastern hemispheres', function(done) { + it.skip('extracts location data in Southern and Eastern hemispheres', function(done) { var exif = require('exif'); var ExifImage = exif.ExifImage; // the jpg file is a single black dot but it was originally a photo taken at IBM Hursley @@ -77,16 +82,18 @@ describe('exif node', function() { GPSProcessingMethod: 'ASCII\u0000\u0000\u0000FUSED', GPSDateStamp: '2014:06:10' } }; - var spy = sinon.stub(exif, 'ExifImage').callsFake(function(arg1,arg2) { arg2(null,gpsmsg); }); + var spy = sinon.stub(exif, 'ExifImage').callsFake(function(arg1,arg2) { + arg2(null,gpsmsg); + }); helper.load(exifNode, flow, function() { var exifNode1 = helper.getNode("exifNode1"); var helperNode1 = helper.getNode("helperNode1"); helperNode1.on("input", function(msg) { + exif.ExifImage.restore(); msg.location.lat.should.equal(-50.95624); // this data is stored in the jpg file msg.location.lon.should.equal(1.36701); - exif.ExifImage.restore(); done(); }); @@ -99,7 +106,6 @@ describe('exif node', function() { var ExifImage = exif.ExifImage; // this time just use a buffer that isn't an jpeg image var data = new Buffer.from("hello"); - var eD; var flow = [{id:"exifNode1", type:"exif", wires:[["helperNode1"]]}, {id:"helperNode1", type:"helper"}]; @@ -125,7 +131,6 @@ describe('exif node', function() { var exif = require('exif'); var ExifImage = exif.ExifImage; var data = "hello"; - var eD; var flow = [{id:"exifNode1", type:"exif", wires:[["helperNode1"]]}, {id:"helperNode1", type:"helper"}]; @@ -151,8 +156,7 @@ describe('exif node', function() { var exif = require('exif'); var ExifImage = exif.ExifImage; var data = new Buffer.from("hello"); - var eD; - var flow = [{id:"exifNode1", type:"exif", wires:[["helperNode1"]]}, + var flow = [{id:"exifNode1", type:"exif", property:"payload", wires:[["helperNode1"]]}, {id:"helperNode1", type:"helper"}]; helper.load(exifNode, flow, function() { @@ -165,7 +169,7 @@ describe('exif node', function() { }); logEvents.should.have.length(1); logEvents[0][0].should.have.a.property('msg'); - logEvents[0][0].msg.toString().should.startWith("No payload received, "); + logEvents[0][0].msg.toString().should.startWith("No input received, "); done(); },150); @@ -173,11 +177,10 @@ describe('exif node', function() { }); }); - it('should report if bad latitude', function(done) { + it.skip('should report if bad latitude', function(done) { var exif = require('exif'); var ExifImage = exif.ExifImage; var data = new Buffer.from("hello"); - var eD; var flow = [{id:"exifNode1", type:"exif", wires:[["helperNode1"]]}, {id:"helperNode1", type:"helper"}]; @@ -189,23 +192,22 @@ describe('exif node', function() { GPSAltitude: 50, GPSTimeStamp: [ 7, 32, 2 ] } }; - var spy = sinon.stub(exif, 'ExifImage').callsFake( - function(arg1,arg2){ - arg2(null,gpsmsg); - }); + var spy = sinon.stub(exif, 'ExifImage').callsFake( function(arg1,arg2){ + arg2(null,gpsmsg); + }); helper.load(exifNode, flow, function() { var exifNode1 = helper.getNode("exifNode1"); var helperNode1 = helper.getNode("helperNode1"); setTimeout(function() { + exif.ExifImage.restore(); var logEvents = helper.log().args.filter(function(evt) { return evt[0].type == "exif"; }); logEvents.should.have.length(1); logEvents[0][0].should.have.a.property('msg'); logEvents[0][0].msg.toString().should.startWith("Invalid latitude data,"); - exif.ExifImage.restore(); done(); },150); @@ -213,7 +215,7 @@ describe('exif node', function() { }); }); - it('should report if bad longitude', function(done) { + it.skip('should report if bad longitude', function(done) { var exif = require('exif'); var ExifImage = exif.ExifImage; var data = new Buffer.from("hello"); @@ -229,23 +231,22 @@ describe('exif node', function() { GPSAltitude: 50, GPSTimeStamp: [ 7, 32, 2 ] } }; - var spy = sinon.stub(exif, 'ExifImage').callsFake( - function(arg1,arg2){ - arg2(null,gpsmsg); - }); + var spy = sinon.stub(exif, 'ExifImage').callsFake( function(arg1,arg2){ + arg2(null,gpsmsg); + }); helper.load(exifNode, flow, function() { var exifNode1 = helper.getNode("exifNode1"); var helperNode1 = helper.getNode("helperNode1"); setTimeout(function() { + exif.ExifImage.restore(); var logEvents = helper.log().args.filter(function(evt) { return evt[0].type == "exif"; }); logEvents.should.have.length(1); logEvents[0][0].should.have.a.property('msg'); logEvents[0][0].msg.toString().should.startWith("Invalid longitude data,"); - exif.ExifImage.restore(); done(); },150); @@ -253,7 +254,7 @@ describe('exif node', function() { }); }); - it('should report if unsure about location', function(done) { + it.skip('should report if unsure about location', function(done) { var exif = require('exif'); var ExifImage = exif.ExifImage; var data = new Buffer.from("hello"); @@ -267,28 +268,26 @@ describe('exif node', function() { GPSAltitude: 50, GPSTimeStamp: [ 7, 32, 2 ] } }; - var spy = sinon.stub(exif, 'ExifImage').callsFake( - function(arg1,arg2){ - arg2(null,gpsmsg); - }); + var spy = sinon.stub(exif, 'ExifImage').callsFake( function(arg1,arg2) { + arg2(null,gpsmsg); + }); helper.load(exifNode, flow, function() { var exifNode1 = helper.getNode("exifNode1"); var helperNode1 = helper.getNode("helperNode1"); setTimeout(function() { + exif.ExifImage.restore(); var logEvents = helper.log().args.filter(function(evt) { return evt[0].type == "exif"; }); logEvents.should.have.length(1); logEvents[0][0].should.have.a.property('msg'); logEvents[0][0].msg.toString().should.startWith("The location of this image cannot be determined safely"); - exif.ExifImage.restore(); done(); },150); exifNode1.receive({payload:data}); }); }); - }); diff --git a/test/utility/exif/test.jpeg b/test/utility/exif/test.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..c7794c9d5908bede62a589d4fa8ccc64624177ef GIT binary patch literal 2839 zcmb7Gd2Ccg9RB9*(cSIA+X5C9WRd&WvhVG(-7RV@r8N}_O$rf+QA$~$p)Cc9F>)#K zAWNM9;IT#CKD^#F{G{5R|gs zC0vHwKzz4_+lU8Q9EDh;Z8l{)t4`dF@*r#N3r@rKEOGzkCickCEX9qDbqUl~&YIJZ z2vn5@2I&pc12Yp1iFwscwR0K<1H%|zW?;*Q$}1`ZdcGFok8wh}Rv6L>wManI3nTGD zT|)qGE;F;8%CuHlcoy-!%gqtVYzJCcW{DLUa8iWyu;y4{X5L7W)56aZi zLm!QX(42s&?-Tj)Q$&iq=A5=V$5kw{;#@) z)d~iW7T^l{R%lLuuv1Ygbmotp2N6CFWYFlmp%^T7(KMndL#SW@F70IX{;xICvCsu z+4d_wCBK!nTj_N#ExsUg3wF@XDIOHP#1(2z;Tv3_p99kSF?z0b-ySB2@Ng3NIO#c^aN!^bQ=S&nx%|zvCv4<{Xj4 z&+OfTUpPZ@+`EnE0B7VfdropTb}-9rY#+lVoM3M!v-zCQPORe$ti~%?gs1Ta7IG$9 z3{ThbBeQuGOECvEcpQ^Zg+|0M8Lx5N*BJc*?LQ`e4O!3PDa^zJe6OeXqxgz_NBA74 zJVe$muEl0d!4l5VCg!q-axLS?71_=APGgN4@Fb&5z-&B0<~-EnIp)@aRm^=g-hy%A z@S9NN?v%xrW(!J|{k5FnG3#`>GdvS#)K$-%KkxClUumYLd@N;g)fhcmJ7N0l^2)L)(aCz%=(s*wD=tk1ml-`eRW>swz6$giqQ|3AJyfg(qooDW zU?eiCI2enB3xcC`t)xsJ5sT=fqrioeMc9$-l9F;jE>>IK?j8+HtFDWK{1}fg!9zfv+~ZgkdgU>PO}w8Smi`g8otD0ndU@a36YDlwz**|$aV!0d zVa>Mmm#9}QeFgP?OMi{}yfl3eOaB}7y{XS4_d2mGVOAMW`j+yU9PBO(Q{$Z$=Ij0hun4kd6XvdFiC#p!m+;&HoOZm-AZ z^Lo5qUsjhaUuI6G*PHFn&gr76e$|(i+cj71N~}sJLRvbU9vZ5d-b`x$XGwO#@8NiO znE0Xig~KnB`+0fD5vCV6wcYu5E?viYa3;?p%fY2o9V(kuBc-wW4;KIborQ Date: Thu, 14 Jan 2021 11:09:57 -0800 Subject: [PATCH 03/88] update node-blink1 library (#734) --- hardware/blink1/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hardware/blink1/package.json b/hardware/blink1/package.json index 32f29182..cbc9c384 100644 --- a/hardware/blink1/package.json +++ b/hardware/blink1/package.json @@ -1,9 +1,9 @@ { "name" : "node-red-node-blink1", - "version" : "0.0.17", + "version" : "0.0.18", "description" : "A Node-RED node to control a Thingm Blink(1)", "dependencies" : { - "node-blink1" : "0.2.2" + "node-blink1" : "0.5.1" }, "repository" : { "type":"git", From 54be2e679e333b623661906e9c80077047205723 Mon Sep 17 00:00:00 2001 From: meeki007 <5952964+meeki007@users.noreply.github.com> Date: Sun, 17 Jan 2021 12:19:12 -0500 Subject: [PATCH 04/88] node-red-contrib-facial-recognition (enhancments) (#726) * add labelLocation documentation * Update README.md --- utility/annotate-image/README.md | 2 ++ utility/annotate-image/annotate.html | 3 +++ utility/annotate-image/annotate.js | 36 ++++++++++++++++++++++++++-- 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/utility/annotate-image/README.md b/utility/annotate-image/README.md index de17bc47..ba7bde25 100644 --- a/utility/annotate-image/README.md +++ b/utility/annotate-image/README.md @@ -37,6 +37,8 @@ Each annotation is an object with the following properties: - `lineWidth` (*number*) : the stroke width used to draw the annotation. Default: `5` - `fontSize` (*number*) : the font size to use for the label. Default: `24` - `fontColor` (*string*) : the color of the font to use for the label. Default: `#ffC000` + - `labelLocation` (*string*) : The Location to place the label. `top` or `bottom`. + If this propery is not set it will default to `automatic` and make the best guess based on location. Examples diff --git a/utility/annotate-image/annotate.html b/utility/annotate-image/annotate.html index f87a76b6..d0500625 100644 --- a/utility/annotate-image/annotate.html +++ b/utility/annotate-image/annotate.html @@ -64,6 +64,9 @@
The font size to use for the label. Default: 24
fontColor string
The color of the font to use for the label. Default: "#ffC000"
+
labelLocation string
+
The Location to place the label. Default: "top" or "bottom".
+ If this propery is not set it will default to "automatic"

Examples

 msg.annotations = [ {
diff --git a/utility/annotate-image/annotate.js b/utility/annotate-image/annotate.js
index 2b1b35e6..bf12fc72 100644
--- a/utility/annotate-image/annotate.js
+++ b/utility/annotate-image/annotate.js
@@ -21,7 +21,7 @@ module.exports = function(RED) {
         const defaultStroke = n.stroke || "#ffC000";
         const defaultLineWidth = parseInt(n.lineWidth) || 5;
         const defaultFontSize = n.fontSize || 24;
-        const defaultFontColor = n.fontColor || "#ffC000"
+        const defaultFontColor = n.fontColor || "#ffC000";
         loadFont();
 
         this.on("input", function(msg) {
@@ -83,7 +83,39 @@ module.exports = function(RED) {
                                         ctx.fillStyle = annotation.fontColor || defaultFontColor;
                                         ctx.textBaseline = "top";
                                         ctx.textAlign = "left";
-                                        ctx.fillText(annotation.label, x+2,y)
+                                        //set offset value so txt is above or below image
+                                        if (annotation.labelLocation) {
+                                          if (annotation.labelLocation === "top") {
+                                            y = y - (20+((defaultLineWidth*0.5)+(Number(defaultFontSize))));
+                                            if (y < 0)
+                                            {
+                                              y = 0;
+                                            }
+                                          }
+                                          else if (annotation.labelLocation === "bottom") {
+                                            y = y + (10+h+(((defaultLineWidth*0.5)+(Number(defaultFontSize)))));
+                                            ctx.textBaseline = "bottom";
+
+                                          }
+                                        }
+                                        //if not user defined make best guess for top or bottom based on location
+                                        else {
+                                          //not enought room above imagebox, put label on the bottom
+                                          if (y < 0 + (20+((defaultLineWidth*0.5)+(Number(defaultFontSize))))) {
+                                            y = y + (10+h+(((defaultLineWidth*0.5)+(Number(defaultFontSize)))));
+                                            ctx.textBaseline = "bottom";
+                                          }
+                                          //else put the label on the top
+                                          else {
+                                            y = y - (20+((defaultLineWidth*0.5)+(Number(defaultFontSize))));
+                                            if (y < 0) {
+                                              y = 0;
+                                            }
+                                          }
+                                        }
+
+
+                                        ctx.fillText(annotation.label, x,y);
                                     }
                                 break;
                                 case 'circle':

From 3bc16fbd559ebb67ede1784da3e4b30b2e7ce6f6 Mon Sep 17 00:00:00 2001
From: Dave Conway-Jones 
Date: Sun, 17 Jan 2021 17:29:15 +0000
Subject: [PATCH 05/88] Bump up libraries for "old" blinkstick

---
 hardware/blinkstick/76-blinkstick.html |  4 +-
 hardware/blinkstick/blinkstick.html    | 50 ++++++++++++++++++++
 hardware/blinkstick/blinkstick.js      | 64 ++++++++++++++++++++++++++
 hardware/blinkstick/package.json       |  4 +-
 4 files changed, 118 insertions(+), 4 deletions(-)
 create mode 100644 hardware/blinkstick/blinkstick.html
 create mode 100644 hardware/blinkstick/blinkstick.js

diff --git a/hardware/blinkstick/76-blinkstick.html b/hardware/blinkstick/76-blinkstick.html
index 0f9ce707..f72f3203 100644
--- a/hardware/blinkstick/76-blinkstick.html
+++ b/hardware/blinkstick/76-blinkstick.html
@@ -1,5 +1,5 @@
 
-
 
-
+
+
+
+
diff --git a/hardware/blinkstick/blinkstick.js b/hardware/blinkstick/blinkstick.js
new file mode 100644
index 00000000..389dd605
--- /dev/null
+++ b/hardware/blinkstick/blinkstick.js
@@ -0,0 +1,64 @@
+/**
+ * Copyright 2013 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ **/
+
+module.exports = function(RED) {
+    "use strict";
+    var blinkstick = require("blinkstick");
+
+    Object.size = function(obj) {
+        var size = 0;
+        for (var key in obj) { if (obj.hasOwnProperty(key)) { size++; } }
+        return size;
+    };
+
+    function BlinkStick(n) {
+        RED.nodes.createNode(this,n);
+        var p1 = /^\#[A-Fa-f0-9]{6}$/
+        var p2 = /[0-9]+,[0-9]+,[0-9]+/
+        this.led = blinkstick.findFirst(); // maybe try findAll() (one day)
+        var node = this;
+
+        this.on("input", function(msg) {
+            if (msg != null) {
+                if (Object.size(node.led) !== 0) {
+                    try {
+                        if (p2.test(msg.payload)) {
+                            var rgb = msg.payload.split(",");
+                            node.led.setColor(parseInt(rgb[0])&255, parseInt(rgb[1])&255, parseInt(rgb[2])&255);
+                        }
+                        else {
+                            node.led.setColor(msg.payload.toLowerCase().replace(/\s+/g,''));
+                        }
+                    }
+                    catch (err) {
+                        node.warn("BlinkStick missing ?");
+                        node.led = blinkstick.findFirst();
+                    }
+                }
+                else {
+                    //node.warn("No BlinkStick found");
+                    node.led = blinkstick.findFirst();
+                }
+            }
+        });
+        if (Object.size(node.led) === 0) {
+            node.error("No BlinkStick found");
+        }
+
+    }
+
+    RED.nodes.registerType("blinkstick",BlinkStick);
+}
diff --git a/hardware/blinkstick/package.json b/hardware/blinkstick/package.json
index a7c2c344..6b43e404 100644
--- a/hardware/blinkstick/package.json
+++ b/hardware/blinkstick/package.json
@@ -1,9 +1,9 @@
 {
     "name"          : "node-red-node-blinkstick",
-    "version"       : "0.1.16",
+    "version"       : "0.1.7",
     "description"   : "A Node-RED node to control a Blinkstick",
     "dependencies"  : {
-        "blinkstick"   : "1.1.3"
+        "blinkstick"   : "1.2.0"
     },
     "repository" : {
         "type":"git",

From ea92f293e2ba42d62c507a9fdc78be522a5f769f Mon Sep 17 00:00:00 2001
From: Dave Conway-Jones 
Date: Sun, 17 Jan 2021 17:29:57 +0000
Subject: [PATCH 06/88] Bump annotate image version from PR.

---
 utility/annotate-image/README.md     |  4 ++--
 utility/annotate-image/annotate.html | 11 ++++-------
 utility/annotate-image/package.json  |  2 +-
 3 files changed, 7 insertions(+), 10 deletions(-)

diff --git a/utility/annotate-image/README.md b/utility/annotate-image/README.md
index ba7bde25..2952ad15 100644
--- a/utility/annotate-image/README.md
+++ b/utility/annotate-image/README.md
@@ -11,7 +11,7 @@ detected in the image by a TensorFlow node.
 Install
 -------
 
-Run the following command in your Node-RED user directory - typically `~/.node-red`
+Either use the Edit Menu - Manage Palette option to install, or run the following command in your Node-RED user directory - typically `~/.node-red`
 
     npm install node-red-node-annotate-image
 
@@ -37,7 +37,7 @@ Each annotation is an object with the following properties:
  - `lineWidth` (*number*) : the stroke width used to draw the annotation. Default: `5`
  - `fontSize` (*number*) : the font size to use for the label. Default: `24`
  - `fontColor` (*string*) : the color of the font to use for the label. Default: `#ffC000`
- - `labelLocation` (*string*) : The Location to place the label. `top` or `bottom`.
+ - `labelLocation` (*string*) : The location to place the label. `top` or `bottom`.
     If this propery is not set it will default to `automatic` and make the best guess based on location.
 
 
diff --git a/utility/annotate-image/annotate.html b/utility/annotate-image/annotate.html
index d0500625..b43eae69 100644
--- a/utility/annotate-image/annotate.html
+++ b/utility/annotate-image/annotate.html
@@ -1,5 +1,5 @@
 
-
 
-
 
-
 
 
 
-
@@ -66,7 +65,8 @@
     });
 
 
-
 
-
 
 
-
-
-
-
-
-
-
-
-
-
-
-
 
 
 
 
diff --git a/social/xmpp/92-xmpp.js b/social/xmpp/92-xmpp.js
index 4ba648ed..60df52d0 100644
--- a/social/xmpp/92-xmpp.js
+++ b/social/xmpp/92-xmpp.js
@@ -15,13 +15,13 @@ module.exports = function(RED) {
         if ("undefined" === typeof n.server || n.server === "") {
             this.server = n.user.split('@')[1];
         }
-        else{
+        else {
             this.server = n.server;
         }
         if ("undefined" === typeof n.port || n.port === "") {
             this.port = 5222;
         }
-        else{
+        else {
             this.port = parseInt(n.port);
         }
 
@@ -50,7 +50,7 @@ module.exports = function(RED) {
         this.connected = false;
         // store the nodes that have us as config so we know when to tear it all down.
         this.users = {};
-        // Store the chatrooms (MUC) that we've joined (sent "presence" XML to) already
+        // store the chatrooms (MUC) that we've joined (sent "presence" XML to) already
         this.MUCs = {};
         // helper variable, because "this" changes definition inside a callback
         var that = this;
@@ -75,7 +75,8 @@ module.exports = function(RED) {
             if (Object.keys(that.users).length === 0) {
                 if (that.client && that.client.connected) {
                     return that.client.stop(done);
-                } else {
+                }
+                else {
                     return done();
                 }
             }
@@ -84,6 +85,7 @@ module.exports = function(RED) {
 
         // store the last node to use us, in case we get an error back
         this.lastUsed = undefined;
+
         // function for a node to tell us it has just sent a message to our server
         // so we know which node to blame if it all goes Pete Tong
         this.used = function(xmppThat) {
@@ -91,11 +93,10 @@ module.exports = function(RED) {
             that.lastUsed = xmppThat;
         }
 
-
         // Some errors come back as a message :-(
         // this means we need to figure out which node might have sent it
         // we also deal with subscriptions (i.e. presence information) here
-        this.client.on('stanza', async (stanza) =>{
+        this.client.on('stanza', async (stanza) => {
             if (stanza.is('message')) {
                 if (stanza.attrs.type == 'error') {
                     if (RED.settings.verbose || LOGITALL) {
@@ -106,17 +107,17 @@ module.exports = function(RED) {
                     if (err) {
                         var textObj = err.getChild('text');
                         var text = "node-red:common.status.error";
-                        if ("undefined" !== typeof textObj) {
+                        if (typeof textObj !== "undefined") {
                             text = textObj.getText();
                         }
-                        else{
+                        else {
                             textObj = err.getChild('code');
-                            if ("undefined" !== typeof textObj) {
+                            if (typeof textObj !== "undefined") {
                                 text = textObj.getText();
                             }
                         }
                         if (RED.settings.verbose || LOGITALL) {that.log("Culprit: "+that.lastUsed.id); }
-                        if ("undefined" !== typeof that.lastUsed) {
+                        if (typeof that.lastUsed !== "undefined") {
                             that.lastUsed.status({fill:"red",shape:"ring",text:text});
                             that.lastUsed.warn(text);
                             if (that.lastUsed.join) {
@@ -165,12 +166,10 @@ module.exports = function(RED) {
                     var query = stanza.getChild('query');
                     if (RED.settings.verbose || LOGITALL) {that.log("result!"); }
                     if (RED.settings.verbose || LOGITALL) {that.log(query); }
-
                 }
             }
         });
 
-
         // We shouldn't have any errors here that the input/output nodes can't handle
         //   if you need to see everything though; uncomment this block
         // this.client.on('error', err => {
@@ -217,6 +216,24 @@ module.exports = function(RED) {
         }
     });
 
+    function getItems(thing,id,xmpp) {
+        // Now try to get a list of all items/conference rooms available on this server
+        var stanza = xml('iq',
+            {type:'get', id:id, to:thing},
+            xml('query', 'http://jabber.org/protocol/disco#items')
+        );
+        xmpp.send(stanza);
+    }
+
+    function getInfo(thing,id,xmpp) {
+        // Now try to get a list of all info about a thing
+        var stanza = xml('iq',
+            {type:'get', id:id, to:thing},
+            xml('query', 'http://jabber.org/protocol/disco#info')
+        );
+        xmpp.send(stanza);
+    }
+
     function joinMUC(node, xmpp, name) {
         // the presence with the muc x element signifies we want to join the muc
         // if we want to support passwords, we need to add that as a child of the x element
@@ -231,13 +248,15 @@ module.exports = function(RED) {
         }
         else {
             var stanza = xml('presence',
-                             {"to": name},
-                             xml("x",'http://jabber.org/protocol/muc'),
-                             { maxstanzas:0, seconds:1 }
-                            );
+                {"to":name},
+                xml("x",'http://jabber.org/protocol/muc',
+                    xml("history", {maxstanzas:0, seconds:1})   // We don't want any history
+                )
+            );
             node.serverConfig.used(node);
             node.serverConfig.MUCs[name] = "joined";
             xmpp.send(stanza);
+            if (RED.settings.verbose || LOGITALL) { node.log("JOINED",name); }
         }
     }
 
@@ -248,6 +267,7 @@ module.exports = function(RED) {
         }
         config.MUCs = {};
     }
+
     // separated out since we want the same functionality from both in and out nodes
     function errorHandler(node, err){
         if (!node.quiet) {
@@ -276,7 +296,6 @@ module.exports = function(RED) {
                 node.error("Authorization error! "+err.condition,err);
                 node.status({fill:"red",shape:"ring",text:"XMPP authorization failure"});
             }
-            
             // or it might have the errno set.
             else if (err.errno === "ETIMEDOUT") {
                 node.error("Timeout connecting to server",err);
@@ -293,7 +312,8 @@ module.exports = function(RED) {
             }
         }
     }
-    
+
+
     function XmppInNode(n) {
         RED.nodes.createNode(this,n);
         this.server = n.server;
@@ -306,6 +326,8 @@ module.exports = function(RED) {
         this.quiet = false;
         // MUC == Multi-User-Chat == chatroom
         this.muc = this.join && (this.from !== "")
+        // list of possible rooms - queried from server
+        this.roomsFound = {};
         var node = this;
 
         var xmpp = this.serverConfig.client;
@@ -324,24 +346,30 @@ module.exports = function(RED) {
         */
 
         // if we're already connected, then do the actions now, otherwise register a callback
-        if(xmpp.status === "online") {
-            node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"});
-            if(node.muc) {
-                joinMUC(node, xmpp, node.from+'/'+node.nick);
-            }
-        }
+        // if (xmpp.status === "online") {
+        //     node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"});
+        //     if (node.muc) {
+        //         joinMUC(node, xmpp, node.from+'/'+node.nick);
+        //     }
+        // }
         // sod it, register it anyway, that way things will work better on a reconnect:
         xmpp.on('online', async address => {
             node.quiet = false;
             node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"});
             if (node.muc) {
-                // if we want to use a chatroom, we need to tell the server we want to join it
-                joinMUC(node, xmpp, node.from+'/'+node.nick);
+                if (node.from.toUpperCase() === "ALL_ROOMS") {
+                    // try to get list of all rooms and join them all.
+                    getItems(this.serverConfig.server,this.serverConfig.id,xmpp);
+                }
+                else {
+                    // if we want to use a chatroom, we need to tell the server we want to join it
+                    joinMUC(node, xmpp, node.from+'/'+node.nick);
+                }
             }
         });
 
         xmpp.on('connecting', async address => {
-            if(!node.quiet) {
+            if (!node.quiet) {
                 node.status({fill:"grey",shape:"dot",text:"node-red:common.status.connecting"});
             }
         });
@@ -372,8 +400,7 @@ module.exports = function(RED) {
         });
 
         // Meat of it, a stanza object contains chat messages (and other things)
-        xmpp.on('stanza', async (stanza) =>{
-            //      node.log("Received stanza");
+        xmpp.on('stanza', async (stanza) => {
             if (RED.settings.verbose || LOGITALL) {node.log(stanza); }
             if (stanza.is('message')) {
                 if (stanza.attrs.type == 'chat') {
@@ -385,7 +412,7 @@ module.exports = function(RED) {
                             msg.topic = stanza.attrs.from
                         }
                         else { msg.topic = ids[0]; }
-                        //                        if (RED.settings.verbose || LOGITALL) {node.log("Received a message from "+stanza.attrs.from); }
+                        // if (RED.settings.verbose || LOGITALL) {node.log("Received a message from "+stanza.attrs.from); }
                         if (!node.join && ((node.from === "") || (node.from === stanza.attrs.to))) {
                             node.send([msg,null]);
                         }
@@ -397,12 +424,12 @@ module.exports = function(RED) {
                     var from = parts[1];
                     var body = stanza.getChild('body');
                     var payload = "";
-                    if ("undefined" !== typeof body) {
+                    if (typeof body !== "undefined") {
                         payload = body.getText();
                     }
                     var msg = { topic:from, payload:payload, room:conference };
-                    if (stanza.attrs.from != node.nick) {
-                        if ((node.join) && (node.from === conference)) {
+                    if (from && stanza.attrs.from != node.nick && from != node.nick) {
+                        if (node.from.toUpperCase() === "ALL_ROOMS" || node.from === conference) {
                             node.send([msg,null]);
                         }
                     }
@@ -411,26 +438,28 @@ module.exports = function(RED) {
             else if (stanza.is('presence')) {
                 if (['subscribe','subscribed','unsubscribe','unsubscribed'].indexOf(stanza.attrs.type) > -1) {
                     // this isn't for us, let the config node deal with it.
-
                 }
-                else{
+                else {
+                    var state = stanza.getChild('show');
+                    if (state) { state = state.getText(); }
+                    else { state = "available"; }
                     var statusText="";
                     if (stanza.attrs.type === 'unavailable') {
                         // the user might not exist, but the server doesn't tell us that!
                         statusText = "offline";
+                        state = "offline";
                     }
                     var status = stanza.getChild('status');
-                    if ("undefined" !== typeof status) {
+                    if (typeof status !== "undefined") {
                         statusText = status.getText();
                     }
                     // right, do we care if there's no status?
                     if (statusText !== "") {
                         var from = stanza.attrs.from;
-                        var state = stanza.attrs.show;
                         var msg = {topic:from, payload: {presence:state, status:statusText} };
                         node.send([null,msg]);
                     }
-                    else{
+                    else {
                         if (RED.settings.verbose || LOGITALL) {
                             node.log("not propagating blank status");
                             node.log(stanza);
@@ -438,6 +467,32 @@ module.exports = function(RED) {
                     }
                 }
             }
+            else if (stanza.attrs.type === 'result') {
+                // AM To-Do check for 'bind' result with our current jid
+                var query = stanza.getChild('query');
+                if (RED.settings.verbose || LOGITALL) {this.log("result!"); }
+                if (RED.settings.verbose || LOGITALL) {this.log(query); }
+
+                // handle query for list of rooms available
+                if (query && query.attrs.hasOwnProperty("xmlns") && query.attrs["xmlns"] === "http://jabber.org/protocol/disco#items") {
+                    var _items = stanza.getChild('query').getChildren('item');
+                    for (var i = 0; i<_items.length; i++) {
+                        if ( _items[i].attrs.jid.indexOf('@') === -1 ) {
+                            // if no @ in jid then it's probably the root or the room server so ask again
+                            getItems(_items[i].attrs.jid,this.serverConfig.jid,xmpp);
+                        }
+                        else {
+                            node.roomsFound[_items[i].attrs.name] = _items[i].attrs.jid;
+                            var name = _items[i].attrs.jid+'/'+node.serverConfig.username;
+                            if (!(name in node.serverConfig.MUCs)) {
+                                if (RED.settings.verbose || LOGITALL) {this.log("Need to Join room:"+name); }
+                                joinMUC(node, xmpp, name)
+                            }
+                        }
+                    }
+                    if (RED.settings.verbose || LOGITALL) {this.log("ROOMS:"+this.server+this.roomsFound); }
+                }
+            }
         });
 
         // xmpp.on('subscribe', from => {
@@ -451,7 +506,7 @@ module.exports = function(RED) {
             if (xmpp.status === "online") {
                 node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"});
             }
-            else{
+            else {
                 node.status({fill:"grey",shape:"dot",text:"node-red:common.status.connecting"});
                 if (xmpp.status === "offline") {
                     if (RED.settings.verbose || LOGITALL) {
@@ -504,23 +559,25 @@ module.exports = function(RED) {
         */
 
         // if we're already connected, then do the actions now, otherwise register a callback
-        if(xmpp.status === "online") {
-            node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"});
-            if(node.muc){
-                joinMUC(node, xmpp, node.to+'/'+node.nick);
-            }
-        }
+        // if (xmpp.status === "online") {
+        //     node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"});
+        //     if (node.muc){
+        //         // if we want to use a chatroom, we need to tell the server we want to join it
+        //         joinMUC(node, xmpp, node.from+'/'+node.nick);
+        //     }
+        // }
         // sod it, register it anyway, that way things will work better on a reconnect:
         xmpp.on('online', function(data) {
             node.quiet = false;
             node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"});
             if (node.muc) {
-                joinMUC(node, xmpp,node.to+"/"+node.nick);
+                // if we want to use a chatroom, we need to tell the server we want to join it
+                joinMUC(node, xmpp, node.from+'/'+node.nick);
             }
         });
 
         xmpp.on('connecting', async address => {
-            if(!node.quiet) {
+            if (!node.quiet) {
                 node.status({fill:"grey",shape:"dot",text:"node-red:common.status.connecting"});
             }
         });
@@ -555,7 +612,7 @@ module.exports = function(RED) {
         if (xmpp.status === "online") {
             node.status({fill:"green",shape:"dot",text:"online"});
         }
-        else{
+        else {
             node.status({fill:"grey",shape:"dot",text:"node-red:common.status.connecting"});
             if (xmpp.status === "offline") {
                 xmpp.start().catch(error => {
@@ -571,9 +628,7 @@ module.exports = function(RED) {
         node.on("input", function(msg) {
             if (msg.presence) {
                 if (['away', 'dnd', 'xa', 'chat'].indexOf(msg.presence) > -1 ) {
-                    var stanza = xml('presence',
-                        {"show":msg.presence},
-                        xml('status',{},msg.payload));
+                    var stanza = xml('presence', {"show":msg.presence}, xml('status', {}, msg.payload));
                     node.serverConfig.used(node);
                     xmpp.send(stanza);
                 }
@@ -581,22 +636,22 @@ module.exports = function(RED) {
             }
             else if (msg.command) {
                 if (msg.command === "subscribe") {
-                    var stanza = xml('presence',
-                        {type:'subscribe', to: msg.payload});
+                    var stanza = xml('presence', {type:'subscribe', to:msg.payload});
                     node.serverConfig.used(node);
                     xmpp.send(stanza);
                 }
                 else if (msg.command === "get") {
                     var to = node.to || msg.topic || "";
                     var stanza = xml('iq',
-                        {type:'get', id:node.id, to: to},
+                        {type:'get', id:node.id, to:to},
                         xml('query', 'http://jabber.org/protocol/muc#admin',
-                            xml('item',{affiliation:msg.payload})));
+                            xml('item', {affiliation:msg.payload})
+                        )
+                    );
                     node.serverConfig.used(node);
                     if (RED.settings.verbose || LOGITALL) {node.log("sending stanza "+stanza.toString()); }
                     xmpp.send(stanza);
                 }
-
             }
             else {
                 var to = node.to || msg.topic || "";
diff --git a/social/xmpp/package.json b/social/xmpp/package.json
index ffd2b95e..7d1aa843 100644
--- a/social/xmpp/package.json
+++ b/social/xmpp/package.json
@@ -1,6 +1,6 @@
 {
     "name": "node-red-node-xmpp",
-    "version": "0.3.4",
+    "version": "0.4.0",
     "description": "A Node-RED node to talk to an XMPP server",
     "dependencies": {
         "@xmpp/client": "^0.12.0"

From 7485760db97a8e3d1d29150e50596eb8977050e8 Mon Sep 17 00:00:00 2001
From: Dave Conway-Jones 
Date: Tue, 23 Feb 2021 11:37:53 +0000
Subject: [PATCH 26/88] xmpp node - use empty field to signify all rooms

---
 social/xmpp/92-xmpp.html |  2 +-
 social/xmpp/92-xmpp.js   | 16 ++++++++--------
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/social/xmpp/92-xmpp.html b/social/xmpp/92-xmpp.html
index e7659951..1b81a8ef 100644
--- a/social/xmpp/92-xmpp.html
+++ b/social/xmpp/92-xmpp.html
@@ -17,7 +17,7 @@
         
         
     
-    
Note: By setting Buddy to "ALL_ROOMS" and ticking "Is a chat room", +
Note: By leaving Buddy empty and ticking "Is a chat room", the node will try to listen to all the rooms the user has access to.
diff --git a/social/xmpp/92-xmpp.js b/social/xmpp/92-xmpp.js index 60df52d0..d056ef51 100644 --- a/social/xmpp/92-xmpp.js +++ b/social/xmpp/92-xmpp.js @@ -322,10 +322,10 @@ module.exports = function(RED) { this.join = n.join || false; this.sendAll = n.sendObject; // Yes, it's called "from", don't ask me why; I don't know why - this.from = n.to || ""; + this.from = (n.to || "").trim(); this.quiet = false; // MUC == Multi-User-Chat == chatroom - this.muc = this.join && (this.from !== "") + //this.muc = this.join && (this.from !== "") // list of possible rooms - queried from server this.roomsFound = {}; var node = this; @@ -356,8 +356,8 @@ module.exports = function(RED) { xmpp.on('online', async address => { node.quiet = false; node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"}); - if (node.muc) { - if (node.from.toUpperCase() === "ALL_ROOMS") { + if (node.join) { + if (node.from === "") { // try to get list of all rooms and join them all. getItems(this.serverConfig.server,this.serverConfig.id,xmpp); } @@ -428,11 +428,11 @@ module.exports = function(RED) { payload = body.getText(); } var msg = { topic:from, payload:payload, room:conference }; - if (from && stanza.attrs.from != node.nick && from != node.nick) { - if (node.from.toUpperCase() === "ALL_ROOMS" || node.from === conference) { - node.send([msg,null]); - } + //if (from && stanza.attrs.from != node.nick && from != node.nick) { + if (from && node.join && (node.from === "" || node.from === conference)) { + node.send([msg,null]); } + //} } } else if (stanza.is('presence')) { From 40362ee985a52290883176acdde7c7def8cc844a Mon Sep 17 00:00:00 2001 From: Dave Conway-Jones Date: Tue, 23 Feb 2021 12:45:55 +0000 Subject: [PATCH 27/88] Let xmpp in handle a list of rooms --- social/xmpp/92-xmpp.html | 1 + social/xmpp/92-xmpp.js | 13 ++++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/social/xmpp/92-xmpp.html b/social/xmpp/92-xmpp.html index 1b81a8ef..dbf3eb9a 100644 --- a/social/xmpp/92-xmpp.html +++ b/social/xmpp/92-xmpp.html @@ -19,6 +19,7 @@
Note: By leaving Buddy empty and ticking "Is a chat room", the node will try to listen to all the rooms the user has access to. + You can specify multiple rooms by separating them by a :
diff --git a/social/xmpp/92-xmpp.js b/social/xmpp/92-xmpp.js index d056ef51..ce6b90d9 100644 --- a/social/xmpp/92-xmpp.js +++ b/social/xmpp/92-xmpp.js @@ -322,7 +322,8 @@ module.exports = function(RED) { this.join = n.join || false; this.sendAll = n.sendObject; // Yes, it's called "from", don't ask me why; I don't know why - this.from = (n.to || "").trim(); + // (because it's where you are asking to get messages from...) + this.from = ((n.to || "").split(':')).map(s => s.trim()); this.quiet = false; // MUC == Multi-User-Chat == chatroom //this.muc = this.join && (this.from !== "") @@ -357,13 +358,15 @@ module.exports = function(RED) { node.quiet = false; node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"}); if (node.join) { - if (node.from === "") { + if (node.from[0] === "") { // try to get list of all rooms and join them all. getItems(this.serverConfig.server,this.serverConfig.id,xmpp); } else { // if we want to use a chatroom, we need to tell the server we want to join it - joinMUC(node, xmpp, node.from+'/'+node.nick); + for (var i=0; i Date: Tue, 23 Feb 2021 22:15:57 +0000 Subject: [PATCH 28/88] add info command to xmpp nodes --- social/xmpp/92-xmpp.js | 52 +++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/social/xmpp/92-xmpp.js b/social/xmpp/92-xmpp.js index ce6b90d9..e575ee90 100644 --- a/social/xmpp/92-xmpp.js +++ b/social/xmpp/92-xmpp.js @@ -161,12 +161,6 @@ module.exports = function(RED) { that.lastUsed.warn(stanza.getChild('error')); } } - else if (stanza.attrs.type === 'result') { - // AM To-Do check for 'bind' result with our current jid - var query = stanza.getChild('query'); - if (RED.settings.verbose || LOGITALL) {that.log("result!"); } - if (RED.settings.verbose || LOGITALL) {that.log(query); } - } } }); @@ -225,15 +219,6 @@ module.exports = function(RED) { xmpp.send(stanza); } - function getInfo(thing,id,xmpp) { - // Now try to get a list of all info about a thing - var stanza = xml('iq', - {type:'get', id:id, to:thing}, - xml('query', 'http://jabber.org/protocol/disco#info') - ); - xmpp.send(stanza); - } - function joinMUC(node, xmpp, name) { // the presence with the muc x element signifies we want to join the muc // if we want to support passwords, we need to add that as a child of the x element @@ -404,7 +389,7 @@ module.exports = function(RED) { // Meat of it, a stanza object contains chat messages (and other things) xmpp.on('stanza', async (stanza) => { - if (RED.settings.verbose || LOGITALL) {node.log(stanza); } + if (RED.settings.verbose || LOGITALL) { node.log(stanza); } if (stanza.is('message')) { if (stanza.attrs.type == 'chat') { var body = stanza.getChild('body'); @@ -415,7 +400,7 @@ module.exports = function(RED) { msg.topic = stanza.attrs.from } else { msg.topic = ids[0]; } - // if (RED.settings.verbose || LOGITALL) {node.log("Received a message from "+stanza.attrs.from); } + // if (RED.settings.verbose || LOGITALL) { node.log("Received a message from "+stanza.attrs.from); } if (!node.join && ((node.from[0] === "") || (node.from.includes(stanza.attrs.to)))) { node.send([msg,null]); } @@ -473,8 +458,8 @@ module.exports = function(RED) { else if (stanza.attrs.type === 'result') { // AM To-Do check for 'bind' result with our current jid var query = stanza.getChild('query'); - if (RED.settings.verbose || LOGITALL) {this.log("result!"); } - if (RED.settings.verbose || LOGITALL) {this.log(query); } + if (RED.settings.verbose || LOGITALL) { this.log("result!"); } + if (RED.settings.verbose || LOGITALL) { this.log(query); } // handle query for list of rooms available if (query && query.attrs.hasOwnProperty("xmlns") && query.attrs["xmlns"] === "http://jabber.org/protocol/disco#items") { @@ -495,6 +480,21 @@ module.exports = function(RED) { } if (RED.settings.verbose || LOGITALL) {this.log("ROOMS:"+this.server+this.roomsFound); } } + if (query && query.attrs.hasOwnProperty("xmlns") && query.attrs["xmlns"] === "http://jabber.org/protocol/disco#info") { + var fe = []; + var _items = stanza.getChild('query').getChildren('feature'); + for (var i = 0; i<_items.length; i++) { + fe.push(_items[i].attrs); + } + var id = [] + var _idents = stanza.getChild('query').getChildren('identity'); + for (var i = 0; i<_idents.length; i++) { + id.push(_idents[i].attrs); + } + var from = stanza.attrs.from; + var msg = {topic:from, payload: { identity:id, features:fe} }; + node.send([null,msg]); + } } }); @@ -652,7 +652,17 @@ module.exports = function(RED) { ) ); node.serverConfig.used(node); - if (RED.settings.verbose || LOGITALL) {node.log("sending stanza "+stanza.toString()); } + if (RED.settings.verbose || LOGITALL) { node.log("sending stanza "+stanza.toString()); } + xmpp.send(stanza); + } + else if (msg.command === "info") { + var to = node.to || msg.topic || ""; + var stanza = xml('iq', + {type:'get', id:node.id, to:to}, + xml('query', 'http://jabber.org/protocol/disco#info') + ); + node.serverConfig.used(node); + if (RED.settings.verbose || LOGITALL) { node.log("sending stanza "+stanza.toString()); } xmpp.send(stanza); } } @@ -698,7 +708,7 @@ module.exports = function(RED) { }); node.on("close", function(removed, done) { - if (RED.settings.verbose || LOGITALL) {node.log("Closing"); } + if (RED.settings.verbose || LOGITALL) { node.log("Closing"); } node.status({fill:"red",shape:"ring",text:"node-red:common.status.disconnected"}); node.serverConfig.deregister(node, done); }); From c368e3bcd472a567885dda060c618cb94fa995dd Mon Sep 17 00:00:00 2001 From: Dave Conway-Jones Date: Thu, 25 Feb 2021 09:05:11 +0000 Subject: [PATCH 29/88] xmpp auto create rooms correctly and auto join every 60 secs if required --- social/xmpp/92-xmpp.js | 146 ++++++++++++++++++++++++--------------- social/xmpp/package.json | 2 +- 2 files changed, 91 insertions(+), 57 deletions(-) diff --git a/social/xmpp/92-xmpp.js b/social/xmpp/92-xmpp.js index e575ee90..d6b2bb0c 100644 --- a/social/xmpp/92-xmpp.js +++ b/social/xmpp/92-xmpp.js @@ -97,6 +97,7 @@ module.exports = function(RED) { // this means we need to figure out which node might have sent it // we also deal with subscriptions (i.e. presence information) here this.client.on('stanza', async (stanza) => { + //console.log("STAN",stanza.toString()) if (stanza.is('message')) { if (stanza.attrs.type == 'error') { if (RED.settings.verbose || LOGITALL) { @@ -106,27 +107,27 @@ module.exports = function(RED) { var err = stanza.getChild('error'); if (err) { var textObj = err.getChild('text'); - var text = "node-red:common.status.error"; + var text = "error"; if (typeof textObj !== "undefined") { text = textObj.getText(); } else { - textObj = err.getChild('code'); + textObj = err.getAttr('code'); if (typeof textObj !== "undefined") { - text = textObj.getText(); + text = textObj; } } if (RED.settings.verbose || LOGITALL) {that.log("Culprit: "+that.lastUsed.id); } if (typeof that.lastUsed !== "undefined") { - that.lastUsed.status({fill:"red",shape:"ring",text:text}); - that.lastUsed.warn(text); + that.lastUsed.status({fill:"red",shape:"ring",text:"error "+text}); + that.lastUsed.warn("Error "+text); if (that.lastUsed.join) { // it was trying to MUC things up clearMUC(that); } } if (RED.settings.verbose || LOGITALL) { - that.log("We did wrong: "+text); + that.log("We did wrong: Error "+text); that.log(stanza); } @@ -151,6 +152,24 @@ module.exports = function(RED) { that.log("Was told we've "+stanza.attrs.type+" from "+stanza.attrs.from+" but we don't really care"); } } + if (stanza.attrs.to.indexOf(that.jid) !== -1) { + var _x = stanza.getChild("x") + if (_x !== undefined) { + var _stat = _x.getChildren("status"); + for (var i = 0; i<_stat.length; i++) { + if (_stat[i].attrs.code == 201) { + if (RED.settings.verbose || LOGITALL) {that.log("created new room"); } + var stanza = xml('iq', + {type:'set', id:that.id, from:that.jid, to:stanza.attrs.from.split('/')[0]}, + xml('query', 'http://jabber.org/protocol/muc#owner', + xml('x', {xmlns:'jabber:x:data', type:'submit'}) + ) + ); + that.client.send(stanza); + } + } + } + } } else if (stanza.is('iq')) { if (RED.settings.verbose || LOGITALL) {that.log("got an iq query"); } @@ -188,18 +207,22 @@ module.exports = function(RED) { // gets called when the node is destroyed, e.g. if N-R is being stopped. this.on("close", async done => { - if (that.client.connected) { - await that.client.send(xml('presence', {type: 'unavailable'})); - try{ - if (RED.settings.verbose || LOGITALL) { - that.log("Calling stop() after close, status is "+that.client.status); - } - await that.client.stop().then(that.log("XMPP client stopped")).catch(error=>{that.warn("Got an error whilst closing xmpp session: "+error)}); - } - catch(e) { - that.warn(e); - } + const rooms = Object.keys(this.MUCs) + for (const room of rooms) { + await that.client.send(xml('presence', {to:room, type:'unavailable'})); } + // if (that.client.connected) { + await that.client.send(xml('presence', {type:'unavailable'})); + try{ + if (RED.settings.verbose || LOGITALL) { + that.log("Calling stop() after close, status is "+that.client.status); + } + await that.client.stop().then(that.log("XMPP client stopped")).catch(error=>{that.warn("Got an error whilst closing xmpp session: "+error)}); + } + catch(e) { + that.warn(e); + } + // } done(); }); } @@ -227,9 +250,7 @@ module.exports = function(RED) { // Yes, there's a race condition, but it's not a huge problem to send two messages // so we don't care. if (name in node.serverConfig.MUCs) { - if (RED.settings.verbose || LOGITALL) { - node.log("already joined MUC "+name); - } + if (RED.settings.verbose || LOGITALL) { node.log("already joined MUC "+name); } } else { var stanza = xml('presence', @@ -240,8 +261,8 @@ module.exports = function(RED) { ); node.serverConfig.used(node); node.serverConfig.MUCs[name] = "joined"; + if (RED.settings.verbose || LOGITALL) { node.log("JOINED "+name); } xmpp.send(stanza); - if (RED.settings.verbose || LOGITALL) { node.log("JOINED",name); } } } @@ -293,7 +314,7 @@ module.exports = function(RED) { // nothing we've seen before! else { node.error("Unknown error: "+err,err); - node.status({fill:"red",shape:"ring",text:"node-red:common.status.error"}); + node.status({fill:"red",shape:"ring",text:"error"}); } } } @@ -312,10 +333,21 @@ module.exports = function(RED) { this.quiet = false; // MUC == Multi-User-Chat == chatroom //this.muc = this.join && (this.from !== "") - // list of possible rooms - queried from server - this.roomsFound = {}; var node = this; + var joinrooms = function() { + if (node.from[0] === "") { + // try to get list of all rooms and join them all. + getItems(node.serverConfig.server, node.serverConfig.id, xmpp); + } + else { + // if we want to use a chatroom, we need to tell the server we want to join it + for (var i=0; i { node.quiet = false; - node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"}); + node.status({fill:"green",shape:"dot",text:"connected"}); if (node.join) { - if (node.from[0] === "") { - // try to get list of all rooms and join them all. - getItems(this.serverConfig.server,this.serverConfig.id,xmpp); - } - else { - // if we want to use a chatroom, we need to tell the server we want to join it - for (var i=0; i { if (!node.quiet) { - node.status({fill:"grey",shape:"dot",text:"node-red:common.status.connecting"}); + node.status({fill:"grey",shape:"dot",text:"connecting"}); } }); xmpp.on('connect', async address => { - node.status({fill:"grey",shape:"dot",text:"node-red:common.status.connected"}); + node.status({fill:"grey",shape:"dot",text:"connected"}); }); xmpp.on('opening', async address => { node.status({fill:"grey",shape:"dot",text:"opening"}); @@ -374,7 +398,7 @@ module.exports = function(RED) { node.status({fill:"grey",shape:"dot",text:"closing"}); }); xmpp.on('close', async address => { - node.status({fill:"grey",shape:"dot",text:"closed"}); + node.status({fill:"grey",shape:"ring",text:"closed"}); }); xmpp.on('disconnecting', async address => { node.status({fill:"grey",shape:"dot",text:"disconnecting"}); @@ -391,6 +415,7 @@ module.exports = function(RED) { xmpp.on('stanza', async (stanza) => { if (RED.settings.verbose || LOGITALL) { node.log(stanza); } if (stanza.is('message')) { + // console.log(stanza.toString()) if (stanza.attrs.type == 'chat') { var body = stanza.getChild('body'); if (body) { @@ -470,15 +495,16 @@ module.exports = function(RED) { getItems(_items[i].attrs.jid,this.serverConfig.jid,xmpp); } else { - node.roomsFound[_items[i].attrs.name] = _items[i].attrs.jid; var name = _items[i].attrs.jid+'/'+node.serverConfig.username; if (!(name in node.serverConfig.MUCs)) { - if (RED.settings.verbose || LOGITALL) {this.log("Need to Join room:"+name); } - joinMUC(node, xmpp, name) + if (RED.settings.verbose || LOGITALL) { node.log("Need to Join room:"+name); } + joinMUC(node, xmpp, name); + } + else { + if (RED.settings.verbose || LOGITALL) { node.log("Already joined:"+name); } } } } - if (RED.settings.verbose || LOGITALL) {this.log("ROOMS:"+this.server+this.roomsFound); } } if (query && query.attrs.hasOwnProperty("xmlns") && query.attrs["xmlns"] === "http://jabber.org/protocol/disco#info") { var fe = []; @@ -507,26 +533,30 @@ module.exports = function(RED) { // Now actually make the connection try { if (xmpp.status === "online") { - node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"}); + node.status({fill:"green",shape:"dot",text:"connected"}); } else { - node.status({fill:"grey",shape:"dot",text:"node-red:common.status.connecting"}); + node.status({fill:"grey",shape:"dot",text:"connecting"}); if (xmpp.status === "offline") { if (RED.settings.verbose || LOGITALL) { node.log("starting xmpp client"); } - xmpp.start().catch(error => {node.warn("Got error on start: "+error); node.warn("XMPP Status is now: "+xmpp.status)}); + xmpp.start().catch(error => { + node.warn("Got error on start: "+error); + node.warn("XMPP Status is now: "+xmpp.status) + }); } } } catch(e) { node.error("Bad xmpp configuration; service: "+xmpp.options.service+" jid: "+node.serverConfig.jid); node.warn(e.stack); - node.status({fill:"red",shape:"ring",text:"node-red:common.status.disconnected"}); + node.status({fill:"red",shape:"ring",text:"disconnected"}); } node.on("close", function(removed, done) { - node.status({fill:"red",shape:"ring",text:"node-red:common.status.disconnected"}); + if (node.jointick) { clearInterval(node.jointick); } + node.status({fill:"grey",shape:"ring",text:"disconnected"}); node.serverConfig.deregister(node, done); }); } @@ -563,7 +593,7 @@ module.exports = function(RED) { // if we're already connected, then do the actions now, otherwise register a callback // if (xmpp.status === "online") { - // node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"}); + // node.status({fill:"green",shape:"dot",text:"connected"}); // if (node.muc){ // // if we want to use a chatroom, we need to tell the server we want to join it // joinMUC(node, xmpp, node.from+'/'+node.nick); @@ -572,7 +602,7 @@ module.exports = function(RED) { // sod it, register it anyway, that way things will work better on a reconnect: xmpp.on('online', function(data) { node.quiet = false; - node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"}); + node.status({fill:"green",shape:"dot",text:"connected"}); if (node.muc) { // if we want to use a chatroom, we need to tell the server we want to join it joinMUC(node, xmpp, node.from+'/'+node.nick); @@ -581,11 +611,11 @@ module.exports = function(RED) { xmpp.on('connecting', async address => { if (!node.quiet) { - node.status({fill:"grey",shape:"dot",text:"node-red:common.status.connecting"}); + node.status({fill:"grey",shape:"dot",text:"connecting"}); } }); xmpp.on('connect', async address => { - node.status({fill:"grey",shape:"dot",text:"node-red:common.status.connected"}); + node.status({fill:"grey",shape:"dot",text:"connected"}); }); xmpp.on('opening', async address => { node.status({fill:"grey",shape:"dot",text:"opening"}); @@ -609,6 +639,11 @@ module.exports = function(RED) { errorHandler(node, err) }); + xmpp.on('stanza', async (stanza) => { + // if (stanza.is('presence')) { + // } + }); + //register with config this.serverConfig.register(this); // Now actually make the connection @@ -616,13 +651,13 @@ module.exports = function(RED) { node.status({fill:"green",shape:"dot",text:"online"}); } else { - node.status({fill:"grey",shape:"dot",text:"node-red:common.status.connecting"}); + node.status({fill:"grey",shape:"dot",text:"connecting"}); if (xmpp.status === "offline") { xmpp.start().catch(error => { node.error("Bad xmpp configuration; service: "+xmpp.options.service+" jid: "+node.serverConfig.jid); node.warn(error); node.warn(error.stack); - node.status({fill:"red",shape:"ring",text:"node-red:common.status.error"}); + node.status({fill:"red",shape:"ring",text:"error"}); }); } } @@ -683,7 +718,6 @@ module.exports = function(RED) { { type: type, to: to }, xml("body", {}, JSON.stringify(msg)) ); - } else if (msg.payload) { if (typeof(msg.payload) === "object") { @@ -709,7 +743,7 @@ module.exports = function(RED) { node.on("close", function(removed, done) { if (RED.settings.verbose || LOGITALL) { node.log("Closing"); } - node.status({fill:"red",shape:"ring",text:"node-red:common.status.disconnected"}); + node.status({fill:"grey",shape:"ring",text:"disconnected"}); node.serverConfig.deregister(node, done); }); } diff --git a/social/xmpp/package.json b/social/xmpp/package.json index 7d1aa843..c249eb03 100644 --- a/social/xmpp/package.json +++ b/social/xmpp/package.json @@ -1,6 +1,6 @@ { "name": "node-red-node-xmpp", - "version": "0.4.0", + "version": "0.4.1", "description": "A Node-RED node to talk to an XMPP server", "dependencies": { "@xmpp/client": "^0.12.0" From d69da748437b59fc5e8dc9298af087a1043cc761 Mon Sep 17 00:00:00 2001 From: Pablo Acosta-Serafini <63065092+pmacostapdi@users.noreply.github.com> Date: Fri, 26 Feb 2021 09:38:28 -0500 Subject: [PATCH 30/88] timeswitch node: time zone support; do not mark as misconfigured when sunrise/sunset not used and lat/lon not given (#757) * timeswitch node: a) do not mark node as misconfigured if sunrise and sunset are not used and latitude/longitude are not given. b) support for specifying time zone when on and/or off times are not specified as sunrise and/or sunset. * Replaced moment dependency with spacetime * Timezone defaults to UTC for compatibility with previous node version --- time/timeswitch/package.json | 1 + time/timeswitch/timeswitch.html | 646 +++++++++++++++++++++++++++++++- time/timeswitch/timeswitch.js | 9 +- 3 files changed, 649 insertions(+), 7 deletions(-) diff --git a/time/timeswitch/package.json b/time/timeswitch/package.json index acaf2bf0..6d0fca3b 100644 --- a/time/timeswitch/package.json +++ b/time/timeswitch/package.json @@ -3,6 +3,7 @@ "version" : "0.0.8", "description" : "A Node-RED node to provide a simple timeswitch to schedule daily on/off events.", "dependencies" : { + "spacetime": "^6.12.5", "suncalc": "^1.8.0" }, "repository" : { diff --git a/time/timeswitch/timeswitch.html b/time/timeswitch/timeswitch.html index 910cca6a..52506229 100644 --- a/time/timeswitch/timeswitch.html +++ b/time/timeswitch/timeswitch.html @@ -214,6 +214,616 @@ +
+ + +
+
@@ -280,6 +890,15 @@ @@ -73,6 +90,10 @@
+
+ + +
@@ -98,6 +119,9 @@ join: {value:false}, sendObject: {value:false} }, + credentials: { + password: {type:"password"} + }, inputs:1, outputs:0, icon: "xmpp.png", @@ -107,6 +131,16 @@ }, labelStyle: function() { return (this.name)?"node_label_italic":""; + }, + oneditprepare: function() { + $('#node-input-join').change(function() { + if ($("#node-input-join").is(':checked') && $("#node-input-to").val() && $("#node-input-to").val().indexOf(':') === -1) { $("#node-room-pwd").show(); } + else { $("#node-room-pwd").hide(); } + }); + $('#node-input-to').change(function() { + if ($("#node-input-join").is(':checked') && $("#node-input-to").val() && $("#node-input-to").val().indexOf(':') === -1) { $("#node-room-pwd").show(); } + else { $("#node-room-pwd").hide(); } + }); } }); @@ -127,7 +161,7 @@
- +
diff --git a/social/xmpp/92-xmpp.js b/social/xmpp/92-xmpp.js index 7219c06e..d7eb0f7b 100644 --- a/social/xmpp/92-xmpp.js +++ b/social/xmpp/92-xmpp.js @@ -119,8 +119,8 @@ module.exports = function(RED) { } if (RED.settings.verbose || LOGITALL) {that.log("Culprit: "+that.lastUsed.id); } if (typeof that.lastUsed !== "undefined") { - that.lastUsed.status({fill:"red",shape:"ring",text:"error "+text}); - that.lastUsed.warn("Error "+text); + that.lastUsed.status({fill:"yellow",shape:"dot",text:"warning. "+text}); + that.lastUsed.warn("Warning. "+text); if (that.lastUsed.join) { // it was trying to MUC things up clearMUC(that); @@ -260,6 +260,15 @@ module.exports = function(RED) { xml("history", {maxstanzas:0, seconds:1}) // We don't want any history ) ); + if (node.hasOwnProperty("credentials") && node.credentials.hasOwnProperty("password")) { + stanza = xml('presence', + {"to":name}, + xml("x",'http://jabber.org/protocol/muc', + xml("history", {maxstanzas:0, seconds:1}), // We don't want any history + xml("password", {}, node.credentials.password) // Add the password + ) + ); + } node.serverConfig.used(node); node.serverConfig.MUCs[mu] = "joined"; if (RED.settings.verbose || LOGITALL) { node.log("JOINED "+mu); } @@ -458,6 +467,29 @@ module.exports = function(RED) { // this isn't for us, let the config node deal with it. } else { + if (stanza.attrs.type === 'error') { + var error = stanza.getChild('error'); + if (error.attrs.code) { + try { + var reas = error.toString().split('><')[1].split(" xml")[0].trim(); + if (reas == "registration-required") { reas = "membership-required"; } + } + catch(e) {}; + var msg = { + topic:stanza.attrs.from, + payload: { + code:error.attrs.code, + status:"error", + reason:reas, + name:node.serverConfig.MUCs[stanza.attrs.from.split('/')[0]] + } + }; + node.send([null,msg]); + node.status({fill:"red",shape:"ring",text:"error : "+error.attrs.code+", "+error.attrs.type+", "+reas}); + node.error(error.attrs.type+" error. "+error.attrs.code+" "+reas,msg); + } + } + var state = stanza.getChild('show'); if (state) { state = state.getText(); } else { state = "available"; } @@ -573,7 +605,11 @@ module.exports = function(RED) { node.serverConfig.deregister(node, done); }); } - RED.nodes.registerType("xmpp in",XmppInNode); + RED.nodes.registerType("xmpp in",XmppInNode,{ + credentials: { + password: {type: "password"} + } + }); function XmppOutNode(n) { @@ -653,8 +689,27 @@ module.exports = function(RED) { }); xmpp.on('stanza', async (stanza) => { - // if (stanza.is('presence')) { - // } + if (stanza.attrs.type === 'error') { + var error = stanza.getChild('error'); + if (error.attrs.code) { + try { + var reas = error.toString().split('><')[1].split(" xml")[0].trim(); + if (reas == "registration-required") { reas = "membership-required"; } + } + catch(e) {}; + var msg = { + topic:stanza.attrs.from, + payload: { + code:error.attrs.code, + status:"error", + reason:reas, + name:node.serverConfig.MUCs[stanza.attrs.from.split('/')[0]] + } + }; + node.status({fill:"red",shape:"ring",text:"error : "+error.attrs.code+", "+error.attrs.type+", "+reas}); + node.error(error.attrs.type+" error. "+error.attrs.code+" "+reas,msg); + } + } }); //register with config @@ -723,16 +778,15 @@ module.exports = function(RED) { // joinMUC will do nothing if we're already joined joinMUC(node, xmpp, to+'/'+node.nick); } - // if (msg.subject) { - // var stanza = xml( - // "message", - // { type:type, to:to }, - // xml("subject", {}, msg.subject.toString()) - // ); - // node.serverConfig.used(node); - // console.log("SENDING",stanza.toString()) - // xmpp.send(stanza); - // } + if (msg.subject) { + var stanza = xml( + "message", + { type:type, to:to, from:node.serverConfig.jid }, + xml("subject", {}, msg.subject.toString()) + ); + node.serverConfig.used(node); + xmpp.send(stanza); + } if (node.sendAll) { message = xml( "message", @@ -756,8 +810,10 @@ module.exports = function(RED) { ); } } - node.serverConfig.used(node); - xmpp.send(message); + if (message) { + node.serverConfig.used(node); + xmpp.send(message); + } } } }); @@ -768,5 +824,9 @@ module.exports = function(RED) { node.serverConfig.deregister(node, done); }); } - RED.nodes.registerType("xmpp out",XmppOutNode); + RED.nodes.registerType("xmpp out",XmppOutNode,{ + credentials: { + password: {type: "password"} + } + }); } diff --git a/social/xmpp/package.json b/social/xmpp/package.json index 4bafae0a..67f60f84 100644 --- a/social/xmpp/package.json +++ b/social/xmpp/package.json @@ -1,6 +1,6 @@ { "name": "node-red-node-xmpp", - "version": "0.4.2", + "version": "0.5.0", "description": "A Node-RED node to talk to an XMPP server", "dependencies": { "@xmpp/client": "^0.12.0" From fe42b6971279e3ea212cf7c8b63bc2b9743922a0 Mon Sep 17 00:00:00 2001 From: Dave Conway-Jones Date: Thu, 11 Mar 2021 19:09:13 +0000 Subject: [PATCH 36/88] let daemon accept real json array of parameters to close #768 --- utility/daemon/daemon.html | 1 + utility/daemon/daemon.js | 9 ++++++++- utility/daemon/package.json | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/utility/daemon/daemon.html b/utility/daemon/daemon.html index 8b89688c..2d932800 100644 --- a/utility/daemon/daemon.html +++ b/utility/daemon/daemon.html @@ -52,6 +52,7 @@ diff --git a/analysis/mlsentiment/mlsentiment.html b/analysis/mlsentiment/mlsentiment.html index d6b75a8e..c8394fe5 100644 --- a/analysis/mlsentiment/mlsentiment.html +++ b/analysis/mlsentiment/mlsentiment.html @@ -118,35 +118,6 @@ - - diff --git a/function/PID/pidcontrol.html b/function/PID/pidcontrol.html index 06116a32..005808b4 100644 --- a/function/PID/pidcontrol.html +++ b/function/PID/pidcontrol.html @@ -24,14 +24,6 @@ The damping factors are typically in the range 0 - 1.
- - - - diff --git a/function/smooth/17-smooth.html b/function/smooth/17-smooth.html index 75103f05..81643a1b 100644 --- a/function/smooth/17-smooth.html +++ b/function/smooth/17-smooth.html @@ -45,16 +45,6 @@
Tip: This node ONLY works with numbers.
- - diff --git a/hardware/Arduino/35-arduino.html b/hardware/Arduino/35-arduino.html index b492fa28..dd509759 100644 --- a/hardware/Arduino/35-arduino.html +++ b/hardware/Arduino/35-arduino.html @@ -24,14 +24,6 @@
- - - - + + diff --git a/hardware/pigpiod/locales/en-US/pi-gpiod.html b/hardware/pigpiod/locales/en-US/pi-gpiod.html new file mode 100644 index 00000000..471b6c10 --- /dev/null +++ b/hardware/pigpiod/locales/en-US/pi-gpiod.html @@ -0,0 +1,33 @@ + + + + diff --git a/hardware/pigpiod/pi-gpiod.html b/hardware/pigpiod/pi-gpiod.html index 7d5a39f9..113028a5 100644 --- a/hardware/pigpiod/pi-gpiod.html +++ b/hardware/pigpiod/pi-gpiod.html @@ -167,22 +167,6 @@
- - - - + + diff --git a/hardware/sensehat/sensehat.html b/hardware/sensehat/sensehat.html index 41c42dd6..c85cce2b 100644 --- a/hardware/sensehat/sensehat.html +++ b/hardware/sensehat/sensehat.html @@ -1,132 +1,33 @@ - - - - - - - - - - - + + + + + + diff --git a/social/irc/91-irc.html b/social/irc/91-irc.html index 2849914d..f3a00627 100644 --- a/social/irc/91-irc.html +++ b/social/irc/91-irc.html @@ -15,64 +15,6 @@
- - - - - - + + diff --git a/social/notify/57-notify.html b/social/notify/57-notify.html index fe3244a2..db576917 100644 --- a/social/notify/57-notify.html +++ b/social/notify/57-notify.html @@ -10,13 +10,6 @@ - - diff --git a/storage/leveldb/67-leveldb.html b/storage/leveldb/67-leveldb.html index 60b75414..ae7969ce 100644 --- a/storage/leveldb/67-leveldb.html +++ b/storage/leveldb/67-leveldb.html @@ -6,7 +6,7 @@
- + - - - - +
@@ -276,6 +276,10 @@ $("#node-input-criteria").val("UNSEEN"); this.criteria = "UNSEEN"; } + if (typeof this.autotls === 'undefined') { + $("#node-input-autotls").val("never"); + this.autotls = "never"; + } if ($("#node-input-fetch").val() === null) { $("#node-input-fetch").val("auto"); } $("#node-input-fetch").change(function() { if ($("#node-input-fetch").val() === "trigger") { diff --git a/social/email/locales/de/61-email.json b/social/email/locales/de/61-email.json index 6d4b87a4..575774f0 100644 --- a/social/email/locales/de/61-email.json +++ b/social/email/locales/de/61-email.json @@ -16,10 +16,6 @@ "folder": "Verzeichnis", "protocol": "Protokoll", "useSSL": "SSL", - "autotls": "STARTTLS?", - "never": "nie", - "required": "wenn erforderlich", - "always": "immer", "useTLS": "TLS", "disposition": "Behandlung", "none": "Keine", @@ -33,7 +29,11 @@ "seen": "Gesichtet", "unanswered": "Unbeantwortet", "unflagged": "Unmarkiert", - "unseen": "Ungesehen" + "unseen": "Ungesehen", + "autotls": "STARTTLS?", + "never": "nie", + "required": "wenn erforderlich", + "always": "immer" }, "default-message": "__description__\n\nDatei von Node-RED ist angehängt: __filename__", "tip": { diff --git a/social/email/locales/en-US/61-email.json b/social/email/locales/en-US/61-email.json index 7d22c313..6203c6e7 100644 --- a/social/email/locales/en-US/61-email.json +++ b/social/email/locales/en-US/61-email.json @@ -16,7 +16,6 @@ "folder": "Folder", "protocol": "Protocol", "useSSL": "Use SSL?", - "autotls": "STARTTLS?", "useTLS": "Use TLS?", "disposition": "Disposition", "none": "None", @@ -30,7 +29,11 @@ "seen": "Seen", "unanswered": "Unanswered", "unflagged": "Unflagged", - "unseen": "Unseen" + "unseen": "Unseen", + "autotls": "Start TLS?", + "never": "never", + "required": "if required", + "always": "always" }, "default-message": "__description__\n\nFile from Node-RED is attached: __filename__", "tip": { diff --git a/social/email/locales/ja/61-email.json b/social/email/locales/ja/61-email.json index 0938a236..27f3b597 100644 --- a/social/email/locales/ja/61-email.json +++ b/social/email/locales/ja/61-email.json @@ -16,7 +16,11 @@ "none": "なし", "read": "既読", "delete": "削除", - "criteriaFromMsg": "- msg.criteriaから使用 -" + "criteriaFromMsg": "- msg.criteriaから使用 -", + "autotls": "TLSを開始?", + "never": "なし", + "always": "常時", + "required": "必要な場合" }, "default-message": "__description__\n\nNode-REDからファイルが添付されました: __filename__", "tip": { diff --git a/social/email/package.json b/social/email/package.json index e6371f5c..2ff69660 100644 --- a/social/email/package.json +++ b/social/email/package.json @@ -1,11 +1,11 @@ { "name": "node-red-node-email", - "version": "1.11.1", + "version": "1.12.0", "description": "Node-RED nodes to send and receive simple emails.", "dependencies": { "imap": "^0.8.19", "poplib": "^0.1.7", - "mailparser": "^3.1.0", + "mailparser": "^3.2.0", "nodemailer": "~6.5.0", "smtp-server": "^3.8.0" },