optimizations
optimizations

file:a/onvif/index.html (deleted)
<script type="text/x-red" data-template-name="ONVIF Snapshot">  
<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-url"><i class="fa fa-link"></i> IP Cam URL</label>  
<input type="text" id="node-input-url" placeholder="http://192.168.0.10:8080/onvif/device_service">  
</div>  
<div class="form-row">  
<label for="node-input-username"><i class="fa fa-user"></i> Username</label>  
<input type="text" id="node-input-username" placeholder="Username">  
</div>  
<div class="form-row">  
<label for="node-input-password"><i class="fa fa-key"></i> Password</label>  
<input type="text" id="node-input-password" placeholder="Password">  
</div>  
<div class="form-row">  
<label for="node-input-interval"><i class="fa fa-clock-o"></i> Interval (S)</label>  
<input type="text" id="node-input-interval" placeholder="Interval">  
</div>  
</script>  
 
<script type="text/x-red" data-help-name="ONVIF Snapshot">  
<p>Fetches a snapshot from an ip camera</p>  
</script>  
 
<script type="text/javascript">  
RED.nodes.registerType("ONVIF Snapshot", {  
category: "advanced-input",  
color: "#91d2f7",  
defaults: {  
name: {value: ""},  
url: {value: "", required: true},  
interval: {value: "60", required: true, validate: RED.validators.number()},  
username: {value: ""},  
password: {value: ""},  
active: {value: true}  
},  
inputs: 0,  
outputs: 1,  
icon: "onvif-snapshot.png",  
label: function() {  
return this.name || this.url || this.type;  
},  
labelStyle: function() {  
return this.name?"node_label_italic":"";  
},  
paletteLabel: "ONVIF Snapshot",  
align: "left",  
button: {  
toggle: "active",  
onclick: function() {  
var label = this.name || this.url || this.type;  
var node = this;  
$.ajax({  
url: "onvif-snapshot/"+this.id+"/"+(this.active?"enable":"disable"),  
type: "POST",  
success: function(resp, textStatus, xhr) {  
var historyEvent = {  
t:'edit',  
node:node,  
changes:{  
active: !node.active  
},  
dirty:node.dirty,  
changed:node.changed  
};  
node.changed = true;  
node.dirty = true;  
RED.nodes.dirty(true);  
RED.history.push(historyEvent);  
RED.view.redraw();  
if (xhr.status == 200) {  
RED.notify(label + " succesfully activated", "success");  
} else if (xhr.status == 201) {  
RED.notify(label + " succesfully deactivated", "success");  
}  
},  
error: function(jqXHR,textStatus,errorThrown) {  
if (jqXHR.status == 404) {  
RED.notify(label + " not deployed", "error");  
} else if (jqXHR.status == 0) {  
RED.notify(label + " no response", "error");  
} else {  
RED.notify(label + " unexpected error", "error");  
}  
}  
});  
}  
},  
oneditprepare: function() {  
},  
oneditsave: function() {  
}  
});  
</script>  
 
