luci-app-statistics: only graph data supported by APC UPS 1653/head
authorguidosarducci <guidosarducci@users.noreply.github.com>
Sat, 3 Mar 2018 21:45:23 +0000 (13:45 -0800)
committerguidosarducci <guidosarducci@users.noreply.github.com>
Sat, 3 Mar 2018 21:54:55 +0000 (13:54 -0800)
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 <itugrok@yahoo.com>
applications/luci-app-statistics/luasrc/statistics/rrdtool/definitions/apcups.lua

index 2a8aceec0863dd09548174793d26a53099dc2801..9f7a51a868c14104fb23d268fd14249515242cf7 100644 (file)
@@ -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