From 0187bdcd826251b500a4cf8a12d71b8d50c54d6d Mon Sep 17 00:00:00 2001 From: guidosarducci Date: Mon, 13 Mar 2017 19:36:52 -0700 Subject: [PATCH 1/3] luci-app-statistics: add support for apcups plugin OpenWRT/LEDE support for APC UPSes is only partial: although the collectd apcups plugin is included, related lua/luci code is missing. These changes add the lua side and have been used for ~2 years, both on OpenWRT and LEDE. Reworked from patches submitted by James Klaas to the luci development list in 2015. Signed-off-by: Tony Ambardar (cherry picked from commit 808f2617931dcd6f84637e1bff3a737b9368917c) --- .../luci_statistics/luci_statistics.lua | 5 +- .../model/cbi/luci_statistics/apcups.lua | 28 +++++ .../statistics/rrdtool/definitions/apcups.lua | 101 ++++++++++++++++++ .../root/etc/config/luci_statistics | 5 + .../root/usr/bin/stat-genconfig | 6 ++ 5 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 applications/luci-app-statistics/luasrc/model/cbi/luci_statistics/apcups.lua create mode 100644 applications/luci-app-statistics/luasrc/statistics/rrdtool/definitions/apcups.lua diff --git a/applications/luci-app-statistics/luasrc/controller/luci_statistics/luci_statistics.lua b/applications/luci-app-statistics/luasrc/controller/luci_statistics/luci_statistics.lua index 443f20b0f4..ec26f02d0d 100644 --- a/applications/luci-app-statistics/luasrc/controller/luci_statistics/luci_statistics.lua +++ b/applications/luci-app-statistics/luasrc/controller/luci_statistics/luci_statistics.lua @@ -23,6 +23,7 @@ function index() s_general = _("General plugins"), s_network = _("Network plugins"), + apcups = _("APC UPS"), conntrack = _("Conntrack"), contextswitch = _("Context Switches"), cpu = _("Processor"), @@ -59,8 +60,8 @@ function index() -- our collectd menu local collectd_menu = { output = { "csv", "network", "rrdtool", "unixsock" }, - general = { "contextswitch", "cpu", "cpufreq", "df", "disk", "email", - "entropy", "exec", "irq", "load", "memory", + general = { "apcups", "contextswitch", "cpu", "cpufreq", "df", + "disk", "email", "entropy", "exec", "irq", "load", "memory", "nut", "processes", "sensors", "thermal", "uptime" }, network = { "conntrack", "dns", "interface", "iptables", "netlink", "olsrd", "openvpn", "ping", diff --git a/applications/luci-app-statistics/luasrc/model/cbi/luci_statistics/apcups.lua b/applications/luci-app-statistics/luasrc/model/cbi/luci_statistics/apcups.lua new file mode 100644 index 0000000000..49e28c7cfd --- /dev/null +++ b/applications/luci-app-statistics/luasrc/model/cbi/luci_statistics/apcups.lua @@ -0,0 +1,28 @@ +-- Copyright 2015 Jo-Philipp Wich +-- Licensed to the public under the Apache License 2.0. + +m = Map("luci_statistics", + translate("APCUPS Plugin Configuration"), + translate( + "The APCUPS plugin collects statistics about the APC UPS." + )) + +-- collectd_apcups config section +s = m:section( NamedSection, "collectd_apcups", "luci_statistics" ) + +-- collectd_apcups.enable +enable = s:option( Flag, "enable", translate("Enable this plugin") ) +enable.default = 0 + +-- collectd_apcups.host (Host) +host = s:option( Value, "Host", translate("Monitor host"), translate ("Add multiple hosts separated by space.")) +host.default = "localhost" +host:depends( "enable", 1 ) + +-- collectd_apcups.port (Port) +port = s:option( Value, "Port", translate("Port for apcupsd communication") ) +port.isinteger = true +port.default = 3551 +port:depends( "enable", 1 ) + +return m diff --git a/applications/luci-app-statistics/luasrc/statistics/rrdtool/definitions/apcups.lua b/applications/luci-app-statistics/luasrc/statistics/rrdtool/definitions/apcups.lua new file mode 100644 index 0000000000..04eee93051 --- /dev/null +++ b/applications/luci-app-statistics/luasrc/statistics/rrdtool/definitions/apcups.lua @@ -0,0 +1,101 @@ +-- Copyright 2015 Jo-Philipp Wich +-- Licensed to the public under the Apache License 2.0. + +module("luci.statistics.rrdtool.definitions.apcups",package.seeall) + +function rrdargs( graph, plugin, plugin_instance, dtype ) + + local voltages = { + title = "%H: Voltages on APC UPS ", + vlabel = "V", + number_format = "%5.1lfV", + data = { + instances = { + voltage = { "battery", "input", "output" } + }, + + options = { + voltage_output = { color = "00e000", title = "Output voltage", noarea=true, overlay=true }, + voltage_battery = { color = "0000ff", title = "Battery voltage", noarea=true, overlay=true }, + voltage_input = { color = "ffb000", title = "Input voltage", noarea=true, overlay=true } + } + } + } + + local percentload = { + title = "%H: Load on APC UPS ", + vlabel = "Percent", + y_min = "0", + y_max = "100", + number_format = "%5.1lf%%", + data = { + sources = { + percent_load = { "value" } + }, + instances = { + percent = "load" + }, + options = { + percent_load = { color = "00ff00", title = "Load level" } + } + } + } + + local charge_percent = { + title = "%H: Battery charge on APC UPS ", + vlabel = "Percent", + y_min = "0", + y_max = "100", + number_format = "%5.1lf%%", + data = { + types = { "charge" }, + options = { + charge = { color = "00ff0b", title = "Charge level" } + } + } + } + + local temperature = { + title = "%H: Battery temperature on APC UPS ", + vlabel = "\176C", + number_format = "%5.1lf\176C", + data = { + types = { "temperature" }, + options = { + temperature = { color = "ffb000", title = "Battery temperature" } } + } + } + + local timeleft = { + title = "%H: Time left on APC UPS ", + vlabel = "Minutes", + number_format = "%.1lfm", + data = { + sources = { + timeleft = { "value" } + }, + options = { + timeleft = { color = "0000ff", title = "Time left" } + } + } + } + + local frequency = { + title = "%H: Incoming line frequency on APC UPS ", + vlabel = "Hz", + number_format = "%5.0lfhz", + data = { + sources = { + frequency_input = { "value" } + }, + instances = { + frequency = "frequency" + }, + options = { + frequency_frequency = { color = "000fff", title = "Line frequency" } + } + } + } + + return { voltages, percentload, charge_percent, temperature, timeleft, frequency } +end diff --git a/applications/luci-app-statistics/root/etc/config/luci_statistics b/applications/luci-app-statistics/root/etc/config/luci_statistics index c081a8e724..8cc918e3db 100644 --- a/applications/luci-app-statistics/root/etc/config/luci_statistics +++ b/applications/luci-app-statistics/root/etc/config/luci_statistics @@ -49,6 +49,11 @@ config statistics 'collectd_unixsock' # input plugins +config statistics 'collectd_apcups' + option enable '0' + option Host 'localhost' + option Port '3551' + config statistics 'collectd_conntrack' option enable '0' diff --git a/applications/luci-app-statistics/root/usr/bin/stat-genconfig b/applications/luci-app-statistics/root/usr/bin/stat-genconfig index 41482ea463..d33b1a823b 100755 --- a/applications/luci-app-statistics/root/usr/bin/stat-genconfig +++ b/applications/luci-app-statistics/root/usr/bin/stat-genconfig @@ -255,6 +255,12 @@ end plugins = { + apcups = { + { "Host", "Port" }, + { }, + { } + }, + collectd = { { "BaseDir", "Include", "PIDFile", "PluginDir", "TypesDB", "Interval", "ReadThreads", "Hostname" }, { }, From 176f5fb94cd06acaa62f2f3174476f421a430fd8 Mon Sep 17 00:00:00 2001 From: bobmseagithub Date: Thu, 20 Jul 2017 11:47:57 -0700 Subject: [PATCH 2/3] luci-app-statistics: Voltage graphs - AC and DC The Voltage graph combines Battery, Input Voltage and Output Voltage. The Y-Axis scale masks changes in Input/Output voltages over time. This patch splits the graphs into 2 graphs. This makes it possible to see variations in AC Input/Output voltages. Signed-off-by: Bob Meizlik (cherry picked from commit 2145b7b33bbc4c142b243ac032e6e9c1c28ca835) --- .../statistics/rrdtool/definitions/apcups.lua | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/applications/luci-app-statistics/luasrc/statistics/rrdtool/definitions/apcups.lua b/applications/luci-app-statistics/luasrc/statistics/rrdtool/definitions/apcups.lua index 04eee93051..2a8aceec08 100644 --- a/applications/luci-app-statistics/luasrc/statistics/rrdtool/definitions/apcups.lua +++ b/applications/luci-app-statistics/luasrc/statistics/rrdtool/definitions/apcups.lua @@ -5,18 +5,34 @@ module("luci.statistics.rrdtool.definitions.apcups",package.seeall) function rrdargs( graph, plugin, plugin_instance, dtype ) - local voltages = { - title = "%H: Voltages on APC UPS ", - vlabel = "V", + local voltagesdc = { + title = "%H: Voltages on APC UPS - Battery", + vlabel = "Volts DC", + alt_autoscale = true, number_format = "%5.1lfV", data = { instances = { - voltage = { "battery", "input", "output" } + voltage = { "battery" } + }, + + options = { + voltage = { title = "Battery voltage", noarea=true } + } + } + } + + local voltages = { + title = "%H: Voltages on APC UPS - AC", + vlabel = "Volts AC", + alt_autoscale = true, + number_format = "%5.1lfV", + data = { + instances = { + voltage = { "input", "output" } }, options = { voltage_output = { color = "00e000", title = "Output voltage", noarea=true, overlay=true }, - voltage_battery = { color = "0000ff", title = "Battery voltage", noarea=true, overlay=true }, voltage_input = { color = "ffb000", title = "Input voltage", noarea=true, overlay=true } } } @@ -97,5 +113,5 @@ function rrdargs( graph, plugin, plugin_instance, dtype ) } } - return { voltages, percentload, charge_percent, temperature, timeleft, frequency } + return { voltages, voltagesdc, percentload, charge_percent, temperature, timeleft, frequency } end From 387b89e6f90499a0ffe47ea926de789f83210c28 Mon Sep 17 00:00:00 2001 From: guidosarducci Date: Sat, 3 Mar 2018 13:45:23 -0800 Subject: [PATCH 3/3] luci-app-statistics: only graph data supported by APC UPS Some graph definitions rely on data not supported across all APC UPSes. Due to recent upstream changes in collectd, the daemon no longer creates a NaN-filled .rrd file corresponding to any missing UPS data. Depending on the connected UPS, this may result in some "broken" graphs on the Luci Statistics page since rrdtool cannot find the expected .rrd file. Include the add_supported() function to determine the UPS data available at runtime and update any definitions of graphs to include only supported data. For example, the whole chart stack of AC input and output voltages will normally be "broken" if the UPS only measures AC input voltage. With these changes, the output voltage graph definition is stripped out, allowing the chart to render. Make consistent use of data types and instances in graph definitions. All definitions now use the same format with the 'instances' key. Unnecessary 'types' and 'sources' keys are removed. Fix the definition of 'line frequency' graph, based on upstream collectd apcups plugin code: type is 'frequency' but instance should be 'input'. This also includes some code and whitespace cleanup. Signed-off-by: Tony Ambardar (cherry picked from commit fa1f4c42a6e73483d8ed6284b177e5648f44a114) --- .../statistics/rrdtool/definitions/apcups.lua | 100 ++++++++++++++---- 1 file changed, 79 insertions(+), 21 deletions(-) diff --git a/applications/luci-app-statistics/luasrc/statistics/rrdtool/definitions/apcups.lua b/applications/luci-app-statistics/luasrc/statistics/rrdtool/definitions/apcups.lua index 2a8aceec08..9f7a51a868 100644 --- a/applications/luci-app-statistics/luasrc/statistics/rrdtool/definitions/apcups.lua +++ b/applications/luci-app-statistics/luasrc/statistics/rrdtool/definitions/apcups.lua @@ -3,25 +3,80 @@ module("luci.statistics.rrdtool.definitions.apcups",package.seeall) -function rrdargs( graph, plugin, plugin_instance, dtype ) +function rrdargs( graph, plugin, plugin_instance ) + + local lu = require("luci.util") + local rv = { } + + -- Types and instances supported by APC UPS + -- e.g. ups_types -> { 'timeleft', 'charge', 'percent', 'voltage' } + -- e.g. ups_inst['voltage'] -> { 'input', 'battery' } + + local ups_types = graph.tree:data_types( plugin, plugin_instance ) + + local ups_inst = {} + for _, t in ipairs(ups_types) do + ups_inst[t] = graph.tree:data_instances( plugin, plugin_instance, t ) + end + + + -- Check if hash table or array is empty or nil-filled + + local function empty( t ) + for _, v in pairs(t) do + if type(v) then return false end + end + return true + end + + + -- Append graph definition but only types/instances which are + -- supported and available to the plugin and UPS. + + local function add_supported( t, defs ) + local def_inst = defs['data']['instances'] + + if type(def_inst) == "table" then + for k, v in pairs( def_inst ) do + if lu.contains( ups_types, k) then + for j = #v, 1, -1 do + if not lu.contains( ups_inst[k], v[j] ) then + table.remove( v, j ) + end + end + if #v == 0 then + def_inst[k] = nil -- can't assign v: immutable + end + else + def_inst[k] = nil -- can't assign v: immutable + end + end + if empty(def_inst) then return end + end + table.insert( t, defs ) + end + + + -- Graph definitions for APC UPS measurements MUST use only 'instances': + -- e.g. instances = { voltage = { "input", "output" } } local voltagesdc = { title = "%H: Voltages on APC UPS - Battery", vlabel = "Volts DC", - alt_autoscale = true, + alt_autoscale = true, number_format = "%5.1lfV", data = { instances = { voltage = { "battery" } }, - - options = { + options = { voltage = { title = "Battery voltage", noarea=true } } } } - - local voltages = { + add_supported( rv, voltagesdc ) + + local voltagesac = { title = "%H: Voltages on APC UPS - AC", vlabel = "Volts AC", alt_autoscale = true, @@ -30,13 +85,13 @@ function rrdargs( graph, plugin, plugin_instance, dtype ) instances = { voltage = { "input", "output" } }, - options = { voltage_output = { color = "00e000", title = "Output voltage", noarea=true, overlay=true }, voltage_input = { color = "ffb000", title = "Input voltage", noarea=true, overlay=true } } } } + add_supported( rv, voltagesac ) local percentload = { title = "%H: Load on APC UPS ", @@ -45,17 +100,15 @@ function rrdargs( graph, plugin, plugin_instance, dtype ) y_max = "100", number_format = "%5.1lf%%", data = { - sources = { - percent_load = { "value" } - }, instances = { - percent = "load" + percent = { "load" } }, options = { percent_load = { color = "00ff00", title = "Load level" } } } } + add_supported( rv, percentload ) local charge_percent = { title = "%H: Battery charge on APC UPS ", @@ -64,54 +117,59 @@ function rrdargs( graph, plugin, plugin_instance, dtype ) y_max = "100", number_format = "%5.1lf%%", data = { - types = { "charge" }, + instances = { + charge = { "" } + }, options = { charge = { color = "00ff0b", title = "Charge level" } } } } + add_supported( rv, charge_percent ) local temperature = { title = "%H: Battery temperature on APC UPS ", vlabel = "\176C", number_format = "%5.1lf\176C", data = { - types = { "temperature" }, + instances = { + temperature = { "" } + }, options = { temperature = { color = "ffb000", title = "Battery temperature" } } } } + add_supported( rv, temperature ) local timeleft = { title = "%H: Time left on APC UPS ", vlabel = "Minutes", number_format = "%.1lfm", data = { - sources = { - timeleft = { "value" } + instances = { + timeleft = { "" } }, options = { timeleft = { color = "0000ff", title = "Time left" } } } } + add_supported( rv, timeleft ) local frequency = { title = "%H: Incoming line frequency on APC UPS ", vlabel = "Hz", number_format = "%5.0lfhz", data = { - sources = { - frequency_input = { "value" } - }, instances = { - frequency = "frequency" + frequency = { "input" } }, options = { - frequency_frequency = { color = "000fff", title = "Line frequency" } + frequency_input = { color = "000fff", title = "Line frequency" } } } } + add_supported( rv, frequency ) - return { voltages, voltagesdc, percentload, charge_percent, temperature, timeleft, frequency } + return rv end