node-red-contrib-hik-media-buffer 1.1.46 → 1.1.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/hik-media-buffer.js +27 -18
- package/package.json +1 -1
package/hik-media-buffer.js
CHANGED
|
@@ -22,9 +22,7 @@ module.exports = function(RED) {
|
|
|
22
22
|
let isClosing = false;
|
|
23
23
|
let lastTriggerTime = {};
|
|
24
24
|
let nvrOnline = true;
|
|
25
|
-
|
|
26
25
|
let statoCanale = {};
|
|
27
|
-
let ultimoAllarmeTempo = {};
|
|
28
26
|
|
|
29
27
|
const httpsAgent = new https.Agent({ rejectUnauthorized: false });
|
|
30
28
|
|
|
@@ -80,7 +78,7 @@ module.exports = function(RED) {
|
|
|
80
78
|
while ((matchBlocco = bloccoRegex.exec(xmlData)) !== null) {
|
|
81
79
|
const bloccoContenuto = matchBlocco[1];
|
|
82
80
|
|
|
83
|
-
const idMatch =
|
|
81
|
+
const idMatch = bloccoContenited.match(/<id>(\d+)<\/id>/i);
|
|
84
82
|
const statusMatch = bloccoContenuto.match(/<status>([^<]+)</i);
|
|
85
83
|
|
|
86
84
|
if (idMatch && statusMatch) {
|
|
@@ -120,20 +118,21 @@ module.exports = function(RED) {
|
|
|
120
118
|
|
|
121
119
|
const heartbeatInterval = setInterval(checkCameras, 30000);
|
|
122
120
|
|
|
123
|
-
// --- DOWNLOAD MULTIMEDIALE
|
|
121
|
+
// --- DOWNLOAD MULTIMEDIALE BASATO SULL'ISPEZIONA REALE DELL'NVR ---
|
|
124
122
|
async function downloadMedia(evento, channelID) {
|
|
125
123
|
const nowTime = Date.now();
|
|
126
124
|
if (!lastTriggerTime[channelID]) lastTriggerTime[channelID] = 0;
|
|
127
125
|
if (nowTime - lastTriggerTime[channelID] < 5000) return;
|
|
128
126
|
lastTriggerTime[channelID] = nowTime;
|
|
129
127
|
|
|
130
|
-
// ISTANZIAMO camAuth SULL'NVR: Risolve il problema delle credenziali vuote nel vecchio blocco
|
|
131
128
|
const camAuth = new AxiosDigestAuth({ username: node.user, password: node.pass });
|
|
132
129
|
|
|
133
130
|
const referenceTime = new Date();
|
|
134
131
|
const timestamp = Math.floor(referenceTime.getTime() / 1000);
|
|
135
|
-
|
|
136
|
-
|
|
132
|
+
|
|
133
|
+
// Finestra temporale basata sulle date ISO
|
|
134
|
+
const startTime = toHikDate(new Date(referenceTime.getTime() - (20 * 1000)));
|
|
135
|
+
const endTime = toHikDate(new Date(referenceTime.getTime() + (20 * 1000)));
|
|
137
136
|
|
|
138
137
|
node.status({fill:"yellow", shape:"dot", text:`Download Cam ${channelID}...`});
|
|
139
138
|
const nomeCamera = await getCameraName(channelID);
|
|
@@ -141,12 +140,21 @@ module.exports = function(RED) {
|
|
|
141
140
|
await new Promise(resolve => setTimeout(resolve, 6000));
|
|
142
141
|
const baseUrl = `${node.protocol}://${node.host}:${node.port}/ISAPI/ContentMgmt`;
|
|
143
142
|
|
|
143
|
+
// Ricostruiamo l'evento con il case-sensitive corretto per l'NVR (FieldDetection / LineDetection)
|
|
144
|
+
let eventoNVR = "FieldDetection";
|
|
145
|
+
for (let e of EventList) {
|
|
146
|
+
if (evento.toLowerCase() === e.toLowerCase()) {
|
|
147
|
+
eventoNVR = e;
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
144
152
|
let output = {
|
|
145
153
|
tipo_messaggio: "evento",
|
|
146
154
|
nome_cliente: node.name,
|
|
147
155
|
nome_telecamera: nomeCamera,
|
|
148
156
|
ip_telecamera: node.host,
|
|
149
|
-
tipo_evento:
|
|
157
|
+
tipo_evento: eventoNVR,
|
|
150
158
|
timestamp_epoch: timestamp,
|
|
151
159
|
stato_telecamera: "ONLINE",
|
|
152
160
|
channel: channelID.toString(),
|
|
@@ -155,16 +163,19 @@ module.exports = function(RED) {
|
|
|
155
163
|
};
|
|
156
164
|
|
|
157
165
|
const parsedChannel = parseInt(channelID, 10);
|
|
158
|
-
const trackVideo = (parsedChannel * 100) + 1; //
|
|
159
|
-
const trackFoto = (parsedChannel * 100) + 3; //
|
|
166
|
+
const trackVideo = (parsedChannel * 100) + 1; // Canale 2 -> 201
|
|
167
|
+
const trackFoto = (parsedChannel * 100) + 3; // Canale 2 -> 203
|
|
160
168
|
|
|
161
|
-
const tracks = [
|
|
169
|
+
const tracks = [
|
|
170
|
+
{ id: trackVideo.toString(), isFoto: false },
|
|
171
|
+
{ id: trackFoto.toString(), isFoto: true }
|
|
172
|
+
];
|
|
162
173
|
let fileDaCancellare = [];
|
|
163
174
|
|
|
164
175
|
try {
|
|
165
176
|
for (let t of tracks) {
|
|
166
|
-
//
|
|
167
|
-
const searchXml = `<?xml version="1.0" encoding="utf-8"?><CMSearchDescription><searchID>LAST_EVENT</searchID><trackIDList><trackID>${t.id}</trackID></trackIDList><timeSpanList><timeSpan><startTime>${startTime}</startTime><endTime>${endTime}</endTime></timeSpan></timeSpanList><maxResults>
|
|
177
|
+
// COPIATO DALL'ISPEZIONA: Inserito <contentTypeList> e corretto metadataDescriptor proprietario hikvision
|
|
178
|
+
const searchXml = `<?xml version="1.0" encoding="utf-8"?><CMSearchDescription><searchID>LAST_EVENT</searchID><trackIDList><trackID>${t.id}</trackID></trackIDList><timeSpanList><timeSpan><startTime>${startTime}</startTime><endTime>${endTime}</endTime></timeSpan></timeSpanList><contentTypeList><contentType>metadata</contentType></contentTypeList><maxResults>30</maxResults><metadataList><metadataDescriptor>recordType.meta.hikvision.com/${eventoNVR}</metadataDescriptor></metadataList></CMSearchDescription>`;
|
|
168
179
|
|
|
169
180
|
const resSearch = await camAuth.request({
|
|
170
181
|
method: 'POST', url: `${baseUrl}/search`, data: searchXml, headers: { "Content-Type": "application/xml" }
|
|
@@ -183,8 +194,8 @@ module.exports = function(RED) {
|
|
|
183
194
|
});
|
|
184
195
|
|
|
185
196
|
let buffer = Buffer.from(resDown.data);
|
|
186
|
-
if (t.
|
|
187
|
-
// SALVA FOTO IN LOCALE
|
|
197
|
+
if (t.isFoto) {
|
|
198
|
+
// SALVA FOTO TERMICA NATIVA IN LOCALE
|
|
188
199
|
const fullImgPath = path.join(baseStorage, `img_${timestamp}.jpg`);
|
|
189
200
|
fs.writeFileSync(fullImgPath, buffer);
|
|
190
201
|
output.foto_base64 = fs.readFileSync(fullImgPath, { encoding: 'base64' });
|
|
@@ -245,9 +256,7 @@ module.exports = function(RED) {
|
|
|
245
256
|
if (chMatch) {
|
|
246
257
|
let ev = "Unknown";
|
|
247
258
|
for (let e of EventList) { if (data.includes(e.toLowerCase())) { ev = e; break; } }
|
|
248
|
-
|
|
249
|
-
if (ev === "Unknown") return; // Ignora heartbeat o altri eventi non mappati
|
|
250
|
-
|
|
259
|
+
if (ev === "Unknown") return;
|
|
251
260
|
downloadMedia(ev, chMatch[1]);
|
|
252
261
|
}
|
|
253
262
|
}
|