file:a/onvif/index.js (deleted)
module.exports = (RED) => {  
"use strict";  
let onvif = require("node-onvif");  
 
function fetchSnapshot(config) {  
RED.nodes.createNode(this, config);  
this.active = config.active;  
var node = this;  
 
if (!config.url) {  
node.warn("No URL is specified. Please specify in node configuration.");  
return;  
}  
 
config.interval = parseInt(config.interval);  
node.intervalId = null;  
let msg = {  
name: config.name,  
url: config.url,  
error: false  
};  
runInterval(msg, node, config);  
node.log("URL (" + config.interval + " seconds): " + config.url);  
 
node.on("close", () => {  
if (this.intervalId != null) {  
clearInterval(this.intervalId);  
}  
});  
}  
RED.nodes.registerType("ONVIF Snapshot", fetchSnapshot);  
 
RED.httpAdmin.post("/onvif-snapshot/:id/:state", RED.auth.needsPermission("onvif-snapshot.write"), (req,res) => {  
var node = RED.nodes.getNode(req.params.id);  
var state = req.params.state;  
if (node !== null && typeof node !== "undefined" ) {  
if (state === "enable") {  
node.active = true;  
res.sendStatus(200);  
} else if (state === "disable") {  
node.active = false;  
res.sendStatus(201);  
} else {  
res.sendStatus(404);  
}  
} else {  
res.sendStatus(404);  
}  
});  
 
function runInterval(msg, node, config) {  
if (node.intervalId != null) {  
clearInterval(node.intervalId);  
}  
if (node.active == false) return;  
 
let fetch = function() {  
let onvifInstance = new onvif.OnvifDevice({  
xaddr: config.url,  
user : config.username,  
pass : config.password  
});  
 
onvifInstance.init().then((info) => {  
node.log('Fetching snapshot from ' + config.url + '...');  
return onvifInstance.fetchSnapshot();  
}).then((res) => {  
let prefix = 'data:' + res.headers['content-type'] + ';base64,';  
let base64Image = Buffer.from(res.body, 'binary').toString('base64');  
msg.payload = prefix + base64Image;  
node.send(msg);  
}).catch((error) => {  
msg.payload = null;  
msg.error = error;  
node.send(msg);  
});  
}  
fetch();  
node.intervalId = setInterval(() => {  
fetch();  
}, config.interval * 1000);  
}  
}  
 
  <script type="text/x-red" data-template-name="ONVIF Snapshot">
  <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-url"><i class="fa fa-link"></i> IP Cam URL</label>
  <input type="text" id="node-input-url" placeholder="http://192.168.0.10:8080/onvif/device_service">
  </div>
  <div class="form-row">
  <label for="node-input-username"><i class="fa fa-user"></i> Username</label>
  <input type="text" id="node-input-username" placeholder="Username">
  </div>
  <div class="form-row">
  <label for="node-input-password"><i class="fa fa-key"></i> Password</label>
  <input type="text" id="node-input-password" placeholder="Password">
  </div>
  <div class="form-row">
  <label for="node-input-interval"><i class="fa fa-clock-o"></i> Interval (S)</label>
  <input type="text" id="node-input-interval" placeholder="Interval">
  </div>
  </script>
 
  <script type="text/x-red" data-help-name="ONVIF Snapshot">
  <p>Fetches a snapshot from an ip camera</p>
  </script>
 
  <script type="text/javascript">
  RED.nodes.registerType("ONVIF Snapshot", {
  category: "ONVIF",
  color: "#91d2f7",
  defaults: {
  name: {value: ""},
  url: {value: "", required: true},
  interval: {value: "60", required: true, validate: RED.validators.number()},
  username: {value: ""},
  password: {value: ""},
  active: {value: true}
  },
  inputs: 0,
  outputs: 1,
  icon: "onvif-snapshot.png",
  label: function() {
  return this.name || this.url || this.type;
  },
  labelStyle: function() {
  return this.name?"node_label_italic":"";
  },
  paletteLabel: "Snapshot",
  align: "left",
  button: {
  toggle: "active",
  onclick: function() {
  var label = this.name || this.url || this.type;
  var node = this;
  $.ajax({
  url: "onvif-snapshot/"+this.id+"/"+(this.active?"enable":"disable"),
  type: "POST",
  success: function(resp, textStatus, xhr) {
  var historyEvent = {
  t:'edit',
  node:node,
  changes:{
  active: !node.active
  },
  dirty:node.dirty,
  changed:node.changed
  };
  node.changed = true;
  node.dirty = true;
  RED.nodes.dirty(true);
  RED.history.push(historyEvent);
  RED.view.redraw();
  if (xhr.status == 200) {
  RED.notify(label + " succesfully activated", "success");
  } else if (xhr.status == 201) {
  RED.notify(label + " succesfully deactivated", "success");
  }
  },
  error: function(jqXHR,textStatus,errorThrown) {
  if (jqXHR.status == 404) {
  RED.notify(label + " not deployed", "error");
  } else if (jqXHR.status == 0) {
  RED.notify(label + " no response", "error");
  } else {
  RED.notify(label + " unexpected error", "error");
  }
  }
  });
  }
  },
  oneditprepare: function() {
  },
  oneditsave: function() {
  }
  });
  </script>
 
