node-red-contrib-hikvision-ultimate
Advanced tools
Comparing version 1.1.18 to 1.1.19
@@ -7,2 +7,10 @@ <p align="center"><img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/logo.png' width="40%"></p> | ||
<p> | ||
<b>Version 1.1.19</b> April 2024<br/> | ||
- NEW: Speaker node.<br/> | ||
</p> | ||
<p> | ||
<b>Version 1.1.18</b> April 2024<br/> | ||
- ANPR: fixed an issue it the plate's list parser in cameras having ISAPI protocol 1.0.<br/> | ||
</p> | ||
<p> | ||
<b>Version 1.1.17</b> April 2024<br/> | ||
@@ -9,0 +17,0 @@ - ANPR: fixed an issue it the plate's list parser. Thanks @jpgnz.<br/> |
@@ -9,7 +9,4 @@ | ||
node.server = RED.nodes.getNode(config.server) | ||
node.avoidsameplatetime = config.avoidsameplatetime || 20; // Doesn't send the same plate in this timeframe, in seconds. | ||
node.currentPlate = ""; // Stores the current plate (for the avoidsameplatetime function) | ||
node.timerAvoidSamePlate = null; // Timer for avoiding repeating plate | ||
node.bAvoidSamePlate = false; | ||
node.setNodeStatus = ({ fill, shape, text }) => { | ||
@@ -27,19 +24,3 @@ var dDate = new Date(); | ||
if (node.currentPlate === _msg.payload) { | ||
if (node.bAvoidSamePlate) { | ||
try { node.setNodeStatus({ fill: "grey", shape: "ring", text: "Temporary block same plate " + _msg.payload }); } catch (error) { }; | ||
return; | ||
} | ||
} | ||
// Timer for avoiding same plate | ||
// ########################## | ||
if (node.timerAvoidSamePlate !== null) clearTimeout(node.timerAvoidSamePlate); | ||
node.bAvoidSamePlate = true; | ||
node.timerAvoidSamePlate = setTimeout(() => { | ||
node.bAvoidSamePlate = false; | ||
}, node.avoidsameplatetime * 1000); | ||
// ########################## | ||
node.currentPlate = _msg.payload; | ||
node.send([_msg, null]); | ||
@@ -58,3 +39,14 @@ try { | ||
this.on('input', function (msg) { | ||
if (msg.payload === true) { | ||
(async () => { | ||
msg.payload = await node.server.playAloud(config.customAudioID, config.volume); | ||
node.send([msg, null]) | ||
})(); | ||
} | ||
if (msg.payload === false) { | ||
(async () => { | ||
msg.payload = await node.server.stopFile(config.customAudioID); | ||
node.send([msg, null]) | ||
})(); | ||
} | ||
}); | ||
@@ -61,0 +53,0 @@ |
@@ -12,3 +12,3 @@ | ||
RED.nodes.createNode(this, config) | ||
var node = this | ||
var node = this; | ||
node.port = config.port || 80; | ||
@@ -23,3 +23,2 @@ node.debug = config.host.toString().toLowerCase().indexOf("banana") > -1; | ||
node.deviceinfo = config.deviceinfo || {}; | ||
node.timerCheckRing = null; | ||
var oReadable = new readableStr(); | ||
@@ -131,4 +130,4 @@ var controller = null; // AbortController | ||
const resInfo = await clientInfo.fetch(jParams.protocol + "://" + jParams.host + "/ISAPI/AccessControl/EventCardLinkageCfg/CustomAudio?format=json", opt); | ||
const body = await resInfo.text(); | ||
res.json(body); | ||
const body = await resInfo.json(); | ||
res.json(body.CustomAudioInfoList); | ||
return; | ||
@@ -139,3 +138,55 @@ } catch (error) { | ||
} | ||
})(); | ||
} catch (err) { | ||
res.json(err); | ||
} | ||
}); | ||
// 17/94/2024 Get the files | ||
RED.httpAdmin.get("/hikvisionUltimateSpeakerTest", RED.auth.needsPermission('Speakerconfig.read'), function (req, res) { | ||
var jParams = RED.nodes.getNode(req.query.nodeID).server;// Retrieve node.id of the config node. | ||
let customAudioID = req.query.customAudioID; | ||
var _nodeServer = null; | ||
var clientInfo; | ||
if (jParams.credentials.password === "__PWRD__") { | ||
// The password isn't changed or (the server node was already present, it's only updated) | ||
_nodeServer = RED.nodes.getNode(req.query.nodeID);// Retrieve node.id of the config node. | ||
if (jParams.authentication === "digest") clientInfo = new DigestFetch(jParams.credentials.user, _nodeServer.credentials.password); // Instantiate the fetch client. | ||
if (jParams.authentication === "basic") clientInfo = new DigestFetch(jParams.credentials.user, _nodeServer.credentials.password, { basic: true }); // Instantiate the fetch client. | ||
} else { | ||
// The node is NEW | ||
if (jParams.authentication === "digest") clientInfo = new DigestFetch(jParams.credentials.user, jParams.credentials.password); // Instantiate the fetch client. | ||
if (jParams.authentication === "basic") clientInfo = new DigestFetch(jParams.credentials.user, jParams.credentials.password, { basic: true }); // Instantiate the fetch client. | ||
} | ||
var opt = { | ||
// These properties are part of the Fetch Standard | ||
method: "PUT", | ||
headers: {}, // request headers. format is the identical to that accepted by the Headers constructor (see below) | ||
body: null, // request body. can be null, a string, a Buffer, a Blob, or a Node.js Readable stream | ||
redirect: 'follow', // set to `manual` to extract redirect headers, `error` to reject redirect | ||
signal: null, // pass an instance of AbortSignal to optionally abort requests | ||
// The following properties are node-fetch extensions | ||
follow: 20, // maximum redirect count. 0 to not follow redirect | ||
timeout: 5000, // req/res timeout in ms, it resets on redirect. 0 to disable (OS limit applies). Signal is recommended instead. | ||
compress: false, // support gzip/deflate content encoding. false to disable | ||
size: 0, // maximum response body size in bytes. 0 to disable | ||
agent: jParams.protocol === "https" ? customHttpsAgent : null // http(s).Agent instance or function that returns an instance (see below) | ||
}; | ||
try { | ||
(async () => { | ||
try { | ||
// const resInfo = await clientInfo.fetch(jParams.protocol + "://" + jParams.host + ":" + jParams.port + "/ISAPI/AccessControl/EventCardLinkageCfg/CustomAudio?format=json", opt); | ||
const resInfo = await clientInfo.fetch(jParams.protocol + "://" + jParams.host + "/ISAPI/Event/triggers/notifications/AudioAlarm/AudioOut/1/PlayCustomAudioFile?format=json&customAudioID=" + customAudioID + "&audioVolume=2&loopPlaybackTimes=1", opt); | ||
const body = await resInfo.json(); | ||
res.json({}); | ||
return; | ||
} catch (error) { | ||
RED.log.error("Errore hikvisionUltimateGetInfoSpeaker " + error.message); | ||
res.json(error); | ||
} | ||
})(); | ||
@@ -148,3 +199,83 @@ | ||
// PLAY THE FILE ALOUD VIA THE SPEAKER | ||
node.playAloud = async function (_customAudioID, _volume) { | ||
var jParams = node; | ||
var clientInfo; | ||
// Set Auth | ||
if (jParams.authentication === "digest") clientInfo = new DigestFetch(jParams.credentials.user, jParams.credentials.password); // Instantiate the fetch client. | ||
if (jParams.authentication === "basic") clientInfo = new DigestFetch(jParams.credentials.user, jParams.credentials.password, { basic: true }); // Instantiate the fetch client. | ||
var opt = { | ||
// These properties are part of the Fetch Standard | ||
method: "PUT", | ||
headers: {}, // request headers. format is the identical to that accepted by the Headers constructor (see below) | ||
body: JSON.stringify({ "audioOutID": [1] }), // request body. | ||
redirect: 'follow', // set to `manual` to extract redirect headers, `error` to reject redirect | ||
signal: null, // pass an instance of AbortSignal to optionally abort requests | ||
// The following properties are node-fetch extensions | ||
follow: 20, // maximum redirect count. 0 to not follow redirect | ||
timeout: 5000, // req/res timeout in ms, it resets on redirect. 0 to disable (OS limit applies). Signal is recommended instead. | ||
compress: false, // support gzip/deflate content encoding. false to disable | ||
size: 0, // maximum response body size in bytes. 0 to disable | ||
agent: jParams.protocol === "https" ? customHttpsAgent : null // http(s).Agent instance or function that returns an instance (see below) | ||
}; | ||
try { | ||
// STOP PLAYING PREVIOUS FILE, IF ANY | ||
const resInfoStop = await clientInfo.fetch(jParams.protocol + "://" + jParams.host + "/ISAPI/AccessControl/EventCardLinkageCfg/CustomAudio/" + _customAudioID + "/stop?format=json", opt); | ||
// PLAY THE FILE | ||
const resInfo = await clientInfo.fetch(jParams.protocol + "://" + jParams.host + "/ISAPI/Event/triggers/notifications/AudioAlarm/AudioOut/1/PlayCustomAudioFile?format=json&customAudioID=" + _customAudioID + "&audioVolume=" + _volume + "&loopPlaybackTimes=1", opt); | ||
const body = await resInfo.json(); | ||
if (body.statusCode === 1) { | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
} catch (error) { | ||
RED.log.error("Errore playAloud Stop " + error.message); | ||
return false; | ||
} | ||
}; | ||
node.stopFile = async function (_customAudioID) { | ||
var jParams = node; | ||
var clientInfo; | ||
// Set Auth | ||
if (jParams.authentication === "digest") clientInfo = new DigestFetch(jParams.credentials.user, jParams.credentials.password); // Instantiate the fetch client. | ||
if (jParams.authentication === "basic") clientInfo = new DigestFetch(jParams.credentials.user, jParams.credentials.password, { basic: true }); // Instantiate the fetch client. | ||
var opt = { | ||
// These properties are part of the Fetch Standard | ||
method: "PUT", | ||
headers: {}, // request headers. format is the identical to that accepted by the Headers constructor (see below) | ||
body: JSON.stringify({ "audioOutID": [1] }), // request body. | ||
redirect: 'follow', // set to `manual` to extract redirect headers, `error` to reject redirect | ||
signal: null, // pass an instance of AbortSignal to optionally abort requests | ||
// The following properties are node-fetch extensions | ||
follow: 20, // maximum redirect count. 0 to not follow redirect | ||
timeout: 5000, // req/res timeout in ms, it resets on redirect. 0 to disable (OS limit applies). Signal is recommended instead. | ||
compress: false, // support gzip/deflate content encoding. false to disable | ||
size: 0, // maximum response body size in bytes. 0 to disable | ||
agent: jParams.protocol === "https" ? customHttpsAgent : null // http(s).Agent instance or function that returns an instance (see below) | ||
}; | ||
// STOP PLAYING PREVIOUS FILE | ||
try { | ||
// const resInfo = await clientInfo.fetch(jParams.protocol + "://" + jParams.host + ":" + jParams.port + "/ISAPI/AccessControl/EventCardLinkageCfg/CustomAudio?format=json", opt); | ||
const resInfo = await clientInfo.fetch(jParams.protocol + "://" + jParams.host + "/ISAPI/AccessControl/EventCardLinkageCfg/CustomAudio/" + _customAudioID + "/stop?format=json", opt); | ||
const body = await resInfo.json(); | ||
if (body.statusCode === 1) { | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
} catch (error) { | ||
RED.log.error("Errore stopFile Stop " + error.message); | ||
return false; | ||
} | ||
} | ||
//#region "HANDLE STREAM MESSAGE" | ||
@@ -297,53 +428,5 @@ // Handle the complete stream message, enclosed into the --boundary stream string | ||
//#region GENERIC GET OT PUT CALL | ||
// Function to get or post generic data on device | ||
node.request = async function (_callerNode, _method, _URL, _body) { | ||
var clientGenericRequest; | ||
if (node.authentication === "digest") clientGenericRequest = new DigestFetch(node.credentials.user, node.credentials.password); // Instantiate the fetch client. | ||
if (node.authentication === "basic") clientGenericRequest = new DigestFetch(node.credentials.user, node.credentials.password, { basic: true }); // Instantiate the fetch client. | ||
var reqController = new AbortController(); // For aborting the stream request | ||
var options = { | ||
// These properties are part of the Fetch Standard | ||
method: _method.toString().toUpperCase(), | ||
headers: {}, // request headers. format is the identical to that accepted by the Headers constructor (see below) | ||
body: _body, // request body. can be null, a string, a Buffer, a Blob, or a Node.js Readable stream | ||
redirect: 'follow', // set to `manual` to extract redirect headers, `error` to reject redirect | ||
signal: reqController.signal, // pass an instance of AbortSignal to optionally abort requests | ||
// The following properties are node-fetch extensions | ||
follow: 20, // maximum redirect count. 0 to not follow redirect | ||
timeout: 8000, // req/res timeout in ms, it resets on redirect. 0 to disable (OS limit applies). Signal is recommended instead. | ||
compress: false, // support gzip/deflate content encoding. false to disable | ||
size: 0, // maximum response body size in bytes. 0 to disable | ||
agent: node.protocol === "https" ? customHttpsAgent : null // http(s).Agent instance or function that returns an instance (see below) | ||
}; | ||
try { | ||
if (!_URL.startsWith("/")) _URL = "/" + _URL; | ||
const response = await clientGenericRequest.fetch(node.protocol + "://" + node.host + _URL, options); | ||
if (response.ok) { | ||
try { | ||
const oReadable = readableStr.from(response.body, { encoding: 'utf8' }); | ||
oReadable.on('data', (chunk) => { | ||
if (node.debug) RED.log.error(chunk); | ||
}); | ||
} catch (error) { | ||
throw new Error("Error readableStream: " + error.message || ""); | ||
} | ||
} else { | ||
throw new Error("Error response: " + response.statusText || " unknown response code"); | ||
} | ||
} catch (error) { | ||
// Main Error | ||
if (node.debug) RED.log.error("Speaker-config: clientGenericRequest.fetch error " + error.message); | ||
throw (new Error("clientGenericRequest.fetch error:" + error.message)); | ||
} | ||
}; | ||
//#endregion | ||
//#region "FUNCTIONS" | ||
//#region "Base FUNCTIONS" | ||
node.on('close', function (removed, done) { | ||
@@ -350,0 +433,0 @@ if (controller !== null) { |
{ | ||
"name": "node-red-contrib-hikvision-ultimate", | ||
"version": "1.1.18", | ||
"version": "1.1.19", | ||
"description": "A native set of nodes for Hikvision (and compatible) Cameras, Alarms, Radars, NVR, Doorbells, etc.", | ||
@@ -37,6 +37,2 @@ "author": "Supergiovane (https://github.com/Supergiovane)", | ||
"nodes": { | ||
"Hikvision-config": "nodes/Hikvision-config.js", | ||
"AXPro-config": "nodes/AXPro-config.js", | ||
"Doorbell-config": "nodes/Doorbell-config.js", | ||
"ANPR-config": "nodes/ANPR-config.js", | ||
"AccessControl-config": "nodes/AccessControl-config.js", | ||
@@ -52,5 +48,11 @@ "hikvisionUltimateText": "nodes/hikvisionUltimateText.js", | ||
"hikvisionUltimateAxPro": "nodes/hikvisionUltimateAxPro.js", | ||
"hikvisionUltimateAccessControlTerminal": "nodes/hikvisionUltimateAccessControlTerminal.js" | ||
"hikvisionUltimateAccessControlTerminal": "nodes/hikvisionUltimateAccessControlTerminal.js", | ||
"hikvisionUltimateSpeaker": "/nodes/hikvisionUltimateSpeaker.js", | ||
"Hikvision-config": "nodes/Hikvision-config.js", | ||
"AXPro-config": "nodes/AXPro-config.js", | ||
"Doorbell-config": "nodes/Doorbell-config.js", | ||
"ANPR-config": "nodes/ANPR-config.js", | ||
"Speaker-config": "/nodes/Speaker-config.js" | ||
} | ||
} | ||
} |
<p align="center"><img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/logo.png' width="60%"></p> | ||
<p align="center"><img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/logo.png'></p> | ||
@@ -27,3 +27,3 @@ A native set of nodes for Hikvision (and compatible) Cameras, Alarms, Radars, NVR, Doorbells etc. | ||
For NVR/DVR, pleas remember to select "Notify Alarm Center" in the event window, otherwise the NVR won't emit any alarm event.<br/> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/NotifyCenter.png' width="30%"> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/NotifyCenter.png'> | ||
@@ -45,3 +45,3 @@ ## COLLABORATORS NEEDED | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/hikcamera.jpg' width="80%"> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/hikcamera.jpg' > | ||
@@ -55,3 +55,3 @@ The Camera Event node connects to ***NVR, Camera, Radars, etc..*** and outputs true/false in case of an alarm. <br/> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/GenericAlarm.png' width="80%"> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/GenericAlarm.png' > | ||
@@ -143,3 +143,3 @@ You can choose from many different alarms, including: <br/> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/hikanprcamera.jpg' width="80%"> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/hikanprcamera.jpg' > | ||
@@ -149,3 +149,3 @@ | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/ANPR.png' width="80%"> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/ANPR.png' > | ||
@@ -189,3 +189,3 @@ **Flow Messages** | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/hikptzcamera.png' width="80%"> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/hikptzcamera.png' > | ||
@@ -196,3 +196,3 @@ Recalls a PTZ pre-recorded preset.<br/> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/PTZ.png' width="80%"> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/PTZ.png' > | ||
@@ -244,3 +244,3 @@ **Flow Messages** | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/hikcamerasettings.png' width="80%"> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/hikcamerasettings.png' > | ||
@@ -254,3 +254,3 @@ This node gets a picture from the camera/NVR, ready to be shown in the dashboard UI.<br/> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/picture.png' width="80%"> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/picture.png' > | ||
@@ -285,3 +285,3 @@ <br/> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/pictureproperties.png' width="30%"> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/pictureproperties.png'> | ||
@@ -344,3 +344,3 @@ **Flow Messages** | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/Text.png' width="80%"> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/Text.png' > | ||
@@ -414,3 +414,3 @@ **Copy this code and paste it into your flow** | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/XML.png' width="80%"> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/XML.png' > | ||
@@ -533,3 +533,3 @@ | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/RawAlarm.png' width="80%"> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/RawAlarm.png' > | ||
@@ -598,3 +598,3 @@ **Flow Messages** | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/Doorbell.png' width="80%"> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/Doorbell.png' > | ||
@@ -684,3 +684,3 @@ **Copy this code and paste it into your flow** | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/axproPicture.jpg' width="80%"> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/axproPicture.jpg' > | ||
@@ -692,3 +692,3 @@ | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/axpro.png' width="80%"> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/axpro.png' > | ||
@@ -805,7 +805,7 @@ **Copy this code and paste it into your flow** | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/CIDEvents/1.png' width="100%"> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/CIDEvents/2.png' width="100%"> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/CIDEvents/3.png' width="100%"> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/CIDEvents/4.png' width="100%"> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/CIDEvents/5.png' width="100%"> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/CIDEvents/1.png' >> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/CIDEvents/2.png' >> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/CIDEvents/3.png' >> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/CIDEvents/4.png' >> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/CIDEvents/5.png' >> | ||
@@ -819,3 +819,3 @@ <br/> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/accesscontrolterminal.jpg' width="80%"> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/accesscontrolterminal.jpg'> | ||
@@ -827,3 +827,3 @@ | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/accesscontrol.png' width="80%"> | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/accesscontrol.png' > | ||
@@ -860,7 +860,17 @@ <br/> | ||
<br/> | ||
<br/> | ||
## Speaker node | ||
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/speaker.jpg' > | ||
This node connects to your Hikvision Speaker and broadcast a selected audio file, that must be already been uploaded to the speaker.<br/> | ||
Please see the help into the Node-Red help tab for further infos. | ||
![Logo](https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/madeinitaly.png) | ||
@@ -867,0 +877,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
5352
864
3409621
92