Hey there
I am developing a custom node. When I do not enter valid input for rectangleItems the node succeeds, however as soon as I enter some values for rectangleItems the node stops working and I get the error in the console: WebSocket connection to 'ws://localhost:1880/comms' failed
See my code:
`var HTTPS = require('https');
var XML = require('pixl-xml');
const sihelper = require("./siwall-helper.js")
var _action = 'CreateViewAndSetOnScreen';
module.exports = function (RED) {
function SiWallCreateViewAndSetOnScreen(config) {
RED.nodes.createNode(this, config);
var node = this;
this.server = RED.nodes.getNode(config.server);
if (this.server) {
node.on('input', function (msg) {
node.send("trying to start")
if (!msg.screen) { msg.screen = config.screen }
if (!msg.rectangleItems) { msg.rectangleItems = config.rectangleItems }
if (msg.screen && msg.rectangleItems) {
// Construct SOAP request payload
var xmls = sihelper.SetSoapPayload(
_action,
`<v1:CreateViewAndSetOnScreen>
<v1:screenId>${msg.screen}</v1:screenId>
<v1:rectangleItems>${msg.rectangleItems}</v1:rectangleItems>
</v1:CreateViewAndSetOnScreen>`
);
node.send(xmls)
node.send("start")
callback = function (response) {
var str = ''
response.on('data', function (chunk) {
str += chunk;
});
response.on('end', function () {
var _xml = XML.parse(str);
var result = _xml['s:Body']['CreateViewAndSetOnScreenResponse']['CreateViewAndSetOnScreenResult'];
if (result == 'false'){
node.status({fill: 'red', shape: 'ring', text: result + 'check if you configured everything correctly'});
}
if (result == 'true'){
node.status({fill: 'green', shape: 'ring', text: "success"});
}
msg.payload = result;
node.send(msg);
});
}
var req = HTTPS.request(sihelper.SetSoapOptions(this.server.host, this.server.port, _action), callback);
req.on('error', function(err) {
if(err.code == 'ENOTFOUND'){
node.status({fill: 'red', shape: 'ring', text: 'host not reachable' });
msg.payload = 'Check Server Connection';
} else if(err.code == 'ECONNREFUSED'){
node.status({fill: 'red', shape: 'ring', text: 'VMS not reachable' });
msg.payload = 'Check if Siveillance Video Client is running';
} else {
node.status({fill: 'red', shape: 'ring', text: err.code });
msg.payload = err.message;
}
node.send(msg);
});
req.write(xmls);
req.end();
}
else {
msg.payload = 'Error: msg.screen or msg.rectangleItems not set';
node.status({ fill: 'red', shape: 'ring', text: msg.payload });
node.send(msg);
}
});
}
}
RED.nodes.registerType("siwall-createviewandsetonscreen", SiWallCreateViewAndSetOnScreen);
}
`
`<script type="text/javascript">
RED.nodes.registerType('siwall-createviewandsetonscreen', {
category: 'SiWall',
paletteLabel: 'CreateViewAndSetOnScreen',
color: '#009999',
defaults: {
name: { value: "CreateViewAndSetOnScreen" },
server: { value: "", type: "siwall-server" },
screen: { value: 0 },
rectangleItems: { value: "" },
},
inputs: 1,
outputs: 1,
icon: "font-awesome/fa-plus-square",
align: 'left',
inputLabels: "msg.screen: number, msg.rectangleItems: list of rectangleItem",
label: function () {
return this.name || "SiWall CreateViewAndSetOnScreen";
},
oneditprepare: function () {
const scope = this;
let screenOptions = [];
// variables used for initizalizing icons
let manualScreen = true;
function manualInputScreen() {
// GET CURRENT SELECTED VALUE
var current = $('#node-input-screen').val();
// REMOVE SELECT FIELD
$('#input-select-toggle-screen').empty();
// CREATE NEW INPUT FIELD
$('#input-select-toggle-screen').append('<input type="number" id="node-input-screen" placeholder=0 style="width: 100%" value="' + current + '" />');
// CHANGE BUTTON ICON
var button = $("#node-config-input-scan-screens");
var buttonIcon = button.find("i");
buttonIcon.removeClass("fa-pencil");
buttonIcon.addClass("fa-search");
}
function searchAndSelectScreen() {
// Aktuell ausgewählten Server auslesen
var server = RED.nodes.node($('#node-input-server option:selected').val());
// View auslesen
var current = $('#node-input-screen').val();
// Benachrichtigung für Views Suche auslösen
var notification = RED.notify(scope._("Searching all Screens..."), { type: "compact", modal: true, fixed: true });
if (server) {
_address = server.host;
_port = server.port;
$.getJSON('siwall-getscreens?host=' + _address + '&port=' + _port, function (data) {
// Optionen für dropdown vorbereiten
data.forEach(function (screen) {
//if (camera.value)
screenOptions[screen['b:Id']] = { value: screen['b:Id'], label: screen['b:Name'] };
});
})
.done(function () {
// Alle Screens in dropdown darstellen & aktuelle vorselektieren
$("#node-input-screen").typedInput({
types: [
{
value: current,
options: Object.values(screenOptions)
}
]
});
// Icon von Knopf ändern
var button = $("#node-config-input-scan-screens");
var buttonIcon = button.find("i");
buttonIcon.removeClass("fa-search");
buttonIcon.addClass("fa-pencil");
}).fail(function () {
RED.notify(scope._("Request error"), "error");
})
.always(function () {
// CLOSE SEARCH NOTIFICATION
notification.close();
})
}
else {
//No Server configured
notification.close();
RED.notify(scope._("No Server configured"), "error");
return false;
}
}
// TOGGLE SELECT/INPUT FIELD for Screens
$('#node-config-input-scan-screens').click(function () {
if (!manualScreen) {
manualInputScreen();
}
else {
searchAndSelectScreen();
}
manualScreen = !manualScreen
});
// Function to add a new rectangleItem input fields
function addRectangleItem() {
const rectangleItemTemplate = `
<div class="rectangle-item">
<div>
<label>Height: </label>
<input type="number" class="rectangle-height" required>
</div>
<br/>
<div>
<label>Width: </label>
<input type="number" class="rectangle-width" required
</div>
<br/>
<br/>
<div>
<label>X-Coordinate: </label>
<input type="number" class="rectangle-x" required>
</div>
<br/>
<div>
<label>Y-Coordinate: </label>
<input type="number" class="rectangle-y" required>
</div>
<br/>
<button class="delete-rectangle-item red-ui-button" type="button" style="color:red"><i class="fa fa-trash"></i></button>
<br/>
<br/>
</div>`;
$('#rectangleItemsContainer').append(rectangleItemTemplate);
}
// Function to delete a rectangleItem when the delete button is clicked
$('#rectangleItemsContainer').on('click', '.delete-rectangle-item', function () {
$(this).closest('.rectangle-item').remove();
});
// Event listener for adding a new rectangleItem
$('#addRectangleItemBtn').click(addRectangleItem);
},
oneditsave: function () {
var rectangleItemsArray = [];
$('.rectangle-item').each(function () {
var rectangleItem = {
height: $(this).find('.rectangle-height').val(),
width: $(this).find('.rectangle-width').val(),
xCoordinate: $(this).find('.rectangle-x').val(),
yCoordinate: $(this).find('.rectangle-y').val()
};
// Build rectangleItems XML based on msg.rectangleItems array
var rectangleItemXML = `<siw:RectangleItem><siw:Height>${rectangleItem.height}</siw:Height><siw:Width>${rectangleItem.width}</siw:Width><siw:X>${rectangleItem.xCoordinate}</siw:X><siw:Y>${rectangleItem.yCoordinate}</siw:Y></siw:RectangleItem>`;
rectangleItemsArray += rectangleItemXML
});
// Save the rectangleItems array into the node's configuration
this.rectangleItems = rectangleItemsArray;
// Calling the default oneditsave function to save other properties
console.log(this)
}
});
</script>
<script type="text/html" data-template-name="siwall-createviewandsetonscreen">
<div class="form-row">
<h2>Create View and set on Screen X</h2>
<b>Please ensure, that the Siveillance Video Client is running,
<br />the right user is logged in,
<br />and the SiWall Plugin ist installed and licensed.
<br /><br />
</b>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
<div class="form-row">
<label for="node-input-server"><i class="fa fa-server"></i> Server</label>
<input type="text" id="node-input-server" required>
</div>
<div class="form-row">
<label for="node-input-screen"><i class="fa fa-window-maximize"></i> Screen</label>
<div style="display: inline-flex; width: 70%">
<div id="input-select-toggle-screen" style="flex-grow: 1;">
<input type="number" id="node-input-screen" placeholder=0 style="width: 100%" title="screen" required>
</div>
<button id="node-config-input-scan-screens" type="button" class="red-ui-button" style="margin-left: 10px;">
<i class="fa fa-search"></i>
</button>
</div>
</div>
<div class="form-row">
<h3>View Windows</h3>
<div for="node-input-rectangleItems" id="rectangleItemsContainer">
<!-- This container will hold dynamically added rectangleItems -->
</div>
<button id="addRectangleItemBtn" type="button" class="red-ui-button"><i class="fa fa-plus"></i></button>
</div>
</div>
<div class="form-row">
<br/>
<h3>Node Message input:</h3>
<b>msg.screen = number</b><br/>
<b>example : </b>0<br/>
<br/>
<b>msg.rectangleItems = list of rectangleitem</b><br/>
<br/>
<h3>Node Message output:</h3>
<b>msg.payload = true / false</b><br/>
<b>true : </b>Success<br/>
<b>false : </b>Failed<br/>
</div>
</script>
<script type="text/html" data-help-name="siwall-createviewandsetonscreen">
<p>Node that creates a view and sets that on screen x</p>
<h3>Input</h3>
<dl class="message-properties">
<dt>screen<span class="property-type">string</span></dt>
<dd>
The screen on which the view should be created.
</dd>
</dl>
<h3>Outputs</h3>
<dl class="message-properties">
<dt>payload<span class="property-type">boolean</span></dt>
<dd>
It returns true if the view has been set on the desired screen.<br>
Returns false when there was an error.
</dd>
</dl>
</script>
Thanks for your help!