file:b/onvif/snapshot.js (new)
  module.exports = (RED) => {
  "use strict";
  let onvif = require("node-onvif");
 
  function snapshot(config) {
  RED.nodes.createNode(this, config);
  this.active = config.active;
  var node = this;
 
  if (!config.url) {
  node.warn("No URL is specified. Please specify in node configuration.");
  return;
  }
  if (node.active == false) return;
 
  config.interval = parseInt(config.interval);
  node.intervalId = null;
 
  runInterval(node, config);
 
  node.on("close", () => {
  if (this.intervalId != null) {
  clearInterval(this.intervalId);
  }
  });
  }
  RED.nodes.registerType("ONVIF Snapshot", snapshot);
 
  RED.httpAdmin.post("/onvif-snapshot/:id/:state", RED.auth.needsPermission("onvif-snapshot.write"), (req, res) => {
  var node = RED.nodes.getNode(req.params.id);
  var state = req.params.state;
  if (node !== null && typeof node !== "undefined" ) {
  if (state === "enable") {
  node.active = true;
  res.sendStatus(200);
  } else if (state === "disable") {
  node.active = false;
  res.sendStatus(201);
  } else {
  res.sendStatus(404);
  }
  } else {
  res.sendStatus(404);
  }
  });
 
  function runInterval(node, config) {
  if (node.intervalId != null) {
  clearInterval(node.intervalId);
  }
  node.log("URL (" + config.interval + " seconds): " + config.url);
 
  let msg = {
  name: config.name,
  url: config.url,
  error: false
  };
 
  let fetch = function() {
  let onvifInstance = new onvif.OnvifDevice({
  xaddr: config.url,
  user : config.username,
  pass : config.password
  });
 
  onvifInstance.init().then((info) => {
  node.log('Fetching snapshot from ' + config.url);
  return onvifInstance.fetchSnapshot();
  }).then((res) => {
  let prefix = 'data:' + res.headers['content-type'] + ';base64,';
  let base64Image = Buffer.from(res.body, 'binary').toString('base64');
  msg.payload = prefix + base64Image;
  msg.binaryImage = res.body;
  node.send(msg);
  }).catch((error) => {
  msg.payload = null;
  msg.error = error;
  node.send(msg);
  });
  }
  fetch();
  node.intervalId = setInterval(() => {
  fetch();
  }, config.interval * 1000);
  }
  }
 
{ {
"name": "node-red-contrib-onvif", "name": "node-red-contrib-onvif",
"version": "0.0.1", "version": "0.0.1",
"description": "A Node-RED node that interacts with ip cameras using the ONVIF protocol", "description": "A Node-RED node that interacts with ip cameras using the ONVIF protocol",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/razvanstanga/node-red-contrib-onvif.git" "url": "https://github.com/razvanstanga/node-red-contrib-onvif.git"
}, },
"dependencies": { "dependencies": {
"node-onvif": "^0.1.7" "node-onvif": "^0.1.7"
}, },
"inputs": 0, "inputs": 0,
"keywords": [ "keywords": [
"node-red", "node-red",
"node-red-contrib", "node-red-contrib",
"onvif", "onvif",
"ipcam" "ipcam"
], ],
"node-red": { "node-red": {
"nodes": { "nodes": {
"ONVIF Snapshot": "onvif/index.js" "ONVIF Snapshot": "onvif/snapshot.js"
} }
}, },
"author": { "author": {
"name": "Razvan Stanga" "name": "Razvan Stanga"
}, },
"license": "Apache", "license": "Apache",
"bugs": { "bugs": {
"url": "https://github.com/razvanstanga/node-red-contrib-onvif/issues" "url": "https://github.com/razvanstanga/node-red-contrib-onvif/issues"
}, },
"homepage": "https://github.com/razvanstanga/node-red-contrib-onvif" "homepage": "https://github.com/razvanstanga/node-red-contrib-onvif"
} }
   
comments