node-red-contrib-hik-media-buffer 1.2.0 → 1.2.2

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.
@@ -126,12 +126,13 @@ module.exports = function(RED) {
126
126
  if (nowTime - lastTriggerTime[channelID] < 5000) return;
127
127
  lastTriggerTime[channelID] = nowTime;
128
128
 
129
- node.status({fill:"yellow", shape:"dot", text:`Attesa (10s)...`});
130
- await new Promise(resolve => setTimeout(resolve, 13000));
131
-
132
129
  const nvrAuth = new AxiosDigestAuth({ username: node.user, password: node.pass });
133
130
  const referenceTime = new Date();
134
131
  const timestamp = Math.floor(referenceTime.getTime() / 1000);
132
+
133
+ node.status({fill:"yellow", shape:"dot", text:`Attesa (15s)...`});
134
+ await new Promise(resolve => setTimeout(resolve, 15000));
135
+
135
136
 
136
137
  const videoTrackID = (parseInt(channelID) * 100) + 1;
137
138
  const nomeCamera = await getCameraName(channelID);
@@ -211,7 +212,6 @@ module.exports = function(RED) {
211
212
  const endClip = pulisciDataHik(targetEvento.endTime);
212
213
 
213
214
  playbackURIGrezzo = `rtsp://${node.host}:${node.port}/Streaming/tracks/${videoTrackID}/?starttime=${startClip}&endtime=${endClip}`;
214
- node.warn(`[HIK SCORCIATOIA] URI Generato: ${playbackURIGrezzo}`);
215
215
  }
216
216
  }
217
217
 
