123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 |
- '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');
- netdata.debug('loaded ' + __filename + ' plugin');
- var fronius = {
- name: "Fronius",
- enable_autodetect: false,
- update_every: 5,
- base_priority: 60000,
- charts: {},
- powerGridId: "p_grid",
- powerPvId: "p_pv",
- powerAccuId: "p_akku", // not my typo! Using the ID from the AP
- consumptionLoadId: "p_load",
- autonomyId: "rel_autonomy",
- consumptionSelfId: "rel_selfconsumption",
- energyTodayId: "e_day",
- energyYearId: "e_year",
- createBasicDimension: function (id, name, 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: 1, // the multiplier
- divisor: divisor, // the divisor
- hidden: false // is hidden (boolean)
- };
- },
- // Gets the site power chart. Will be created if not existing.
- getSitePowerChart: function (service, id) {
- 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);
- 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
- type: netdata.chartTypes.area, // the type of the chart
- 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
- };
- chart = service.chart(id, chart);
- fronius.charts[id] = chart;
- return chart;
- },
- // Gets the site consumption chart. Will be created if not existing.
- getSiteConsumptionChart: function (service, id) {
- var chart = fronius.charts[id];
- if (fronius.isDefined(chart)) return chart;
- var dim = {};
- 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
- 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
- dimensions: dim
- };
- chart = service.chart(id, chart);
- fronius.charts[id] = chart;
- return chart;
- },
- // Gets the site consumption chart. Will be created if not existing.
- getSiteAutonomyChart: function (service, id) {
- 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);
- 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
- 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
- dimensions: dim
- };
- chart = service.chart(id, chart);
- fronius.charts[id] = chart;
- return chart;
- },
- // Gets the site energy chart for today. Will be created if not existing.
- getSiteEnergyTodayChart: function (service, chartId) {
- var chart = fronius.charts[chartId];
- if (fronius.isDefined(chart)) return chart;
- var dim = {};
- 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
- dimensions: dim
- };
- chart = service.chart(chartId, chart);
- fronius.charts[chartId] = chart;
- return chart;
- },
- // Gets the site energy chart for today. Will be created if not existing.
- getSiteEnergyYearChart: function (service, chartId) {
- var chart = fronius.charts[chartId];
- if (fronius.isDefined(chart)) return chart;
- var dim = {};
- 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
- dimensions: dim
- };
- chart = service.chart(chartId, chart);
- fronius.charts[chartId] = chart;
- return chart;
- },
- // 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) {
- 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;
- }
- 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
- 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
- dimensions: dim
- };
- chart = service.chart(chartId, chart);
- fronius.charts[chartId] = chart;
- return chart;
- },
- processResponse: function (service, content) {
- if (content === null) return;
- var json = JSON.parse(content);
- if (!fronius.isResponseValid(json)) return;
- // add the service
- service.commit();
- var site = json.Body.Data.Site;
- // 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));
- 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();
- }
- },
- // 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);
- },
- // 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('http://' + uri),
- update_every: update_every,
- module: this
- });
- service.execute(this.processResponse);
- },
- configure: function (config) {
- if (fronius.isUndefined(config.servers)) return 0;
- var added = 0;
- var len = config.servers.length;
- while (len--) {
- var server = config.servers[len];
- if (fronius.isUndefined(server.update_every)) server.update_every = this.update_every;
- var url = server.hostname + server.api_path;
- this.serviceExecute(server.name, url, server.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();
- });
- },
- isUndefined: function (value) {
- return typeof value === 'undefined';
- },
- isDefined: function (value) {
- return typeof value !== 'undefined';
- }
- };
- module.exports = fronius;
|