summaryrefslogtreecommitdiffstats
path: root/node.d
diff options
context:
space:
mode:
Diffstat (limited to 'node.d')
-rw-r--r--node.d/Makefile.am17
-rw-r--r--node.d/Makefile.in67
-rw-r--r--node.d/README.md55
-rw-r--r--node.d/fronius.node.js311
-rw-r--r--node.d/node_modules/asn1-ber.js6
-rw-r--r--node.d/node_modules/asn1.js20
-rw-r--r--node.d/node_modules/ber/errors.js13
-rw-r--r--node.d/node_modules/ber/index.js27
-rw-r--r--node.d/node_modules/ber/reader.js261
-rw-r--r--node.d/node_modules/ber/types.js36
-rw-r--r--node.d/node_modules/ber/writer.js316
-rw-r--r--node.d/node_modules/lib/ber/errors.js9
-rw-r--r--node.d/node_modules/lib/ber/index.js17
-rw-r--r--node.d/node_modules/lib/ber/reader.js269
-rw-r--r--node.d/node_modules/lib/ber/types.js34
-rw-r--r--node.d/node_modules/lib/ber/writer.js317
-rw-r--r--node.d/node_modules/net-snmp.js2
-rw-r--r--node.d/node_modules/netdata.js8
-rw-r--r--node.d/snmp.node.js37
-rw-r--r--node.d/stiebeleltron.node.js196
20 files changed, 1171 insertions, 847 deletions
diff --git a/node.d/Makefile.am b/node.d/Makefile.am
index 28008aeb7..7f67faa6a 100644
--- a/node.d/Makefile.am
+++ b/node.d/Makefile.am
@@ -6,6 +6,7 @@ dist_node_DATA = \
fronius.node.js \
sma_webbox.node.js \
snmp.node.js \
+ stiebeleltron.node.js \
$(NULL)
nodemodulesdir=$(nodedir)/node_modules
@@ -14,14 +15,14 @@ dist_nodemodules_DATA = \
node_modules/extend.js \
node_modules/pixl-xml.js \
node_modules/net-snmp.js \
- node_modules/asn1.js \
+ node_modules/asn1-ber.js \
$(NULL)
-nodemodulesberdir=$(nodedir)/node_modules/ber
-dist_nodemodulesber_DATA = \
- node_modules/ber/index.js \
- node_modules/ber/errors.js \
- node_modules/ber/reader.js \
- node_modules/ber/types.js \
- node_modules/ber/writer.js \
+nodemoduleslibberdir=$(nodedir)/node_modules/lib/ber
+dist_nodemoduleslibber_DATA = \
+ node_modules/lib/ber/index.js \
+ node_modules/lib/ber/errors.js \
+ node_modules/lib/ber/reader.js \
+ node_modules/lib/ber/types.js \
+ node_modules/lib/ber/writer.js \
$(NULL)
diff --git a/node.d/Makefile.in b/node.d/Makefile.in
index 35024cb12..dd572ee8b 100644
--- a/node.d/Makefile.in
+++ b/node.d/Makefile.in
@@ -81,7 +81,7 @@ host_triplet = @host@
subdir = node.d
DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
$(dist_node_DATA) $(dist_nodemodules_DATA) \
- $(dist_nodemodulesber_DATA)
+ $(dist_nodemoduleslibber_DATA)
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_c___atomic.m4 \
$(top_srcdir)/m4/ax_c__generic.m4 $(top_srcdir)/m4/ax_c_lto.m4 \
@@ -144,9 +144,9 @@ am__uninstall_files_from_dir = { \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
am__installdirs = "$(DESTDIR)$(nodedir)" "$(DESTDIR)$(nodemodulesdir)" \
- "$(DESTDIR)$(nodemodulesberdir)"
+ "$(DESTDIR)$(nodemoduleslibberdir)"
DATA = $(dist_node_DATA) $(dist_nodemodules_DATA) \
- $(dist_nodemodulesber_DATA)
+ $(dist_nodemoduleslibber_DATA)
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
@@ -300,6 +300,7 @@ dist_node_DATA = \
fronius.node.js \
sma_webbox.node.js \
snmp.node.js \
+ stiebeleltron.node.js \
$(NULL)
nodemodulesdir = $(nodedir)/node_modules
@@ -308,16 +309,16 @@ dist_nodemodules_DATA = \
node_modules/extend.js \
node_modules/pixl-xml.js \
node_modules/net-snmp.js \
- node_modules/asn1.js \
+ node_modules/asn1-ber.js \
$(NULL)
-nodemodulesberdir = $(nodedir)/node_modules/ber
-dist_nodemodulesber_DATA = \
- node_modules/ber/index.js \
- node_modules/ber/errors.js \
- node_modules/ber/reader.js \
- node_modules/ber/types.js \
- node_modules/ber/writer.js \
+nodemoduleslibberdir = $(nodedir)/node_modules/lib/ber
+dist_nodemoduleslibber_DATA = \
+ node_modules/lib/ber/index.js \
+ node_modules/lib/ber/errors.js \
+ node_modules/lib/ber/reader.js \
+ node_modules/lib/ber/types.js \
+ node_modules/lib/ber/writer.js \
$(NULL)
all: all-am
@@ -395,27 +396,27 @@ uninstall-dist_nodemodulesDATA:
@list='$(dist_nodemodules_DATA)'; test -n "$(nodemodulesdir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
dir='$(DESTDIR)$(nodemodulesdir)'; $(am__uninstall_files_from_dir)
-install-dist_nodemodulesberDATA: $(dist_nodemodulesber_DATA)
+install-dist_nodemoduleslibberDATA: $(dist_nodemoduleslibber_DATA)
@$(NORMAL_INSTALL)
- @list='$(dist_nodemodulesber_DATA)'; test -n "$(nodemodulesberdir)" || list=; \
+ @list='$(dist_nodemoduleslibber_DATA)'; test -n "$(nodemoduleslibberdir)" || list=; \
if test -n "$$list"; then \
- echo " $(MKDIR_P) '$(DESTDIR)$(nodemodulesberdir)'"; \
- $(MKDIR_P) "$(DESTDIR)$(nodemodulesberdir)" || exit 1; \
+ echo " $(MKDIR_P) '$(DESTDIR)$(nodemoduleslibberdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(nodemoduleslibberdir)" || exit 1; \
fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
done | $(am__base_list) | \
while read files; do \
- echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(nodemodulesberdir)'"; \
- $(INSTALL_DATA) $$files "$(DESTDIR)$(nodemodulesberdir)" || exit $$?; \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(nodemoduleslibberdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(nodemoduleslibberdir)" || exit $$?; \
done
-uninstall-dist_nodemodulesberDATA:
+uninstall-dist_nodemoduleslibberDATA:
@$(NORMAL_UNINSTALL)
- @list='$(dist_nodemodulesber_DATA)'; test -n "$(nodemodulesberdir)" || list=; \
+ @list='$(dist_nodemoduleslibber_DATA)'; test -n "$(nodemoduleslibberdir)" || list=; \
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
- dir='$(DESTDIR)$(nodemodulesberdir)'; $(am__uninstall_files_from_dir)
+ dir='$(DESTDIR)$(nodemoduleslibberdir)'; $(am__uninstall_files_from_dir)
tags TAGS:
ctags CTAGS:
@@ -457,7 +458,7 @@ check-am: all-am
check: check-am
all-am: Makefile $(DATA)
installdirs:
- for dir in "$(DESTDIR)$(nodedir)" "$(DESTDIR)$(nodemodulesdir)" "$(DESTDIR)$(nodemodulesberdir)"; do \
+ for dir in "$(DESTDIR)$(nodedir)" "$(DESTDIR)$(nodemodulesdir)" "$(DESTDIR)$(nodemoduleslibberdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
@@ -512,7 +513,7 @@ info: info-am
info-am:
install-data-am: install-dist_nodeDATA install-dist_nodemodulesDATA \
- install-dist_nodemodulesberDATA
+ install-dist_nodemoduleslibberDATA
install-dvi: install-dvi-am
@@ -557,7 +558,7 @@ ps: ps-am
ps-am:
uninstall-am: uninstall-dist_nodeDATA uninstall-dist_nodemodulesDATA \
- uninstall-dist_nodemodulesberDATA
+ uninstall-dist_nodemoduleslibberDATA
.MAKE: install-am install-strip
@@ -565,16 +566,16 @@ uninstall-am: uninstall-dist_nodeDATA uninstall-dist_nodemodulesDATA \
ctags-am distclean distclean-generic distdir dvi dvi-am html \
html-am info info-am install install-am install-data \
install-data-am install-dist_nodeDATA \
- install-dist_nodemodulesDATA install-dist_nodemodulesberDATA \
- install-dvi install-dvi-am install-exec install-exec-am \
- install-html install-html-am install-info install-info-am \
- install-man install-pdf install-pdf-am install-ps \
- install-ps-am install-strip installcheck installcheck-am \
- installdirs maintainer-clean maintainer-clean-generic \
- mostlyclean mostlyclean-generic pdf pdf-am ps ps-am tags-am \
- uninstall uninstall-am uninstall-dist_nodeDATA \
- uninstall-dist_nodemodulesDATA \
- uninstall-dist_nodemodulesberDATA
+ install-dist_nodemodulesDATA \
+ install-dist_nodemoduleslibberDATA install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
+ pdf-am ps ps-am tags-am uninstall uninstall-am \
+ uninstall-dist_nodeDATA uninstall-dist_nodemodulesDATA \
+ uninstall-dist_nodemoduleslibberDATA
# Tell versions [3.59,3.63) of GNU make to not export all variables.
diff --git a/node.d/README.md b/node.d/README.md
index 3c2977905..6818d34de 100644
--- a/node.d/README.md
+++ b/node.d/README.md
@@ -61,3 +61,58 @@ Sample:
If no configuration is given, the module will be disabled. Each `update_every` is optional, the default is `5`.
---
+
+# stiebel eltron
+
+This module collects metrics from the configured heat pump and hot water installation from Stiebel Eltron ISG web.
+See `netdata/conf.d/node.d/stiebeleltron.conf.md` for more details.
+
+**Requirements**
+ * Configuration file `stiebeleltron.conf` in the node.d netdata config dir (default: `/etc/netdata/node.d/stiebeleltron.conf`)
+ * Stiebel Eltron ISG web with network access (http), without password login
+
+The charts are configurable, however, the provided default configuration collects the following:
+
+1. **General**
+ * Outside temperature in C
+ * Condenser temperature in C
+ * Heating circuit pressure in bar
+ * Flow rate in l/min
+ * Output of water and heat pumps in %
+
+2. **Heating**
+ * Heat circuit 1 temperature in C (set/actual)
+ * Heat circuit 2 temperature in C (set/actual)
+ * Flow temperature in C (set/actual)
+ * Buffer temperature in C (set/actual)
+ * Pre-flow temperature in C
+
+3. **Hot Water**
+ * Hot water temperature in C (set/actual)
+
+4. **Room Temperature**
+ * Heat circuit 1 room temperature in C (set/actual)
+ * Heat circuit 2 room temperature in C (set/actual)
+
+5. **Eletric Reheating**
+ * Dual Mode Reheating temperature in C (hot water/heating)
+
+6. **Process Data**
+ * Remaining compressor rest time in s
+
+7. **Runtime**
+ * Compressor runtime hours (hot water/heating)
+ * Reheating runtime hours (reheating 1/reheating 2)
+
+8. **Energy**
+ * Compressor today in kWh (hot water/heating)
+ * Compressor Total in kWh (hot water/heating)
+
+
+### configuration
+
+The default configuration is provided in [netdata/conf.d/node.d/stiebeleltron.conf.md](https://github.com/firehol/netdata/blob/master/conf.d/node.d/stiebeleltron.conf.md). Just change the `update_every` (if necessary) and hostnames. **You may have to adapt the configuration to suit your needs and setup** (which might be different).
+
+If no configuration is given, the module will be disabled. Each `update_every` is optional, the default is `10`.
+
+---
diff --git a/node.d/fronius.node.js b/node.d/fronius.node.js
index f771f6c3d..7aa2c13b7 100644
--- a/node.d/fronius.node.js
+++ b/node.d/fronius.node.js
@@ -1,15 +1,15 @@
-'use strict';
+"use strict";
// This program will connect to one or more Fronius Symo Inverters.
// to get the Solar Power Generated (current, today).
// example configuration in netdata/conf.d/node.d/fronius.conf.md
-var url = require('url');
-var http = require('http');
-var netdata = require('netdata');
+var url = require("url");
+var http = require("http");
+var netdata = require("netdata");
-netdata.debug('loaded ' + __filename + ' plugin');
+netdata.debug("loaded " + __filename + " plugin");
var fronius = {
name: "Fronius",
@@ -39,24 +39,25 @@ var fronius = {
},
// Gets the site power chart. Will be created if not existing.
- getSitePowerChart: function (service, id) {
+ getSitePowerChart: function (service, suffix) {
+ var id = this.getChartId(service, suffix);
var chart = fronius.charts[id];
if (fronius.isDefined(chart)) return chart;
var dim = {};
- dim[fronius.powerGridId] = this.createBasicDimension(fronius.powerGridId, "Grid", 1);
- dim[fronius.powerPvId] = this.createBasicDimension(fronius.powerPvId, "Photovoltaics", 1);
- dim[fronius.powerAccuId] = this.createBasicDimension(fronius.powerAccuId, "Accumulator", 1);
+ dim[fronius.powerGridId] = this.createBasicDimension(fronius.powerGridId, "grid", 1);
+ dim[fronius.powerPvId] = this.createBasicDimension(fronius.powerPvId, "photovoltaics", 1);
+ dim[fronius.powerAccuId] = this.createBasicDimension(fronius.powerAccuId, "accumulator", 1);
chart = {
id: id, // the unique id of the chart
- name: '', // the unique name of the chart
- title: service.name + ' Current Site Power', // the title of the chart
- units: 'W', // the units of the chart dimensions
- family: 'power', // the family of the chart
- context: 'fronius.power', // the context of the chart
+ name: "", // the unique name of the chart
+ title: service.name + " Current Site Power", // the title of the chart
+ units: "W", // the units of the chart dimensions
+ family: "power", // the family of the chart
+ context: "fronius.power", // the context of the chart
type: netdata.chartTypes.area, // the type of the chart
- priority: fronius.base_priority + 1, // the priority relative to others in the same family
+ priority: fronius.base_priority + 1, // the priority relative to others in the same family
update_every: service.update_every, // the expected update frequency of the chart
dimensions: dim
};
@@ -67,19 +68,20 @@ var fronius = {
},
// Gets the site consumption chart. Will be created if not existing.
- getSiteConsumptionChart: function (service, id) {
+ getSiteConsumptionChart: function (service, suffix) {
+ var id = this.getChartId(service, suffix);
var chart = fronius.charts[id];
if (fronius.isDefined(chart)) return chart;
var dim = {};
- dim[fronius.consumptionLoadId] = this.createBasicDimension(fronius.consumptionLoadId, "Load", 1);
+ dim[fronius.consumptionLoadId] = this.createBasicDimension(fronius.consumptionLoadId, "load", 1);
chart = {
id: id, // the unique id of the chart
- name: '', // the unique name of the chart
- title: service.name + ' Current Load', // the title of the chart
- units: 'W', // the units of the chart dimensions
- family: 'consumption', // the family of the chart
- context: 'fronius.consumption', // the context of the chart
+ name: "", // the unique name of the chart
+ title: service.name + " Current Load", // the title of the chart
+ units: "W", // the units of the chart dimensions
+ family: "consumption", // the family of the chart
+ context: "fronius.consumption", // the context of the chart
type: netdata.chartTypes.area, // the type of the chart
priority: fronius.base_priority + 2, // the priority relative to others in the same family
update_every: service.update_every, // the expected update frequency of the chart
@@ -92,20 +94,21 @@ var fronius = {
},
// Gets the site consumption chart. Will be created if not existing.
- getSiteAutonomyChart: function (service, id) {
+ getSiteAutonomyChart: function (service, suffix) {
+ var id = this.getChartId(service, suffix);
var chart = fronius.charts[id];
if (fronius.isDefined(chart)) return chart;
var dim = {};
- dim[fronius.autonomyId] = this.createBasicDimension(fronius.autonomyId, "Autonomy", 1);
- dim[fronius.consumptionSelfId] = this.createBasicDimension(fronius.consumptionSelfId, "Self Consumption", 1);
+ dim[fronius.autonomyId] = this.createBasicDimension(fronius.autonomyId, "autonomy", 1);
+ dim[fronius.consumptionSelfId] = this.createBasicDimension(fronius.consumptionSelfId, "self_consumption", 1);
chart = {
id: id, // the unique id of the chart
- name: '', // the unique name of the chart
- title: service.name + ' Current Autonomy', // the title of the chart
- units: '%', // the units of the chart dimensions
- family: 'autonomy', // the family of the chart
- context: 'fronius.autonomy', // the context of the chart
+ name: "", // the unique name of the chart
+ title: service.name + " Current Autonomy", // the title of the chart
+ units: "%", // the units of the chart dimensions
+ family: "autonomy", // the family of the chart
+ context: "fronius.autonomy", // the context of the chart
type: netdata.chartTypes.area, // the type of the chart
priority: fronius.base_priority + 3, // the priority relative to others in the same family
update_every: service.update_every, // the expected update frequency of the chart
@@ -118,21 +121,22 @@ var fronius = {
},
// Gets the site energy chart for today. Will be created if not existing.
- getSiteEnergyTodayChart: function (service, chartId) {
+ getSiteEnergyTodayChart: function (service, suffix) {
+ var chartId = this.getChartId(service, suffix);
var chart = fronius.charts[chartId];
if (fronius.isDefined(chart)) return chart;
var dim = {};
- dim[fronius.energyTodayId] = this.createBasicDimension(fronius.energyTodayId, "Today", 1000);
+ dim[fronius.energyTodayId] = this.createBasicDimension(fronius.energyTodayId, "today", 1000);
chart = {
id: chartId, // the unique id of the chart
- name: '', // the unique name of the chart
- title: service.name + ' Energy production for today', // the title of the chart
- units: 'kWh', // the units of the chart dimensions
- family: 'energy', // the family of the chart
- context: 'fronius.energy.today', // the context of the chart
- type: netdata.chartTypes.area, // the type of the chart
- priority: fronius.base_priority + 4, // the priority relative to others in the same family
- update_every: service.update_every, // the expected update frequency of the chart
+ name: "", // the unique name of the chart
+ title: service.name + " Energy production for today",// the title of the chart
+ units: "kWh", // the units of the chart dimensions
+ family: "energy", // the family of the chart
+ context: "fronius.energy.today", // the context of the chart
+ type: netdata.chartTypes.area, // the type of the chart
+ priority: fronius.base_priority + 4, // the priority relative to others in the same family
+ update_every: service.update_every, // the expected update frequency of the chart
dimensions: dim
};
chart = service.chart(chartId, chart);
@@ -142,21 +146,22 @@ var fronius = {
},
// Gets the site energy chart for today. Will be created if not existing.
- getSiteEnergyYearChart: function (service, chartId) {
+ getSiteEnergyYearChart: function (service, suffix) {
+ var chartId = this.getChartId(service, suffix);
var chart = fronius.charts[chartId];
if (fronius.isDefined(chart)) return chart;
var dim = {};
- dim[fronius.energyYearId] = this.createBasicDimension(fronius.energyYearId, "Year", 1000);
+ dim[fronius.energyYearId] = this.createBasicDimension(fronius.energyYearId, "year", 1000);
chart = {
- id: chartId, // the unique id of the chart
- name: '', // the unique name of the chart
- title: service.name + ' Energy production for this year', // the title of the chart
- units: 'kWh', // the units of the chart dimensions
- family: 'energy', // the family of the chart
- context: 'fronius.energy.year', // the context of the chart
- type: netdata.chartTypes.area, // the type of the chart
- priority: fronius.base_priority + 5, // the priority relative to others in the same family
- update_every: service.update_every, // the expected update frequency of the chart
+ id: chartId, // the unique id of the chart
+ name: "", // the unique name of the chart
+ title: service.name + " Energy production for this year",// the title of the chart
+ units: "kWh", // the units of the chart dimensions
+ family: "energy", // the family of the chart
+ context: "fronius.energy.year", // the context of the chart
+ type: netdata.chartTypes.area, // the type of the chart
+ priority: fronius.base_priority + 5, // the priority relative to others in the same family
+ update_every: service.update_every, // the expected update frequency of the chart
dimensions: dim
};
chart = service.chart(chartId, chart);
@@ -167,35 +172,30 @@ var fronius = {
// Gets the inverter power chart. Will be created if not existing.
// Needs the array of inverters in order to create a chart with all inverters as dimensions
- getInverterPowerChart: function (service, chartId, inverters) {
-
+ getInverterPowerChart: function (service, suffix, inverters) {
+ var chartId = this.getChartId(service, suffix);
var chart = fronius.charts[chartId];
if (fronius.isDefined(chart)) return chart;
var dim = {};
-
- var inverterCount = Object.keys(inverters).length;
- var inverter = inverters[inverterCount.toString()];
- var i = 1;
- for (i; i <= inverterCount; i++) {
- if (fronius.isUndefined(inverter)) {
- netdata.error("Expected an Inverter with a numerical name! " +
- "Have a look at your JSON output to verify.");
- continue;
+ for (var key in inverters) {
+ if (inverters.hasOwnProperty(key)) {
+ var name = key;
+ if (!isNaN(key)) name = "inverter_" + key;
+ dim[key] = this.createBasicDimension("inverter_" + key, name, 1);
}
- dim[i.toString()] = this.createBasicDimension("inverter_" + i, "Inverter " + i, 1);
}
chart = {
- id: chartId, // the unique id of the chart
- name: '', // the unique name of the chart
- title: service.name + ' Current Inverter Output', // the title of the chart
- units: 'W', // the units of the chart dimensions
- family: 'inverters', // the family of the chart
- context: 'fronius.inverter.output', // the context of the chart
- type: netdata.chartTypes.stacked, // the type of the chart
+ id: chartId, // the unique id of the chart
+ name: "", // the unique name of the chart
+ title: service.name + " Current Inverter Output",// the title of the chart
+ units: "W", // the units of the chart dimensions
+ family: "inverters", // the family of the chart
+ context: "fronius.inverter.output", // the context of the chart
+ type: netdata.chartTypes.stacked, // the type of the chart
priority: fronius.base_priority + 6, // the priority relative to others in the same family
- update_every: service.update_every, // the expected update frequency of the chart
+ update_every: service.update_every, // the expected update frequency of the chart
dimensions: dim
};
chart = service.chart(chartId, chart);
@@ -205,62 +205,126 @@ var fronius = {
},
processResponse: function (service, content) {
- if (content === null) return;
- var json = JSON.parse(content);
- if (!fronius.isResponseValid(json)) return;
+ var json = fronius.convertToJson(content);
+ if (json === null) return;
// add the service
service.commit();
+ var chartDefinitions = fronius.parseCharts(service, json);
+ var chartCount = chartDefinitions.length;
+ while (chartCount--) {
+ var chartObj = chartDefinitions[chartCount];
+ service.begin(chartObj.chart);
+ var dimCount = chartObj.dimensions.length;
+ while (dimCount--) {
+ var dim = chartObj.dimensions[dimCount];
+ service.set(dim.name, dim.value);
+ }
+ service.end();
+ }
+ },
+
+ parseCharts: function (service, json) {
var site = json.Body.Data.Site;
+ return [
+ this.parsePowerChart(service, site),
+ this.parseConsumptionChart(service, site),
+ this.parseAutonomyChart(service, site),
+ this.parseEnergyTodayChart(service, site),
+ this.parseEnergyYearChart(service, site),
+ this.parseInverterChart(service, json.Body.Data.Inverters)
+ ];
+ },
- // Site Current Power Chart
- service.begin(fronius.getSitePowerChart(service, 'fronius_' + service.name + '.power'));
- service.set(fronius.powerGridId, Math.round(site.P_Grid));
- service.set(fronius.powerPvId, Math.round(site.P_PV));
- service.set(fronius.powerAccuId, Math.round(site.P_Akku));
- service.end();
-
- // Site Consumption Chart
- service.begin(fronius.getSiteConsumptionChart(service, 'fronius_' + service.name + '.consumption'));
- service.set(fronius.consumptionLoadId, Math.round(Math.abs(site.P_Load)));
- service.end();
-
- // Site Autonomy Chart
- service.begin(fronius.getSiteAutonomyChart(service, 'fronius_' + service.name + '.autonomy'));
- service.set(fronius.autonomyId, Math.round(site.rel_Autonomy));
+ parsePowerChart: function (service, site) {
+ return this.getChart(this.getSitePowerChart(service, "power"),
+ [
+ this.getDimension(this.powerGridId, Math.round(site.P_Grid)),
+ this.getDimension(this.powerPvId, Math.round(Math.max(site.P_PV, 0))),
+ this.getDimension(this.powerAccuId, Math.round(site.P_Akku))
+ ]
+ );
+ },
+
+ parseConsumptionChart: function (service, site) {
+ return this.getChart(this.getSiteConsumptionChart(service, "consumption"),
+ [this.getDimension(this.consumptionLoadId, Math.round(Math.abs(site.P_Load)))]
+ );
+ },
+
+ parseAutonomyChart: function (service, site) {
var selfConsumption = site.rel_SelfConsumption;
- service.set(fronius.consumptionSelfId, Math.round(selfConsumption === null ? 100 : selfConsumption));
- service.end();
-
- // Site Energy Today Chart
- service.begin(fronius.getSiteEnergyTodayChart(service, 'fronius_' + service.name + '.energy.today'));
- service.set(fronius.energyTodayId, Math.round(site.E_Day));
- service.end();
-
- // Site Energy Year Chart
- service.begin(fronius.getSiteEnergyYearChart(service, 'fronius_' + service.name + '.energy.year'));
- service.set(fronius.energyYearId, Math.round(site.E_Year));
- service.end();
-
- // Inverters
- var inverters = json.Body.Data.Inverters;
- var inverterCount = Object.keys(inverters).length + 1;
- while (inverterCount--) {
- var inverter = inverters[inverterCount];
- if (fronius.isUndefined(inverter)) continue;
- service.begin(fronius.getInverterPowerChart(service, 'fronius_' + service.name + '.inverters.output', inverters));
- service.set(inverterCount.toString(), Math.round(inverter.P));
- service.end();
+ return this.getChart(this.getSiteAutonomyChart(service, "autonomy"),
+ [
+ this.getDimension(this.autonomyId, Math.round(site.rel_Autonomy)),
+ this.getDimension(this.consumptionSelfId, Math.round(selfConsumption === null ? 100 : selfConsumption))
+ ]
+ );
+ },
+
+ parseEnergyTodayChart: function (service, site) {
+ return this.getChart(this.getSiteEnergyTodayChart(service, "energy.today"),
+ [this.getDimension(this.energyTodayId, Math.round(Math.max(site.E_Day, 0)))]
+ );
+ },
+
+ parseEnergyYearChart: function (service, site) {
+ return this.getChart(this.getSiteEnergyYearChart(service, "energy.year"),
+ [this.getDimension(this.energyYearId, Math.round(Math.max(site.E_Year, 0)))]
+ );
+ },
+
+ parseInverterChart: function (service, inverters) {
+ var dimensions = [];
+ for (var key in inverters) {
+ if (inverters.hasOwnProperty(key)) {
+ dimensions.push(this.getDimension(key, Math.round(inverters[key].P)));
+ }
+ }
+ return this.getChart(this.getInverterPowerChart(service, "inverters.output", inverters), dimensions);
+ },
+
+ getDimension: function (name, value) {
+ return {
+ name: name,
+ value: value
+ };
+ },
+
+ getChart: function (chart, dimensions) {
+ return {
+ chart: chart,
+ dimensions: dimensions
+ };
+ },
+
+ getChartId: function (service, suffix) {
+ return "fronius_" + service.name + "." + suffix;
+ },
+
+ convertToJson: function (httpBody) {
+ if (httpBody === null) return null;
+ var json = httpBody;
+ // can't parse if it's already a json object,
+ // the check enables easier testing if the httpBody is already valid JSON.
+ if (typeof httpBody !== "object") {
+ try {
+ json = JSON.parse(httpBody);
+ } catch (error) {
+ netdata.error("fronius: Got a response, but it is not valid JSON. Ignoring. Error: " + error.message);
+ return null;
+ }
}
+ return this.isResponseValid(json) ? json : null;
},
// some basic validation
isResponseValid: function (json) {
- if (fronius.isUndefined(json.Body)) return false;
- if (fronius.isUndefined(json.Body.Data)) return false;
- if (fronius.isUndefined(json.Body.Data.Site)) return false;
- return fronius.isDefined(json.Body.Data.Inverters);
+ if (this.isUndefined(json.Body)) return false;
+ if (this.isUndefined(json.Body.Data)) return false;
+ if (this.isUndefined(json.Body.Data.Site)) return false;
+ return this.isDefined(json.Body.Data.Inverters);
},
// module.serviceExecute()
@@ -268,11 +332,11 @@ var fronius = {
// its purpose is to prepare the request and call
// netdata.serviceExecute()
serviceExecute: function (name, uri, update_every) {
- netdata.debug(this.name + ': ' + name + ': url: ' + uri + ', update_every: ' + update_every);
+ netdata.debug(this.name + ": " + name + ": url: " + uri + ", update_every: " + update_every);
var service = netdata.service({
name: name,
- request: netdata.requestFromURL('http://' + uri),
+ request: netdata.requestFromURL("http://" + uri),
update_every: update_every,
module: this
});
@@ -287,6 +351,7 @@ var fronius = {
while (len--) {
var server = config.servers[len];
if (fronius.isUndefined(server.update_every)) server.update_every = this.update_every;
+ if (fronius.areUndefined([server.name, server.hostname, server.api_path])) continue;
var url = server.hostname + server.api_path;
this.serviceExecute(server.name, url, server.update_every);
@@ -306,11 +371,19 @@ var fronius = {
},
isUndefined: function (value) {
- return typeof value === 'undefined';
+ return typeof value === "undefined";
+ },
+
+ areUndefined: function (valueArray) {
+ var i = 0;
+ for (i; i < valueArray.length; i++) {
+ if (this.isUndefined(valueArray[i])) return true;
+ }
+ return false;
},
isDefined: function (value) {
- return typeof value !== 'undefined';
+ return typeof value !== "undefined";
}
};
diff --git a/node.d/node_modules/asn1-ber.js b/node.d/node_modules/asn1-ber.js
new file mode 100644
index 000000000..57809f486
--- /dev/null
+++ b/node.d/node_modules/asn1-ber.js
@@ -0,0 +1,6 @@
+
+var Ber = require('./lib/ber/index')
+
+exports.Ber = Ber
+exports.BerReader = Ber.Reader
+exports.BerWriter = Ber.Writer
diff --git a/node.d/node_modules/asn1.js b/node.d/node_modules/asn1.js
deleted file mode 100644
index d1766e7a6..000000000
--- a/node.d/node_modules/asn1.js
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.
-
-// If you have no idea what ASN.1 or BER is, see this:
-// ftp://ftp.rsa.com/pub/pkcs/ascii/layman.asc
-
-var Ber = require('./ber/index');
-
-
-
-///--- Exported API
-
-module.exports = {
-
- Ber: Ber,
-
- BerReader: Ber.Reader,
-
- BerWriter: Ber.Writer
-
-};
diff --git a/node.d/node_modules/ber/errors.js b/node.d/node_modules/ber/errors.js
deleted file mode 100644
index ff21d4fab..000000000
--- a/node.d/node_modules/ber/errors.js
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.
-
-
-module.exports = {
-
- newInvalidAsn1Error: function(msg) {
- var e = new Error();
- e.name = 'InvalidAsn1Error';
- e.message = msg || '';
- return e;
- }
-
-};
diff --git a/node.d/node_modules/ber/index.js b/node.d/node_modules/ber/index.js
deleted file mode 100644
index 4fb90aea9..000000000
--- a/node.d/node_modules/ber/index.js
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.
-
-var errors = require('./errors');
-var types = require('./types');
-
-var Reader = require('./reader');
-var Writer = require('./writer');
-
-
-///--- Exports
-
-module.exports = {
-
- Reader: Reader,
-
- Writer: Writer
-
-};
-
-for (var t in types) {
- if (types.hasOwnProperty(t))
- module.exports[t] = types[t];
-}
-for (var e in errors) {
- if (errors.hasOwnProperty(e))
- module.exports[e] = errors[e];
-}
diff --git a/node.d/node_modules/ber/reader.js b/node.d/node_modules/ber/reader.js
deleted file mode 100644
index 0a00e98e3..000000000
--- a/node.d/node_modules/ber/reader.js
+++ /dev/null
@@ -1,261 +0,0 @@
-// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.
-
-var assert = require('assert');
-
-var ASN1 = require('./types');
-var errors = require('./errors');
-
-
-///--- Globals
-
-var newInvalidAsn1Error = errors.newInvalidAsn1Error;
-
-
-
-///--- API
-
-function Reader(data) {
- if (!data || !Buffer.isBuffer(data))
- throw new TypeError('data must be a node Buffer');
-
- this._buf = data;
- this._size = data.length;
-
- // These hold the "current" state
- this._len = 0;
- this._offset = 0;
-}
-
-Object.defineProperty(Reader.prototype, 'length', {
- enumerable: true,
- get: function () { return (this._len); }
-});
-
-Object.defineProperty(Reader.prototype, 'offset', {
- enumerable: true,
- get: function () { return (this._offset); }
-});
-
-Object.defineProperty(Reader.prototype, 'remain', {
- get: function () { return (this._size - this._offset); }
-});
-
-Object.defineProperty(Reader.prototype, 'buffer', {
- get: function () { return (this._buf.slice(this._offset)); }
-});
-
-
-/**
- * Reads a single byte and advances offset; you can pass in `true` to make this
- * a "peek" operation (i.e., get the byte, but don't advance the offset).
- *
- * @param {Boolean} peek true means don't move offset.
- * @return {Number} the next byte, null if not enough data.
- */
-Reader.prototype.readByte = function(peek) {
- if (this._size - this._offset < 1)
- return null;
-
- var b = this._buf[this._offset] & 0xff;
-
- if (!peek)
- this._offset += 1;
-
- return b;
-};
-
-
-Reader.prototype.peek = function() {
- return this.readByte(true);
-};
-
-
-/**
- * Reads a (potentially) variable length off the BER buffer. This call is
- * not really meant to be called directly, as callers have to manipulate
- * the internal buffer afterwards.
- *
- * As a result of this call, you can call `Reader.length`, until the
- * next thing called that does a readLength.
- *
- * @return {Number} the amount of offset to advance the buffer.
- * @throws {InvalidAsn1Error} on bad ASN.1
- */
-Reader.prototype.readLength = function(offset) {
- if (offset === undefined)
- offset = this._offset;
-
- if (offset >= this._size)
- return null;
-
- var lenB = this._buf[offset++] & 0xff;
- if (lenB === null)
- return null;
-
- if ((lenB & 0x80) == 0x80) {
- lenB &= 0x7f;
-
- if (lenB == 0)
- throw newInvalidAsn1Error('Indefinite length not supported');
-
- if (lenB > 4)
- throw newInvalidAsn1Error('encoding too long');
-
- if (this._size - offset < lenB)
- return null;
-
- this._len = 0;
- for (var i = 0; i < lenB; i++)
- this._len = (this._len << 8) + (this._buf[offset++] & 0xff);
-
- } else {
- // Wasn't a variable length
- this._len = lenB;
- }
-
- return offset;
-};
-
-
-/**
- * Parses the next sequence in this BER buffer.
- *
- * To get the length of the sequence, call `Reader.length`.
- *
- * @return {Number} the sequence's tag.
- */
-Reader.prototype.readSequence = function(tag) {
- var seq = this.peek();
- if (seq === null)
- return null;
- if (tag !== undefined && tag !== seq)
- throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) +
- ': got 0x' + seq.toString(16));
-
- var o = this.readLength(this._offset + 1); // stored in `length`
- if (o === null)
- return null;
-
- this._offset = o;
- return seq;
-};
-
-
-Reader.prototype.readInt = function() {
- return this._readTag(ASN1.Integer);
-};
-
-
-Reader.prototype.readBoolean = function() {
- return (this._readTag(ASN1.Boolean) === 0 ? false : true);
-};
-
-
-Reader.prototype.readEnumeration = function() {
- return this._readTag(ASN1.Enumeration);
-};
-
-
-Reader.prototype.readString = function(tag, retbuf) {
- if (!tag)
- tag = ASN1.OctetString;
-
- var b = this.peek();
- if (b === null)
- return null;
-
- if (b !== tag)
- throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) +
- ': got 0x' + b.toString(16));
-
- var o = this.readLength(this._offset + 1); // stored in `length`
-
- if (o === null)
- return null;
-
- if (this.length > this._size - o)
- return null;
-
- this._offset = o;
-
- if (this.length === 0)
- return retbuf ? new Buffer(0) : '';
-
- var str = this._buf.slice(this._offset, this._offset + this.length);
- this._offset += this.length;
-
- return retbuf ? str : str.toString('utf8');
-};
-
-Reader.prototype.readOID = function(tag) {
- if (!tag)
- tag = ASN1.OID;
-
- var b = this.readString(tag, true);
- if (b === null)
- return null;
-
- var values = [];
- var value = 0;
-
- for (var i = 0; i < b.length; i++) {
- var byte = b[i] & 0xff;
-
- value <<= 7;
- value += byte & 0x7f;
- if ((byte & 0x80) == 0) {
- values.push(value);
- value = 0;
- }
- }
-
- value = values.shift();
- values.unshift(value % 40);
- values.unshift((value / 40) >> 0);
-
- return values.join('.');
-};
-
-
-Reader.prototype._readTag = function(tag) {
- assert.ok(tag !== undefined);
-
- var b = this.peek();
-
- if (b === null)
- return null;
-
- if (b !== tag)
- throw newInvalidAsn1Error('Expected 0x' + tag.toString(16) +
- ': got 0x' + b.toString(16));
-
- var o = this.readLength(this._offset + 1); // stored in `length`
- if (o === null)
- return null;
-
- if (this.length > 4)
- throw newInvalidAsn1Error('Integer too long: ' + this.length);
-
- if (this.length > this._size - o)
- return null;
- this._offset = o;
-
- var fb = this._buf[this._offset];
- var value = 0;
-
- for (var i = 0; i < this.length; i++) {
- value <<= 8;
- value |= (this._buf[this._offset++] & 0xff);
- }
-
- if ((fb & 0x80) == 0x80 && i !== 4)
- value -= (1 << (i * 8));
-
- return value >> 0;
-};
-
-
-
-///--- Exported API
-
-module.exports = Reader;
diff --git a/node.d/node_modules/ber/types.js b/node.d/node_modules/ber/types.js
deleted file mode 100644
index 8aea00013..000000000
--- a/node.d/node_modules/ber/types.js
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.
-
-
-module.exports = {
- EOC: 0,
- Boolean: 1,
- Integer: 2,
- BitString: 3,
- OctetString: 4,
- Null: 5,
- OID: 6,
- ObjectDescriptor: 7,
- External: 8,
- Real: 9, // float
- Enumeration: 10,
- PDV: 11,
- Utf8String: 12,
- RelativeOID: 13,
- Sequence: 16,
- Set: 17,
- NumericString: 18,
- PrintableString: 19,
- T61String: 20,
- VideotexString: 21,
- IA5String: 22,
- UTCTime: 23,
- GeneralizedTime: 24,
- GraphicString: 25,
- VisibleString: 26,
- GeneralString: 28,
- UniversalString: 29,
- CharacterString: 30,
- BMPString: 31,
- Constructor: 32,
- Context: 128
-};
diff --git a/node.d/node_modules/ber/writer.js b/node.d/node_modules/ber/writer.js
deleted file mode 100644
index d9d99af68..000000000
--- a/node.d/node_modules/ber/writer.js
+++ /dev/null
@@ -1,316 +0,0 @@
-// Copyright 2011 Mark Cavage <mcavage@gmail.com> All rights reserved.
-
-var assert = require('assert');
-var ASN1 = require('./types');
-var errors = require('./errors');
-
-
-///--- Globals
-
-var newInvalidAsn1Error = errors.newInvalidAsn1Error;
-
-var DEFAULT_OPTS = {
- size: 1024,
- growthFactor: 8
-};
-
-
-///--- Helpers
-
-function merge(from, to) {
- assert.ok(from);
- assert.equal(typeof(from), 'object');
- assert.ok(to);
- assert.equal(typeof(to), 'object');
-
- var keys = Object.getOwnPropertyNames(from);
- keys.forEach(function(key) {
- if (to[key])
- return;
-
- var value = Object.getOwnPropertyDescriptor(from, key);
- Object.defineProperty(to, key, value);
- });
-
- return to;
-}
-
-
-
-///--- API
-
-function Writer(options) {
- options = merge(DEFAULT_OPTS, options || {});
-
- this._buf = new Buffer(options.size || 1024);
- this._size = this._buf.length;
- this._offset = 0;
- this._options = options;
-
- // A list of offsets in the buffer where we need to insert
- // sequence tag/len pairs.
- this._seq = [];
-}
-
-Object.defineProperty(Writer.prototype, 'buffer', {
- get: function () {
- if (this._seq.length)
- throw new InvalidAsn1Error(this._seq.length + ' unended sequence(s)');
-
- return (this._buf.slice(0, this._offset));
- }
-});
-
-Writer.prototype.writeByte = function(b) {
- if (typeof(b) !== 'number')
- throw new TypeError('argument must be a Number');
-
- this._ensure(1);
- this._buf[this._offset++] = b;
-};
-
-
-Writer.prototype.writeInt = function(i, tag) {
- if (typeof(i) !== 'number')
- throw new TypeError('argument must be a Number');
- if (typeof(tag) !== 'number')
- tag = ASN1.Integer;
-
- var sz = 4;
-
- while ((((i & 0xff800000) === 0) || ((i & 0xff800000) === 0xff800000 >> 0)) &&
- (sz > 1)) {
- sz--;
- i <<= 8;
- }
-
- if (sz > 4)
- throw new InvalidAsn1Error('BER ints cannot be > 0xffffffff');
-
- this._ensure(2 + sz);
- this._buf[this._offset++] = tag;
- this._buf[this._offset++] = sz;
-
- while (sz-- > 0) {
- this._buf[this._offset++] = ((i & 0xff000000) >>> 24);
- i <<= 8;
- }
-
-};
-
-
-Writer.prototype.writeNull = function() {
- this.writeByte(ASN1.Null);
- this.writeByte(0x00);
-};
-
-
-Writer.prototype.writeEnumeration = function(i, tag) {
- if (typeof(i) !== 'number')
- throw new TypeError('argument must be a Number');
- if (typeof(tag) !== 'number')
- tag = ASN1.Enumeration;
-
- return this.writeInt(i, tag);
-};
-
-
-Writer.prototype.writeBoolean = function(b, tag) {
- if (typeof(b) !== 'boolean')
- throw new TypeError('argument must be a Boolean');
- if (typeof(tag) !== 'number')
- tag = ASN1.Boolean;
-
- this._ensure(3);
- this._buf[this._offset++] = tag;
- this._buf[this._offset++] = 0x01;
- this._buf[this._offset++] = b ? 0xff : 0x00;
-};
-
-
-Writer.prototype.writeString = function(s, tag) {
- if (typeof(s) !== 'string')
- throw new TypeError('argument must be a string (was: ' + typeof(s) + ')');
- if (typeof(tag) !== 'number')
- tag = ASN1.OctetString;
-
- var len = Buffer.byteLength(s);
- this.writeByte(tag);
- this.writeLength(len);
- if (len) {
- this._ensure(len);
- this._buf.write(s, this._offset);
- this._offset += len;
- }
-};
-
-
-Writer.prototype.writeBuffer = function(buf, tag) {
- if (typeof(tag) !== 'number')
- throw new TypeError('tag must be a number');
- if (!Buffer.isBuffer(buf))
- throw new TypeError('argument must be a buffer');
-
- this.writeByte(tag);
- this.writeLength(buf.length);
- this._ensure(buf.length);
- buf.copy(this._buf, this._offset, 0, buf.length);
- this._offset += buf.length;
-};
-
-
-Writer.prototype.writeStringArray = function(strings) {
- if ((!strings instanceof Array))
- throw new TypeError('argument must be an Array[String]');
-
- var self = this;
- strings.forEach(function(s) {
- self.writeString(s);
- });
-};
-
-// This is really to solve DER cases, but whatever for now
-Writer.prototype.writeOID = function(s, tag) {
- if (typeof(s) !== 'string')
- throw new TypeError('argument must be a string');
- if (typeof(tag) !== 'number')
- tag = ASN1.OID;
-
- if (!/^([0-9]+\.){3,}[0-9]+$/.test(s))
- throw new Error('argument is not a valid OID string');
-
- function encodeOctet(bytes, octet) {
- if (octet < 128) {
- bytes.push(octet);
- } else if (octet < 16384) {
- bytes.push((octet >>> 7) | 0x80);
- bytes.push(octet & 0x7F);
- } else if (octet < 2097152) {
- bytes.push((octet >>> 14) | 0x80);
- bytes.push(((octet >>> 7) | 0x80) & 0xFF);
- bytes.push(octet & 0x7F);
- } else if (octet < 268435456) {
- bytes.push((octet >>> 21) | 0x80);
- bytes.push(((octet >>> 14) | 0x80) & 0xFF);
- bytes.push(((octet >>> 7) | 0x80) & 0xFF);
- bytes.push(octet & 0x7F);
- } else {
- bytes.push(((octet >>> 28) | 0x80) & 0xFF);
- bytes.push(((octet >>> 21) | 0x80) & 0xFF);
- bytes.push(((octet >>> 14) | 0x80) & 0xFF);
- bytes.push(((octet >>> 7) | 0x80) & 0xFF);
- bytes.push(octet & 0x7F);
- }
- }
-
- var tmp = s.split('.');
- var bytes = [];
- bytes.push(parseInt(tmp[0], 10) * 40 + parseInt(tmp[1], 10));
- tmp.slice(2).forEach(function(b) {
- encodeOctet(bytes, parseInt(b, 10));
- });
-
- var self = this;
- this._ensure(2 + bytes.length);
- this.writeByte(tag);
- this.writeLength(bytes.length);
- bytes.forEach(function(b) {
- self.writeByte(b);
- });
-};
-
-
-Writer.prototype.writeLength = function(len) {
- if (typeof(len) !== 'number')
- throw new TypeError('argument must be a Number');
-
- this._ensure(4);
-
- if (len <= 0x7f) {
- this._buf[this._offset++] = len;
- } else if (len <= 0xff) {
- this._buf[this._offset++] = 0x81;
- this._buf[this._offset++] = len;
- } else if (len <= 0xffff) {
- this._buf[this._offset++] = 0x82;
- this._buf[this._offset++] = len >> 8;
- this._buf[this._offset++] = len;
- } else if (len <= 0xffffff) {
- this._buf[this._offset++] = 0x83;
- this._buf[this._offset++] = len >> 16;
- this._buf[this._offset++] = len >> 8;
- this._buf[this._offset++] = len;
- } else {
- throw new InvalidAsn1ERror('Length too long (> 4 bytes)');
- }
-};
-
-Writer.prototype.startSequence = function(tag) {
- if (typeof(tag) !== 'number')
- tag = ASN1.Sequence | ASN1.Constructor;
-
- this.writeByte(tag);
- this._seq.push(this._offset);
- this._ensure(3);
- this._offset += 3;
-};
-
-
-Writer.prototype.endSequence = function() {
- var seq = this._seq.pop();
- var start = seq + 3;
- var len = this._offset - start;
-
- if (len <= 0x7f) {
- this._shift(start, len, -2);
- this._buf[seq] = len;
- } else if (len <= 0xff) {
- this._shift(start, len, -1);
- this._buf[seq] = 0x81;
- this._buf[seq + 1] = len;
- } else if (len <= 0xffff) {
- this._buf[seq] = 0x82;
- this._buf[seq + 1] = len >> 8;
- this._buf[seq + 2] = len;
- } else if (len <= 0xffffff) {
- this._shift(start, len, 1);
- this._buf[seq] = 0x83;
- this._buf[seq + 1] = len >> 16;
- this._buf[seq + 2] = len >> 8;
- this._buf[seq + 3] = len;
- } else {
- throw new InvalidAsn1Error('Sequence too long');
- }
-};
-
-
-Writer.prototype._shift = function(start, len, shift) {
- assert.ok(start !== undefined);
- assert.ok(len !== undefined);
- assert.ok(shift);
-
- this._buf.copy(this._buf, start + shift, start, start + len);
- this._offset += shift;
-};
-
-Writer.prototype._ensure = function(len) {
- assert.ok(len);
-
- if (this._size - this._offset < len) {
- var sz = this._size * this._options.growthFactor;
- if (sz - this._offset < len)
- sz += len;
-
- var buf = new Buffer(sz);
-
- this._buf.copy(buf, 0, 0, this._offset);
- this._buf = buf;
- this._size = sz;
- }
-};
-
-
-
-///--- Exported API
-
-module.exports = Writer;
diff --git a/node.d/node_modules/lib/ber/errors.js b/node.d/node_modules/lib/ber/errors.js
new file mode 100644
index 000000000..0106747e6
--- /dev/null
+++ b/node.d/node_modules/lib/ber/errors.js
@@ -0,0 +1,9 @@
+
+module.exports = {
+ InvalidAsn1Error: function(msg) {
+ var e = new Error()
+ e.name = 'InvalidAsn1Error'
+ e.message = msg || ''
+ return e
+ }
+}
diff --git a/node.d/node_modules/lib/ber/index.js b/node.d/node_modules/lib/ber/index.js
new file mode 100644
index 000000000..65985c1e1
--- /dev/null
+++ b/node.d/node_modules/lib/ber/index.js
@@ -0,0 +1,17 @@
+
+var errors = require('./errors')
+var types = require('./types')
+
+var Reader = require('./reader')
+var Writer = require('./writer')
+
+for (var t in types)
+ if (types.hasOwnProperty(t))
+ exports[t] = types[t]
+
+for (var e in errors)
+ if (errors.hasOwnProperty(e))
+ exports[e] = errors[e]
+
+exports.Reader = Reader
+exports.Writer = Writer
diff --git a/node.d/node_modules/lib/ber/reader.js b/node.d/node_modules/lib/ber/reader.js
new file mode 100644
index 000000000..f93d829aa
--- /dev/null
+++ b/node.d/node_modules/lib/ber/reader.js
@@ -0,0 +1,269 @@
+
+var assert = require('assert');
+
+var ASN1 = require('./types');
+var errors = require('./errors');
+
+
+///--- Globals
+
+var InvalidAsn1Error = errors.InvalidAsn1Error;
+
+
+
+///--- API
+
+function Reader(data) {
+ if (!data || !Buffer.isBuffer(data))
+ throw new TypeError('data must be a node Buffer');
+
+ this._buf = data;
+ this._size = data.length;
+
+ // These hold the "current" state
+ this._len = 0;
+ this._offset = 0;
+}
+
+Object.defineProperty(Reader.prototype, 'length', {
+ enumerable: true,
+ get: function () { return (this._len); }
+});
+
+Object.defineProperty(Reader.prototype, 'offset', {
+ enumerable: true,
+ get: function () { return (this._offset); }
+});
+
+Object.defineProperty(Reader.prototype, 'remain', {
+ get: function () { return (this._size - this._offset); }
+});
+
+Object.defineProperty(Reader.prototype, 'buffer', {
+ get: function () { return (this._buf.slice(this._offset)); }
+});
+
+
+/**
+ * Reads a single byte and advances offset; you can pass in `true` to make this
+ * a "peek" operation (i.e., get the byte, but don't advance the offset).
+ *
+ * @param {Boolean} peek true means don't move offset.
+ * @return {Number} the next byte, null if not enough data.
+ */
+Reader.prototype.readByte = function(peek) {
+ if (this._size - this._offset < 1)
+ return null;
+
+ var b = this._buf[this._offset] & 0xff;
+
+ if (!peek)
+ this._offset += 1;
+
+ return b;
+};
+
+
+Reader.prototype.peek = function() {
+ return this.readByte(true);
+};
+
+
+/**
+ * Reads a (potentially) variable length off the BER buffer. This call is
+ * not really meant to be called directly, as callers have to manipulate
+ * the internal buffer afterwards.
+ *
+ * As a result of this call, you can call `Reader.length`, until the
+ * next thing called that does a readLength.
+ *
+ * @return {Number} the amount of offset to advance the buffer.
+ * @throws {InvalidAsn1Error} on bad ASN.1
+ */
+Reader.prototype.readLength = function(offset) {
+ if (offset === undefined)
+ offset = this._offset;
+
+ if (offset >= this._size)
+ return null;
+
+ var lenB = this._buf[offset++] & 0xff;
+ if (lenB === null)
+ return null;
+
+ if ((lenB & 0x80) == 0x80) {
+ lenB &= 0x7f;
+
+ if (lenB == 0)
+ throw InvalidAsn1Error('Indefinite length not supported');
+
+ if (lenB > 4)
+ throw InvalidAsn1Error('encoding too long');
+
+ if (this._size - offset < lenB)
+ return null;
+
+ this._len = 0;
+ for (var i = 0; i < lenB; i++)
+ this._len = (this._len << 8) + (this._buf[offset++] & 0xff);
+
+ } else {
+ // Wasn't a variable length
+ this._len = lenB;
+ }
+
+ return offset;
+};
+
+
+/**
+ * Parses the next sequence in this BER buffer.
+ *
+ * To get the length of the sequence, call `Reader.length`.
+ *
+ * @return {Number} the sequence's tag.
+ */
+Reader.prototype.readSequence = function(tag) {
+ var seq = this.peek();
+ if (seq === null)
+ return null;
+ if (tag !== undefined && tag !== seq)
+ throw InvalidAsn1Error('Expected 0x' + tag.toString(16) +
+ ': got 0x' + seq.toString(16));
+
+ var o = this.readLength(this._offset + 1); // stored in `length`
+ if (o === null)
+ return null;
+
+ this._offset = o;
+ return seq;
+};
+
+
+Reader.prototype.readInt = function(tag) {
+ if (typeof(tag) !== 'number')
+ tag = ASN1.Integer;
+
+ return this._readTag(ASN1.Integer);
+};
+
+
+Reader.prototype.readBoolean = function(tag) {
+ if (typeof(tag) !== 'number')
+ tag = ASN1.Boolean;
+
+ return (this._readTag(tag) === 0 ? false : true);
+};
+
+
+Reader.prototype.readEnumeration = function(tag) {
+ if (typeof(tag) !== 'number')
+ tag = ASN1.Enumeration;
+
+ return this._readTag(ASN1.Enumeration);
+};
+
+
+Reader.prototype.readString = function(tag, retbuf) {
+ if (!tag)
+ tag = ASN1.OctetString;
+
+ var b = this.peek();
+ if (b === null)
+ return null;
+
+ if (b !== tag)
+ throw InvalidAsn1Error('Expected 0x' + tag.toString(16) +
+ ': got 0x' + b.toString(16));
+
+ var o = this.readLength(this._offset + 1); // stored in `length`
+
+ if (o === null)
+ return null;
+
+ if (this.length > this._size - o)
+ return null;
+
+ this._offset = o;
+
+ if (this.length === 0)
+ return retbuf ? new Buffer(0) : '';
+
+ var str = this._buf.slice(this._offset, this._offset + this.length);
+ this._offset += this.length;
+
+ return retbuf ? str : str.toString('utf8');
+};
+
+Reader.prototype.readOID = function(tag) {
+ if (!tag)
+ tag = ASN1.OID;
+
+ var b = this.readString(tag, true);
+ if (b === null)
+ return null;
+
+ var values = [];
+ var value = 0;
+
+ for (var i = 0; i < b.length; i++) {
+ var byte = b[i] & 0xff;
+
+ value <<= 7;
+ value += byte & 0x7f;
+ if ((byte & 0x80) == 0) {
+ values.push(value >>> 0);
+ value = 0;
+ }
+ }
+
+ value = values.shift();
+ values.unshift(value % 40);
+ values.unshift((value / 40) >> 0);
+
+ return values.join('.');
+};
+
+
+Reader.prototype._readTag = function(tag) {
+ assert.ok(tag !== undefined);
+
+ var b = this.peek();
+
+ if (b === null)
+ return null;
+
+ if (b !== tag)
+ throw InvalidAsn1Error('Expected 0x' + tag.toString(16) +
+ ': got 0x' + b.toString(16));
+
+ var o = this.readLength(this._offset + 1); // stored in `length`
+ if (o === null)
+ return null;
+
+ if (this.length > 4)
+ throw InvalidAsn1Error('Integer too long: ' + this.length);
+
+ if (this.length > this._size - o)
+ return null;
+ this._offset = o;
+
+ var fb = this._buf[this._offset];
+ var value = 0;
+
+ for (var i = 0; i < this.length; i++) {
+ value <<= 8;
+ value |= (this._buf[this._offset++] & 0xff);
+ }
+
+ if ((fb & 0x80) == 0x80 && i !== 4)
+ value -= (1 << (i * 8));
+
+ return value >> 0;
+};
+
+
+
+///--- Exported API
+
+module.exports = Reader;
diff --git a/node.d/node_modules/lib/ber/types.js b/node.d/node_modules/lib/ber/types.js
new file mode 100644
index 000000000..345824bb1
--- /dev/null
+++ b/node.d/node_modules/lib/ber/types.js
@@ -0,0 +1,34 @@
+
+module.exports = {
+ EOC: 0,
+ Boolean: 1,
+ Integer: 2,
+ BitString: 3,
+ OctetString: 4,
+ Null: 5,
+ OID: 6,
+ ObjectDescriptor: 7,
+ External: 8,
+ Real: 9,
+ Enumeration: 10,
+ PDV: 11,
+ Utf8String: 12,
+ RelativeOID: 13,
+ Sequence: 16,
+ Set: 17,
+ NumericString: 18,
+ PrintableString: 19,
+ T61String: 20,
+ VideotexString: 21,
+ IA5String: 22,
+ UTCTime: 23,
+ GeneralizedTime: 24,
+ GraphicString: 25,
+ VisibleString: 26,
+ GeneralString: 28,
+ UniversalString: 29,
+ CharacterString: 30,
+ BMPString: 31,
+ Constructor: 32,
+ Context: 128
+}
diff --git a/node.d/node_modules/lib/ber/writer.js b/node.d/node_modules/lib/ber/writer.js
new file mode 100644
index 000000000..bf9805886
--- /dev/null
+++ b/node.d/node_modules/lib/ber/writer.js
@@ -0,0 +1,317 @@
+
+var assert = require('assert');
+var ASN1 = require('./types');
+var errors = require('./errors');
+
+
+///--- Globals
+
+var InvalidAsn1Error = errors.InvalidAsn1Error;
+
+var DEFAULT_OPTS = {
+ size: 1024,
+ growthFactor: 8
+};
+
+
+///--- Helpers
+
+function merge(from, to) {
+ assert.ok(from);
+ assert.equal(typeof(from), 'object');
+ assert.ok(to);
+ assert.equal(typeof(to), 'object');
+
+ var keys = Object.getOwnPropertyNames(from);
+ keys.forEach(function(key) {
+ if (to[key])
+ return;
+
+ var value = Object.getOwnPropertyDescriptor(from, key);
+ Object.defineProperty(to, key, value);
+ });
+
+ return to;
+}
+
+
+
+///--- API
+
+function Writer(options) {
+ options = merge(DEFAULT_OPTS, options || {});
+
+ this._buf = new Buffer(options.size || 1024);
+ this._size = this._buf.length;
+ this._offset = 0;
+ this._options = options;
+
+ // A list of offsets in the buffer where we need to insert
+ // sequence tag/len pairs.
+ this._seq = [];
+}
+
+Object.defineProperty(Writer.prototype, 'buffer', {
+ get: function () {
+ if (this._seq.length)
+ throw new InvalidAsn1Error(this._seq.length + ' unended sequence(s)');
+
+ return (this._buf.slice(0, this._offset));
+ }
+});
+
+Writer.prototype.writeByte = function(b) {
+ if (typeof(b) !== 'number')
+ throw new TypeError('argument must be a Number');
+
+ this._ensure(1);
+ this._buf[this._offset++] = b;
+};
+
+
+Writer.prototype.writeInt = function(i, tag) {
+ if (typeof(i) !== 'number')
+ throw new TypeError('argument must be a Number');
+ if (typeof(tag) !== 'number')
+ tag = ASN1.Integer;
+
+ var sz = 4;
+
+ while ((((i & 0xff800000) === 0) || ((i & 0xff800000) === 0xff800000 >> 0)) &&
+ (sz > 1)) {
+ sz--;
+ i <<= 8;
+ }
+
+ if (sz > 4)
+ throw new InvalidAsn1Error('BER ints cannot be > 0xffffffff');
+
+ this._ensure(2 + sz);
+ this._buf[this._offset++] = tag;
+ this._buf[this._offset++] = sz;
+
+ while (sz-- > 0) {
+ this._buf[this._offset++] = ((i & 0xff000000) >>> 24);
+ i <<= 8;
+ }
+
+};
+
+
+Writer.prototype.writeNull = function() {
+ this.writeByte(ASN1.Null);
+ this.writeByte(0x00);
+};
+
+
+Writer.prototype.writeEnumeration = function(i, tag) {
+ if (typeof(i) !== 'number')
+ throw new TypeError('argument must be a Number');
+ if (typeof(tag) !== 'number')
+ tag = ASN1.Enumeration;
+
+ return this.writeInt(i, tag);
+};
+
+
+Writer.prototype.writeBoolean = function(b, tag) {
+ if (typeof(b) !== 'boolean')
+ throw new TypeError('argument must be a Boolean');
+ if (typeof(tag) !== 'number')
+ tag = ASN1.Boolean;
+
+ this._ensure(3);
+ this._buf[this._offset++] = tag;
+ this._buf[this._offset++] = 0x01;
+ this._buf[this._offset++] = b ? 0xff : 0x00;
+};
+
+
+Writer.prototype.writeString = function(s, tag) {
+ if (typeof(s) !== 'string')
+ throw new TypeError('argument must be a string (was: ' + typeof(s) + ')');
+ if (typeof(tag) !== 'number')
+ tag = ASN1.OctetString;
+
+ var len = Buffer.byteLength(s);
+ this.writeByte(tag);
+ this.writeLength(len);
+ if (len) {
+ this._ensure(len);
+ this._buf.write(s, this._offset);
+ this._offset += len;
+ }
+};
+
+
+Writer.prototype.writeBuffer = function(buf, tag) {
+ if (!Buffer.isBuffer(buf))
+ throw new TypeError('argument must be a buffer');
+
+ // If no tag is specified we will assume `buf` already contains tag and length
+ if (typeof(tag) === 'number') {
+ this.writeByte(tag);
+ this.writeLength(buf.length);
+ }
+
+ this._ensure(buf.length);
+ buf.copy(this._buf, this._offset, 0, buf.length);
+ this._offset += buf.length;
+};
+
+
+Writer.prototype.writeStringArray = function(strings, tag) {
+ if (! (strings instanceof Array))
+ throw new TypeError('argument must be an Array[String]');
+
+ var self = this;
+ strings.forEach(function(s) {
+ self.writeString(s, tag);
+ });
+};
+
+// This is really to solve DER cases, but whatever for now
+Writer.prototype.writeOID = function(s, tag) {
+ if (typeof(s) !== 'string')
+ throw new TypeError('argument must be a string');
+ if (typeof(tag) !== 'number')
+ tag = ASN1.OID;
+
+ if (!/^([0-9]+\.){3,}[0-9]+$/.test(s))
+ throw new Error('argument is not a valid OID string');
+
+ function encodeOctet(bytes, octet) {
+ if (octet < 128) {
+ bytes.push(octet);
+ } else if (octet < 16384) {
+ bytes.push((octet >>> 7) | 0x80);
+ bytes.push(octet & 0x7F);
+ } else if (octet < 2097152) {
+ bytes.push((octet >>> 14) | 0x80);
+ bytes.push(((octet >>> 7) | 0x80) & 0xFF);
+ bytes.push(octet & 0x7F);
+ } else if (octet < 268435456) {
+ bytes.push((octet >>> 21) | 0x80);
+ bytes.push(((octet >>> 14) | 0x80) & 0xFF);
+ bytes.push(((octet >>> 7) | 0x80) & 0xFF);
+ bytes.push(octet & 0x7F);
+ } else {
+ bytes.push(((octet >>> 28) | 0x80) & 0xFF);
+ bytes.push(((octet >>> 21) | 0x80) & 0xFF);
+ bytes.push(((octet >>> 14) | 0x80) & 0xFF);
+ bytes.push(((octet >>> 7) | 0x80) & 0xFF);
+ bytes.push(octet & 0x7F);
+ }
+ }
+
+ var tmp = s.split('.');
+ var bytes = [];
+ bytes.push(parseInt(tmp[0], 10) * 40 + parseInt(tmp[1], 10));
+ tmp.slice(2).forEach(function(b) {
+ encodeOctet(bytes, parseInt(b, 10));
+ });
+
+ var self = this;
+ this._ensure(2 + bytes.length);
+ this.writeByte(tag);
+ this.writeLength(bytes.length);
+ bytes.forEach(function(b) {
+ self.writeByte(b);
+ });
+};
+
+
+Writer.prototype.writeLength = function(len) {
+ if (typeof(len) !== 'number')
+ throw new TypeError('argument must be a Number');
+
+ this._ensure(4);
+
+ if (len <= 0x7f) {
+ this._buf[this._offset++] = len;
+ } else if (len <= 0xff) {
+ this._buf[this._offset++] = 0x81;
+ this._buf[this._offset++] = len;
+ } else if (len <= 0xffff) {
+ this._buf[this._offset++] = 0x82;
+ this._buf[this._offset++] = len >> 8;
+ this._buf[this._offset++] = len;
+ } else if (len <= 0xffffff) {
+ this._buf[this._offset++] = 0x83;
+ this._buf[this._offset++] = len >> 16;
+ this._buf[this._offset++] = len >> 8;
+ this._buf[this._offset++] = len;
+ } else {
+ throw new InvalidAsn1Error('Length too long (> 4 bytes)');
+ }
+};
+
+Writer.prototype.startSequence = function(tag) {
+ if (typeof(tag) !== 'number')
+ tag = ASN1.Sequence | ASN1.Constructor;
+
+ this.writeByte(tag);
+ this._seq.push(this._offset);
+ this._ensure(3);
+ this._offset += 3;
+};
+
+
+Writer.prototype.endSequence = function() {
+ var seq = this._seq.pop();
+ var start = seq + 3;
+ var len = this._offset - start;
+
+ if (len <= 0x7f) {
+ this._shift(start, len, -2);
+ this._buf[seq] = len;
+ } else if (len <= 0xff) {
+ this._shift(start, len, -1);
+ this._buf[seq] = 0x81;
+ this._buf[seq + 1] = len;
+ } else if (len <= 0xffff) {
+ this._buf[seq] = 0x82;
+ this._buf[seq + 1] = len >> 8;
+ this._buf[seq + 2] = len;
+ } else if (len <= 0xffffff) {
+ this._shift(start, len, 1);
+ this._buf[seq] = 0x83;
+ this._buf[seq + 1] = len >> 16;
+ this._buf[seq + 2] = len >> 8;
+ this._buf[seq + 3] = len;
+ } else {
+ throw new InvalidAsn1Error('Sequence too long');
+ }
+};
+
+
+Writer.prototype._shift = function(start, len, shift) {
+ assert.ok(start !== undefined);
+ assert.ok(len !== undefined);
+ assert.ok(shift);
+
+ this._buf.copy(this._buf, start + shift, start, start + len);
+ this._offset += shift;
+};
+
+Writer.prototype._ensure = function(len) {
+ assert.ok(len);
+
+ if (this._size - this._offset < len) {
+ var sz = this._size * this._options.growthFactor;
+ if (sz - this._offset < len)
+ sz += len;
+
+ var buf = new Buffer(sz);
+
+ this._buf.copy(buf, 0, 0, this._offset);
+ this._buf = buf;
+ this._size = sz;
+ }
+};
+
+
+
+///--- Exported API
+
+module.exports = Writer;
diff --git a/node.d/node_modules/net-snmp.js b/node.d/node_modules/net-snmp.js
index de5926104..ac9a8d350 100644
--- a/node.d/node_modules/net-snmp.js
+++ b/node.d/node_modules/net-snmp.js
@@ -1,7 +1,7 @@
// Copyright 2013 Stephen Vickers <stephen.vickers.sv@gmail.com>
-var ber = require ("asn1").Ber;
+var ber = require ("asn1-ber").Ber;
var dgram = require ("dgram");
var events = require ("events");
var util = require ("util");
diff --git a/node.d/node_modules/netdata.js b/node.d/node_modules/netdata.js
index 11202061e..143255d9e 100644
--- a/node.d/node_modules/netdata.js
+++ b/node.d/node_modules/netdata.js
@@ -364,12 +364,8 @@ var netdata = {
if(typeof value === 'undefined' || value === null)
return false;
- if(this._current_chart._dimensions_count !== 0) {
- if (value instanceof Buffer)
- this.queue('SET ' + dimension + ' = 0x' + value.toString('hex'));
- else
- this.queue('SET ' + dimension + ' = ' + value.toString());
- }
+ if(this._current_chart._dimensions_count !== 0)
+ this.queue('SET ' + dimension + ' = ' + value.toString());
return true;
};
diff --git a/node.d/snmp.node.js b/node.d/snmp.node.js
index 57b37ffa0..3e7027958 100644
--- a/node.d/snmp.node.js
+++ b/node.d/snmp.node.js
@@ -269,13 +269,36 @@ netdata.processors.snmp = {
failed++;
}
else {
- if(__DEBUG === true)
- netdata.debug(service.module.name + ': ' + service.name + ': found ' + service.module.name + ' value of OIDs ' + varbinds[i].oid + " = " + varbinds[i].value);
-
- if(varbinds[i].type === net_snmp.ObjectType.OctetString && service.snmp_oids_index[varbinds[i].oid].type !== 'title')
- value = parseFloat(varbinds[i].value) * 1000;
- else
- value = varbinds[i].value;
+ // test fom Counter64
+ // varbinds[i].type = net_snmp.ObjectType.Counter64;
+ // varbinds[i].value = new Buffer([0x34, 0x49, 0x2e, 0xdc, 0xd1]);
+
+ switch(varbinds[i].type) {
+ case net_snmp.ObjectType.OctetString:
+ if(service.snmp_oids_index[varbinds[i].oid].type !== 'title')
+ // parse floating point values, exposed as strings
+ value = parseFloat(varbinds[i].value) * 1000;
+ if(__DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': found ' + service.module.name + ' value of OIDs ' + varbinds[i].oid + ", ObjectType " + net_snmp.ObjectType[varbinds[i].type] + " (" + netdata.stringify(varbinds[i].type) + "), typeof(" + typeof(varbinds[i].value) + "), in JSON: " + netdata.stringify(varbinds[i].value) + ", value = " + value.toString() + " (parsed as float in string)");
+ else
+ // just use the string
+ value = varbinds[i].value;
+ if(__DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': found ' + service.module.name + ' value of OIDs ' + varbinds[i].oid + ", ObjectType " + net_snmp.ObjectType[varbinds[i].type] + " (" + netdata.stringify(varbinds[i].type) + "), typeof(" + typeof(varbinds[i].value) + "), in JSON: " + netdata.stringify(varbinds[i].value) + ", value = " + value.toString() + " (parsed as string)");
+ break;
+
+ case net_snmp.ObjectType.Counter64:
+ // copy the buffer
+ value = '0x' + varbinds[i].value.toString('hex');
+ if(__DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': found ' + service.module.name + ' value of OIDs ' + varbinds[i].oid + ", ObjectType " + net_snmp.ObjectType[varbinds[i].type] + " (" + netdata.stringify(varbinds[i].type) + "), typeof(" + typeof(varbinds[i].value) + "), in JSON: " + netdata.stringify(varbinds[i].value) + ", value = " + value.toString() + " (parsed as buffer)");
+ break;
+
+ case net_snmp.ObjectType.Integer:
+ case net_snmp.ObjectType.Counter:
+ case net_snmp.ObjectType.Gauge:
+ default:
+ value = varbinds[i].value;
+ if(__DEBUG === true) netdata.debug(service.module.name + ': ' + service.name + ': found ' + service.module.name + ' value of OIDs ' + varbinds[i].oid + ", ObjectType " + net_snmp.ObjectType[varbinds[i].type] + " (" + netdata.stringify(varbinds[i].type) + "), typeof(" + typeof(varbinds[i].value) + "), in JSON: " + netdata.stringify(varbinds[i].value) + ", value = " + value.toString() + " (parsed as number)");
+ break;
+ }
ok++;
}
diff --git a/node.d/stiebeleltron.node.js b/node.d/stiebeleltron.node.js
new file mode 100644
index 000000000..b0eb0aba7
--- /dev/null
+++ b/node.d/stiebeleltron.node.js
@@ -0,0 +1,196 @@
+'use strict';
+
+// This program will connect to one Stiebel Eltron ISG for heatpump heating
+// to get the heat pump metrics.
+
+// example configuration in netdata/conf.d/node.d/stiebeleltron.conf.md
+
+var url = require("url");
+var http = require("http");
+var netdata = require("netdata");
+
+netdata.debug("loaded " + __filename + " plugin");
+
+var stiebeleltron = {
+ name: "Stiebel Eltron",
+ enable_autodetect: false,
+ update_every: 10,
+ base_priority: 60000,
+ charts: {},
+ pages: {},
+
+ createBasicDimension: function (id, name, multiplier, divisor) {
+ return {
+ id: id, // the unique id of the dimension
+ name: name, // the name of the dimension
+ algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm
+ multiplier: multiplier, // the multiplier
+ divisor: divisor, // the divisor
+ hidden: false // is hidden (boolean)
+ };
+ },
+
+ processResponse: function (service, html) {
+ if (html === null) return;
+
+ // add the service
+ service.commit();
+
+ var page = stiebeleltron.pages[service.name];
+ var categories = page.categories;
+ var categoriesCount = categories.length;
+ while (categoriesCount--) {
+ var context = {
+ html: html,
+ service: service,
+ category: categories[categoriesCount],
+ page: page,
+ chartDefinition: null,
+ dimension: null
+ };
+ stiebeleltron.processCategory(context);
+
+ }
+ },
+
+ processCategory: function (context) {
+ var charts = context.category.charts;
+ var chartCount = charts.length;
+ while (chartCount--) {
+ context.chartDefinition = charts[chartCount];
+ stiebeleltron.processChart(context);
+ }
+ },
+
+ processChart: function (context) {
+ var dimensions = context.chartDefinition.dimensions;
+ var dimensionCount = dimensions.length;
+ context.service.begin(stiebeleltron.getChartFromContext(context));
+
+ while (dimensionCount--) {
+ context.dimension = dimensions[dimensionCount];
+ stiebeleltron.processDimension(context);
+ }
+ context.service.end();
+ },
+
+ processDimension: function (context) {
+ var dimension = context.dimension;
+ var match = new RegExp(dimension.regex).exec(context.html);
+ if (match === null) return;
+ var value = match[1].replace(",", ".");
+ // most values have a single digit by default, which requires the values to be multiplied. can be overridden.
+ if (stiebeleltron.isDefined(dimension.digits)) {
+ value *= Math.pow(10, dimension.digits);
+ } else {
+ value *= 10;
+ }
+ context.service.set(stiebeleltron.getDimensionId(context), value);
+ },
+
+ getChartFromContext: function (context) {
+ var chartId = this.getChartId(context);
+ var chart = stiebeleltron.charts[chartId];
+ if (stiebeleltron.isDefined(chart)) return chart;
+
+ var chartDefinition = context.chartDefinition;
+ var service = context.service;
+ var dimensions = {};
+
+ var dimCount = chartDefinition.dimensions.length;
+ while (dimCount--) {
+ var dim = chartDefinition.dimensions[dimCount];
+ var multiplier = 1;
+ var divisor = 10;
+ if (stiebeleltron.isDefined(dim.digits)) divisor = Math.pow(10, Math.max(0, dim.digits));
+ if (stiebeleltron.isDefined(dim.multiplier)) multiplier = dim.multiplier;
+ if (stiebeleltron.isDefined(dim.divisor)) divisor = dim.divisor;
+ context.dimension = dim;
+ var dimId = this.getDimensionId(context);
+ dimensions[dimId] = this.createBasicDimension(dimId, dim.name, multiplier, divisor);
+ }
+
+ chart = {
+ id: chartId,
+ name: '',
+ title: chartDefinition.title,
+ units: chartDefinition.unit,
+ family: context.category.name,
+ context: 'stiebeleltron.' + context.page.id + "." + context.category.id,
+ type: chartDefinition.type,
+ priority: stiebeleltron.base_priority + chartDefinition.prio,// the priority relative to others in the same family
+ update_every: service.update_every, // the expected update frequency of the chart
+ dimensions: dimensions
+ };
+ chart = service.chart(chartId, chart);
+ stiebeleltron.charts[chartId] = chart;
+
+ return chart;
+ },
+
+ // module.serviceExecute()
+ // this function is called only from this module
+ // its purpose is to prepare the request and call
+ // netdata.serviceExecute()
+ serviceExecute: function (name, uri, update_every) {
+ netdata.debug(this.name + ': ' + name + ': url: ' + uri + ', update_every: ' + update_every);
+
+ var service = netdata.service({
+ name: name,
+ request: netdata.requestFromURL(uri),
+ update_every: update_every,
+ module: this
+ });
+ service.execute(this.processResponse);
+ },
+
+
+ configure: function (config) {
+ if (stiebeleltron.isUndefined(config.pages)) return 0;
+ var added = 0;
+ var pageCount = config.pages.length;
+ while (pageCount--) {
+ var page = config.pages[pageCount];
+ // some validation
+ if (stiebeleltron.isUndefined(page.categories) || page.categories.length < 1) {
+ netdata.error("Your Stiebel Eltron config is invalid. Disabling plugin.");
+ return 0;
+ }
+ if (stiebeleltron.isUndefined(page.update_every)) page.update_every = this.update_every;
+ this.pages[page.name] = page;
+ this.serviceExecute(page.name, page.url, page.update_every);
+ added++;
+ }
+ return added;
+ },
+
+ // module.update()
+ // this is called repeatedly to collect data, by calling
+ // netdata.serviceExecute()
+ update: function (service, callback) {
+ service.execute(function (serv, data) {
+ service.module.processResponse(serv, data);
+ callback();
+ });
+ },
+
+ getChartId: function (context) {
+ return "stiebeleltron_" + context.page.id +
+ "." + context.category.id +
+ "." + context.chartDefinition.id;
+ },
+
+ getDimensionId: function (context) {
+ return context.dimension.id;
+ },
+
+ isUndefined: function (value) {
+ return typeof value === 'undefined';
+ },
+
+ isDefined: function (value) {
+ return typeof value !== 'undefined';
+ }
+};
+
+module.exports = stiebeleltron;