@@ -224,9 +224,6 @@ module.exports = function(RED) {
224
224
  <playbackURI>${playbackURIXml}</playbackURI>
225
225
  </downloadRequest>`;
226
226
 
227
- node.warn(`[HIK DOWNLOAD] Invio Body XML (Stream Mode):\n${payloadDownload}`);
228
-
229
- // 🌟 CAMBIAMENTO CHIAVE: Chiediamo un 'stream' invece di 'arraybuffer'
230
227
  const resDownVideo = await nvrAuth.request({
231
228
  method: 'GET',
232
229
  url: `${node.protocol}://${node.host}:${node.port}/ISAPI/ContentMgmt/download`,
@@ -270,9 +267,6 @@ module.exports = function(RED) {
270
267
  fs.writeFileSync(rawPath, videoBuffer);
271
268
  }
272
269
 
273
- const stats = fs.statSync(rawPath);
274
- node.warn(`[HIK DOWNLOAD OK] File scaricato. Dimensione: ${(stats.size / 1024).toFixed(1)} KB`);
275
-
276
270
  await new Promise((resolve) => {
277
271
  exec(`ffmpeg -y -i "${rawPath}" -c copy -movflags +faststart "${fixedPath}"`, (err) => {
278
272
  if (!err && fs.existsSync(fixedPath)) {
package/hik-snapshot.js CHANGED
@@ -8,9 +8,8 @@ module.exports = function(RED) {
8
8
  RED.nodes.createNode(this, config);
9
9
  const node = this;
10
10
 
11
- // Recuperiamo il nome del nodo dalla configurazione (se vuoto usa l'host)
11
+ // Parametri di default salvati dalla configurazione grafica del nodo
12
12
  node.nodeName = config.name || `NVR_${config.host}`;
13
-
14
13
  node.protocol = config.protocol || "http";
15
14
  node.host = config.host;
16
15
  node.port = config.port || "80";
@@ -21,13 +20,25 @@ module.exports = function(RED) {
21
20
  const httpsAgent = new https.Agent({ rejectUnauthorized: false });
22
21
 
23
22
  node.on('input', async function(msg) {
24
- if (msg.payload !== true) return;
23
+ // 🌟 1. LOGICA DI ACCETTAZIONE FLESSIBILE
24
+ // Il nodo parte se il payload è 'true' OPPURE se stiamo passando una configurazione dinamica
25
+ if (msg.payload !== true && typeof msg.payload !== 'object') return;
25
26
 
26
27
  node.status({fill: "blue", shape: "dot", text: "Verifica canali..."});
27
28
 
29
+ // 🌟 2. VALUTAZIONE PARAMETRI DINAMICI VS PARAMETRI STATICI
30
+ // Se le proprietà sono presenti nel msg, usiamo quelle, altrimenti facciamo il fallback su quelle del nodo
31
+ const NVR_HOST = msg.nvr_host || node.host;
32
+ const NVR_PORT = msg.nvr_port || node.port;
33
+ const NVR_USER = msg.nvr_user || node.user;
34
+ const NVR_PASS = msg.nvr_pass || node.pass;
35
+ const NVR_NAME = msg.nvr_name || node.nodeName;
36
+ const MAX_CHANNELS = parseInt(msg.nvr_channels) || node.maxChannels;
37
+ const PROTOCOL = msg.nvr_protocol || node.protocol;
38
+
28
39
  const digest = new DigestAuthClass({
29
- username: node.user,
30
- password: node.pass
40
+ username: NVR_USER,
41
+ password: NVR_PASS
31
42
  });
32
43
 
33
44
  const data = new Date();
@@ -37,15 +48,16 @@ module.exports = function(RED) {
37
48
 
38
49
  let snapshotResults = [];
39
50
 
40
- for (let i = 1; i <= node.maxChannels; i++) {
51
+ // Il ciclo ora scala dinamicamente in base al numero di canali calcolato
52
+ for (let i = 1; i <= MAX_CHANNELS; i++) {
41
53
  const chanId = i + "01";
42
- const snapUrl = `${node.protocol}://${node.host}:${node.port}/ISAPI/Streaming/channels/${chanId}/picture`;
43
- const recordUrl = `${node.protocol}://${node.host}:${node.port}/ISAPI/ContentMgmt/record/tracks/${chanId}/dailyDistribution`;
54
+ const snapUrl = `${PROTOCOL}://${NVR_HOST}:${NVR_PORT}/ISAPI/Streaming/channels/${chanId}/picture`;
55
+ const recordUrl = `${PROTOCOL}://${NVR_HOST}:${NVR_PORT}/ISAPI/ContentMgmt/record/tracks/${chanId}/dailyDistribution`;
44
56
 
45
57
  const recordXml = `<?xml version="1.0" encoding="utf-8"?><trackDailyParam><year>${year}</year><monthOfYear>${month}</monthOfYear><dayOfMonth>${day}</dayOfMonth></trackDailyParam>`;
46
58
 
47
59
  let resCanale = {
48
- name: node.nodeName, // <--- INIEZIONE RIGIDA DEL NOME DEL CONDOMINIO
60
+ name: NVR_NAME, // Dinamico o statico a seconda della modalità
49
61
  channel: i,
50
62
  photo: null,
51
63
  snapOk: false,
@@ -58,7 +70,7 @@ module.exports = function(RED) {
58
70
  method: 'GET',
59
71
  url: snapUrl,
60
72
  responseType: 'arraybuffer',
61
- httpsAgent: node.protocol === 'https' ? httpsAgent : undefined,
73
+ httpsAgent: PROTOCOL === 'https' ? httpsAgent : undefined,
62
74
  timeout: 5000
63
75
  });
64
76
  resCanale.photo = responseSnap.data;
@@ -74,7 +86,7 @@ module.exports = function(RED) {
74
86
  url: recordUrl,
75
87
  data: recordXml,
76
88
  headers: { 'Content-Type': 'application/xml' },
77
- httpsAgent: node.protocol === 'https' ? httpsAgent : undefined,
89
+ httpsAgent: PROTOCOL === 'https' ? httpsAgent : undefined,
78
90
  timeout: 5000
79
91
  });
80
92
  const xmlOutput = responseRec.data.toString();
@@ -88,17 +100,18 @@ module.exports = function(RED) {
88
100
  await new Promise(resolve => setTimeout(resolve, 200));
89
101
  }
90
102
 
103
+ // Restituiamo i risultati sovrascrivendo il payload ma lasciando inalterato il resto del msg (es. msg.chatId)
91
104
  msg.payload = snapshotResults;
92
105
  node.send(msg);
93
106
 
94
- // Conteggi per lo stato del nodo
107
+ // Conteggi per lo stato visivo sul quadratino del nodo
95
108
  const snapCount = snapshotResults.filter(v => v.snapOk).length;
96
109
  const recCount = snapshotResults.filter(v => v.isRecording).length;
97
110
 
98
111
  node.status({
99
- fill: (snapCount === node.maxChannels && recCount === node.maxChannels) ? "green" : "yellow",
112
+ fill: (snapCount === MAX_CHANNELS && recCount === MAX_CHANNELS) ? "green" : "yellow",
100
113
  shape: "dot",
101
- text: `Snap: ${snapCount}/${node.maxChannels} | Rec: ${recCount}/${node.maxChannels}`
114
+ text: `Snap: ${snapCount}/${MAX_CHANNELS} | Rec: ${recCount}/${MAX_CHANNELS}`
102
115
  });
103
116
  });
104
117
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-contrib-hik-media-buffer",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "Ottiene buffer video e immagine da camere Hikvision via ISAPI",
5
5
  "keywords": [
6
6
  "node-red",