'use strict'; // SPDX-License-Identifier: GPL-3.0-or-later // This program will connect to one or more SMA Sunny Webboxes // to get the Solar Power Generated (current, today, total). // example configuration in /etc/netdata/node.d/sma_webbox.conf /* { "enable_autodetect": false, "update_every": 5, "servers": [ { "name": "plant1", "hostname": "10.0.1.1", "update_every": 10 }, { "name": "plant2", "hostname": "10.0.2.1", "update_every": 15 } ] } */ require('url'); require('http'); var netdata = require('netdata'); if(netdata.options.DEBUG === true) netdata.debug('loaded ' + __filename + ' plugin'); var webbox = { name: __filename, enable_autodetect: true, update_every: 1, base_priority: 60000, charts: {}, processResponse: function(service, data) { if(data !== null) { var r = JSON.parse(data); var d = { 'GriPwr': { unit: null, value: null }, 'GriEgyTdy': { unit: null, value: null }, 'GriEgyTot': { unit: null, value: null } }; // parse the webbox response // and put it in our d object var found = 0; var len = r.result.overview.length; while(len--) { var e = r.result.overview[len]; if(typeof(d[e.meta]) !== 'undefined') { found++; d[e.meta].value = e.value; d[e.meta].unit = e.unit; } } // add the service if(found > 0 && service.added !== true) service.commit(); // Grid Current Power Chart if(d['GriPwr'].value !== null) { const id = 'smawebbox_' + service.name + '.current'; let chart = webbox.charts[id]; if(typeof chart === 'undefined') { chart = { id: id, // the unique id of the chart name: '', // the unique name of the chart title: service.name + ' Current Grid Power', // the title of the chart units: d['GriPwr'].unit, // the units of the chart dimensions family: 'now', // the family of the chart context: 'smawebbox.grid_power', // the context of the chart type: netdata.chartTypes.area, // the type of the chart priority: webbox.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: { 'GriPwr': { id: 'GriPwr', // the unique id of the dimension name: 'power', // the name of the dimension algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm multiplier: 1, // the multiplier divisor: 1, // the divisor hidden: false // is hidden (boolean) } } }; chart = service.chart(id, chart); webbox.charts[id] = chart; } service.begin(chart); service.set('GriPwr', Math.round(d['GriPwr'].value)); service.end(); } if(d['GriEgyTdy'].value !== null) { const id = 'smawebbox_' + service.name + '.today'; let chart = webbox.charts[id]; if(typeof chart === 'undefined') { chart = { id: id, // the unique id of the chart name: '', // the unique name of the chart title: service.name + ' Today Grid Power', // the title of the chart units: d['GriEgyTdy'].unit, // the units of the chart dimensions family: 'today', // the family of the chart context: 'smawebbox.grid_power_today', // the context of the chart type: netdata.chartTypes.area, // the type of the chart priority: webbox.base_priority + 2, // the priority relative to others in the same family update_every: service.update_every, // the expected update frequency of the chart dimensions: { 'GriEgyTdy': { id: 'GriEgyTdy', // the unique id of the dimension name: 'power', // the name of the dimension algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm multiplier: 1, // the multiplier divisor: 1000, // the divisor hidden: false // is hidden (boolean) } } }; chart = service.chart(id, chart); webbox.charts[id] = chart; } service.begin(chart); service.set('GriEgyTdy', Math.round(d['GriEgyTdy'].value * 1000)); service.end(); } if(d['GriEgyTot'].value !== null) { const id = 'smawebbox_' + service.name + '.total'; let chart = webbox.charts[id]; if(typeof chart === 'undefined') { chart = { id: id, // the unique id of the chart name: '', // the unique name of the chart title: service.name + ' Total Grid Power', // the title of the chart units: d['GriEgyTot'].unit, // the units of the chart dimensions family: 'total', // the family of the chart context: 'smawebbox.grid_power_total', // the context of the chart type: netdata.chartTypes.area, // the type of the chart priority: webbox.base_priority + 3, // the priority relative to others in the same family update_every: service.update_every, // the expected update frequency of the chart dimensions: { 'GriEgyTot': { id: 'GriEgyTot', // the unique id of the dimension name: 'power', // the name of the dimension algorithm: netdata.chartAlgorithms.absolute,// the id of the netdata algorithm multiplier: 1, // the multiplier divisor: 1000, // the divisor hidden: false // is hidden (boolean) } } }; chart = service.chart(id, chart); webbox.charts[id] = chart; } service.begin(chart); service.set('GriEgyTot', Math.round(d['GriEgyTot'].value * 1000)); service.end(); } } }, // module.serviceExecute() // this function is called only from this module // its purpose is to prepare the request and call // netdata.serviceExecute() serviceExecute: function(name, hostname, update_every) { if(netdata.options.DEBUG === true) netdata.debug(this.name + ': ' + name + ': hostname: ' + hostname + ', update_every: ' + update_every); var service = netdata.service({ name: name, request: netdata.requestFromURL('http://' + hostname + '/rpc'), update_every: update_every, module: this }); service.postData = 'RPC={"proc":"GetPlantOverview","format":"JSON","version":"1.0","id":"1"}'; service.request.method = 'POST'; service.request.headers['Content-Length'] = service.postData.length; service.execute(this.processResponse); }, configure: function(config) { var added = 0; if(typeof(config.servers) !== 'undefined') { var len = config.servers.length; while(len--) { if(typeof config.servers[len].update_every === 'undefined') config.servers[len].update_every = this.update_every; if(config.servers[len].update_every < 5) config.servers[len].update_every = 5; this.serviceExecute(config.servers[len].name, config.servers[len].hostname, config.servers[len].update_every); added++; } } return added; }, // module.update() // this is called repeatidly to collect data, by calling // netdata.serviceExecute() update: function(service, callback) { service.execute(function(serv, data) { service.module.processResponse(serv, data); callback(); }); }, }; module.exports = webbox;