node-red-contrib-hikvision-ultimate
Version:
A native set of nodes for Hikvision (and compatible) Cameras, Alarms, Radars, NVR, Doorbells, etc.
332 lines (312 loc) • 13.3 kB
HTML
<script type="text/javascript">
RED.nodes.registerType('hikvisionUltimatePicture', {
category: 'Hikvision Ultimate',
color: '#C0C0C0',
defaults: {
name: { value: "" },
topic: { value: "" },
server: { type: "Hikvision-config", required: true },
channelID: { value: "1" },
rotateimage: { value: "0" },
heightimage: { value: "" },
widthimage: { value: "" },
qualityimage: { value: "100" },
cropimage: { value: "" },
textoverlay: { value: "" },
textoverlayXY: { value: "0,0" },
textoverlayWH: { value: "0,0" },
textoverlayFont: { value: "FONT_SANS_32_WHITE" },
urlImageCurrentIndex: { value: 0 }
},
inputs: 1,
outputs: 2,
outputLabels: function (i) {
var ret = "";
switch (i) {
case 0:
return "Picture";
break;
case 1:
return "Error";
break;
default:
break;
}
},
icon: "camera-icon.svg",
label:
function () {
var label = "Picture"
if (this.name !== undefined && this.name.length > 0) {
label = this.name;
}
return label;
},
paletteLabel: function () {
return "Picture";
},
oneditprepare: function () {
var oNodeServer = RED.nodes.node($("#node-input-server").val()); // Store the config-node
// Timer
var tImage = null;
var bAlreadyIn = false;
this.timerRetryAnotherURL = null;
// 19/02/2020 Used to alert the user if the CSV file has not been loaded and to get the server sooner als deploy
// ###########################
$("#node-input-server").change(function () {
try {
oNodeServer = RED.nodes.node($(this).val());
$("#picture").html("<span>Click the <b>Refresh Image</b> button to get the picture from the camera</span>");
//if (oNodeServer !== null && oNodeServer !== undefined) readPictureFromCamera(oNodeServer, true);
} catch (error) {
}
});
// ###########################
function readPictureFromCamera(_oNodeServer, _beginRightURLSearchFromStart) {
if (bAlreadyIn) return;
bAlreadyIn = true;
$("#picture").html("<img src=\"https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/loading.gif\">");
// Prepare the manipulation string
var sManipulate = $("#node-input-channelID").val();
sManipulate += "-SEP-" + $("#node-input-qualityimage").val();
sManipulate += "-SEP-" + $("#node-input-rotateimage").val();
sManipulate += "-SEP-" + $("#node-input-widthimage").val();
sManipulate += "-SEP-" + $("#node-input-heightimage").val();
sManipulate += "-SEP-" + $("#node-input-cropimage").val().toString().trim().replace(/\s/g, '').replace(/,/g, "-");
sManipulate += "-SEP-" + $("#node-input-textoverlay").val();
sManipulate += "-SEP-" + $("#node-input-textoverlayXY").val().toString().trim().replace(/\s/g, '').replace(/,/g, "-");
sManipulate += "-SEP-" + $("#node-input-textoverlayWH").val().toString().trim().replace(/\s/g, '').replace(/,/g, "-");
sManipulate += "-SEP-" + $("#node-input-textoverlayFont").val();
sManipulate += "-SEP-" + (_beginRightURLSearchFromStart ? "YES" : "NO"); // Begin cycling right picture URL from the beginning?
$.getJSON('hikvisionUltimateGetPicture?serverID=' + _oNodeServer.id + "&manipulate=" + sManipulate, (data) => {
$("#picture").html("<img src=\"" + data.picture + "\" style=\"width:320px;height:200px;\" \">");
$("#picturedimensions").html("Width:" + data.width + "px" + " Height:" + data.height + "px");
bAlreadyIn = false;
// Check the return string to understand wether i must retry with another image URL or not
if (data.width.toString().toLowerCase().includes("retry")) {
// Retry
RED.notify("Problem getting image. Trying another URL...",
{
modal: false,
fixed: false,
type: 'info'
})
setTimeout(() => {
if (this.timerRetryAnotherURL !== null) clearTimeout(this.timerRetryAnotherURL);
readPictureFromCamera(oNodeServer, false);
}, 1000);
} else if (data.width.toString().toLowerCase().includes("error")) {
// I've cycled to all URLS, so the .js returns "Error"
RED.notify("Unable to get the image.",
{
modal: false,
fixed: false,
type: 'error'
})
} else if (data.hasOwnProperty("urlImageCurrentIndex")) {
// The image returned is OK and the .js tells me the index of the URL's Array.
$("#node-input-urlImageCurrentIndex").val(data.urlImageCurrentIndex);
}
}).error(function (jqXHR, textStatus, errorThrown) {
bAlreadyIn = false;
$("#picture").html("<span>THIS NODE IS NEW. PLEASE SAVE AND DEPLOY FIRST! <br/> THEN CLICK AGAIN THE BUTTON.</span>");
// SAVE FIRST!
RED.notify("THIS NODE IS NEW. PLEASE SAVE AND DEPLOY FIRST! THEN CLICK AGAIN THE BUTTON.",
{
modal: false,
fixed: false,
type: 'error'
});
});
}
$("#getinfocam").click(function () {
if ($("#node-input-widthimage").val() !== "" && Number($("#node-input-widthimage").val()) > 9999) {
RED.notify("Max value for width is 9999",
{
modal: false,
fixed: false,
type: 'warning'
})
return;
}
if ($("#node-input-heightimage").val() !== "" && Number($("#node-input-heightimage").val()) > 9999) {
RED.notify("Max value fot height is 9999",
{
modal: false,
fixed: false,
type: 'warning'
})
return;
}
if ($("#node-input-cropimage").val().split(",").length !== 4) {
if ($("#node-input-cropimage").val() !== undefined && $("#node-input-cropimage").val() !== "") {
RED.notify("Check the CROP string. Must be: x,y,width,height",
{
modal: false,
fixed: false,
type: 'warning'
})
return;
}
}
readPictureFromCamera(oNodeServer, true);
});
},
oneditsave: function () {
if (this.timerRetryAnotherURL !== null) clearTimeout(this.timerRetryAnotherURL);
}
});
</script>
<script type="text/x-red" data-template-name="hikvisionUltimatePicture">
<div class="form-row">
<b>Picture node</b>    <span style="color:red"><i class="fa fa-question-circle"></i> <a target="_blank" href="https://github.com/Supergiovane/node-red-contrib-hikvision-ultimate"><u>Help online</u></a></span>
<br/>
<br/>
<label for="node-input-server">Server</label>
<input type="text" id="node-input-server" />
</div>
<div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
<div class="form-row">
<label for="node-input-topic"><i class="fa fa-tasks"></i> Node topic</label>
<input type="text" id="node-input-topic" placeholder="Node's own topic">
</div>
<div class="form-row">
<label for="node-input-channelID"><i class="fa fa-tasks"></i> Camera</label>
<select id="node-input-channelID">
<option value="1">1 (DEFAULT)</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
<option value="13">13</option>
<option value="14">14</option>
<option value="15">15</option>
<option value="16">16</option>
<option value="17">17</option>
<option value="18">18</option>
<option value="19">19</option>
<option value="20">20</option>
<option value="21">21</option>
<option value="22">22</option>
<option value="23">23</option>
<option value="24">24</option>
<option value="25">25</option>
<option value="26">26</option>
<option value="27">27</option>
<option value="28">28</option>
<option value="29">29</option>
<option value="30">30</option>
<option value="31">31</option>
<option value="32">32</option>
</select>
<div class="form-tips" style="margin-top:11px">
Above option: Leave 1 if your camera has only one channel (most of the time)
</div>
</div>
<div class="form-row">
<p align="center" id="picture"><img src="https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/loading.gif"></p>
<p align="center" id="picturedimensions"></p>
</div>
<div class="form-row">
<label> <i class="fa fa-sign-in"></i> Image</label>
<input type="button" id="getinfocam" class="ui-button ui-corner-all ui-widget" style="background-color:#AEE1FF;width:150px" value="Refresh Image">
</div>
<div class="form-row">
<label for="node-input-qualityimage"><i class="fa fa-tasks"></i> Jpeg Quality</label>
<select id="node-input-qualityimage">
<option value="100">100 (Unchanged)</option>
<option value="90">90</option>
<option value="80">80</option>
<option value="70">70</option>
<option value="60">60</option>
<option value="50">50</option>
<option value="40">40</option>
<option value="30">30</option>
<option value="20">20</option>
<option value="10">10</option>
</select>
</div>
<div class="form-row">
<label for="node-input-rotateimage"><i class="fa fa-tasks"></i> Rotate</label>
<select id="node-input-rotateimage">
<option value="0">No</option>
<option value="45">45°</option>
<option value="90">90°</option>
<option value="135">135°</option>
<option value="180">180°</option>
<option value="225">225°</option>
</select>
</div>
<div class="form-row">
<label for="node-input-widthimage"><i class="fa fa-tasks"></i> Max Width</label>
<input type="text" id="node-input-widthimage" placeholder="Leave as is">
</div>
<div class="form-row">
<label for="node-input-heightimage"><i class="fa fa-tasks"></i> Max Height</label>
<input type="text" id="node-input-heightimage" placeholder="Leave as is">
<div class="form-tips" style="margin-top:11px">
Above options: Resizes the image. Set the MAX width and height in pixels. Leave empty not to resize. If you specify one max dimension, you MUST specify BOTH! Otherwise, leave all blank.
</div>
</div>
<div class="form-row">
<label for="node-input-cropimage"><i class="fa fa-tasks"></i> Crop</label>
<input type="text" id="node-input-cropimage" placeholder="Leave as is">
<div class="form-tips" style="margin-top:11px">
Above options: Crop the image (get only a portion of image, for example, to zoom on a door). Accepted string is "x, y, width, height" for example "20,30,200,200". Leave blank not to crop.
</div>
</div>
<div class="form-row">
<label for="node-input-textoverlay"><i class="fa fa-tasks"></i> Text Overlay</label>
<input type="text" id="node-input-textoverlay" placeholder="No text">
</div>
<div class="form-row">
<label for="node-input-textoverlayXY"><i class="fa fa-tasks"></i> Position (X,Y)</label>
<input type="text" id="node-input-textoverlayXY" placeholder="Example 10,10">
</div>
<div class="form-row">
<label for="node-input-textoverlayWH"><i class="fa fa-tasks"></i> Max boundary (Width,Height)</label>
<input type="text" id="node-input-textoverlayWH" placeholder="Example 200,100">
</div>
<div class="form-row">
<label for="node-input-textoverlayFont"><i class="fa fa-tasks"></i> Font</label>
<select id="node-input-textoverlayFont">
<option value="FONT_SANS_8_BLACK">FONT_SANS_8_BLACK</option>
<option value="FONT_SANS_10_BLACK">FONT_SANS_10_BLACK</option>
<option value="FONT_SANS_12_BLACK">FONT_SANS_12_BLACK</option>
<option value="FONT_SANS_14_BLACK">FONT_SANS_14_BLACK</option>
<option value="FONT_SANS_16_BLACK">FONT_SANS_16_BLACK</option>
<option value="FONT_SANS_32_BLACK">FONT_SANS_32_BLACK</option>
<option value="FONT_SANS_64_BLACK">FONT_SANS_64_BLACK</option>
<option value="FONT_SANS_128_BLACK">FONT_SANS_128_BLACK</option>
<option value="FONT_SANS_8_WHITE">FONT_SANS_8_WHITE</option>
<option value="FONT_SANS_16_WHITE">FONT_SANS_16_WHITE</option>
<option value="FONT_SANS_32_WHITE">FONT_SANS_32_WHITE</option>
<option value="FONT_SANS_64_WHITE">FONT_SANS_64_WHITE</option>
<option value="FONT_SANS_128_WHITE">FONT_SANS_128_WHITE</option>
</select>
<div class="form-tips" style="margin-top:11px">
Above options: overlay a text over the image. You can set the X position from TOP and the Y position from LEFT, as well as the fonts. You can only choose between the list of avaiable fonts. You cannot currently add more than a row. You can override the overlayed text, by msg.textoverlay
</div>
</div>
<div class="form-row">
<input type="hidden" id="node-input-urlImageCurrentIndex" >
</div>
</script>
<script type="text/x-red" data-help-name="hikvisionUltimatePicture">
<p>
<a href="https://www.paypal.me/techtoday" target="_blank"><img src='https://img.shields.io/badge/Donate-PayPal-blue.svg?style=flat-square' width='30%'></a>
</p>
<p>
The node outputs the picture on PIN 1 and a connection ERROR on PIN 2 (true if the node is DISCONNECTED to the server, otherwise false IF IT'S RECONNECTED).
</p>
</script>