apcupsd.chart.sh 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. # shellcheck shell=bash
  2. # no need for shebang - this file is loaded from charts.d.plugin
  3. # SPDX-License-Identifier: GPL-3.0-or-later
  4. # netdata
  5. # real-time performance and health monitoring, done right!
  6. # (C) 2016 Costa Tsaousis <costa@tsaousis.gr>
  7. #
  8. apcupsd_ip=
  9. apcupsd_port=
  10. declare -A apcupsd_sources=(
  11. ["local"]="127.0.0.1:3551"
  12. )
  13. # how frequently to collect UPS data
  14. apcupsd_update_every=10
  15. apcupsd_timeout=3
  16. # the priority of apcupsd related to other charts
  17. apcupsd_priority=90000
  18. apcupsd_get() {
  19. run -t $apcupsd_timeout apcaccess status "$1"
  20. }
  21. is_ups_alive() {
  22. local status
  23. status="$(apcupsd_get "$1" | sed -e 's/STATUS.*: //' -e 't' -e 'd')"
  24. case "$status" in
  25. "" | "COMMLOST" | "SHUTTING DOWN") return 1 ;;
  26. *) return 0 ;;
  27. esac
  28. }
  29. apcupsd_check() {
  30. # this should return:
  31. # - 0 to enable the chart
  32. # - 1 to disable the chart
  33. require_cmd apcaccess || return 1
  34. # backwards compatibility
  35. if [ "${apcupsd_ip}:${apcupsd_port}" != ":" ]; then
  36. apcupsd_sources["local"]="${apcupsd_ip}:${apcupsd_port}"
  37. fi
  38. local host working=0 failed=0
  39. for host in "${!apcupsd_sources[@]}"; do
  40. apcupsd_get "${apcupsd_sources[${host}]}" >/dev/null
  41. # shellcheck disable=2181
  42. if [ $? -ne 0 ]; then
  43. error "cannot get information for apcupsd server ${host} on ${apcupsd_sources[${host}]}."
  44. failed=$((failed + 1))
  45. else
  46. if ! is_ups_alive ${apcupsd_sources[${host}]}; then
  47. error "APC UPS ${host} on ${apcupsd_sources[${host}]} is not online."
  48. failed=$((failed + 1))
  49. else
  50. working=$((working + 1))
  51. fi
  52. fi
  53. done
  54. if [ ${working} -eq 0 ]; then
  55. error "No APC UPSes found available."
  56. return 1
  57. fi
  58. return 0
  59. }
  60. apcupsd_create() {
  61. local host
  62. for host in "${!apcupsd_sources[@]}"; do
  63. # create the charts
  64. cat <<EOF
  65. CHART apcupsd_${host}.charge '' "UPS Charge" "percentage" ups apcupsd.charge area $((apcupsd_priority + 2)) $apcupsd_update_every '' '' 'apcupsd'
  66. DIMENSION battery_charge charge absolute 1 100
  67. CHART apcupsd_${host}.battery_voltage '' "UPS Battery Voltage" "Volts" ups apcupsd.battery.voltage line $((apcupsd_priority + 4)) $apcupsd_update_every '' '' 'apcupsd'
  68. DIMENSION battery_voltage voltage absolute 1 100
  69. DIMENSION battery_voltage_nominal nominal absolute 1 100
  70. CHART apcupsd_${host}.input_voltage '' "UPS Input Voltage" "Volts" input apcupsd.input.voltage line $((apcupsd_priority + 5)) $apcupsd_update_every '' '' 'apcupsd'
  71. DIMENSION input_voltage voltage absolute 1 100
  72. DIMENSION input_voltage_min min absolute 1 100
  73. DIMENSION input_voltage_max max absolute 1 100
  74. CHART apcupsd_${host}.input_frequency '' "UPS Input Frequency" "Hz" input apcupsd.input.frequency line $((apcupsd_priority + 6)) $apcupsd_update_every '' '' 'apcupsd'
  75. DIMENSION input_frequency frequency absolute 1 100
  76. CHART apcupsd_${host}.output_voltage '' "UPS Output Voltage" "Volts" output apcupsd.output.voltage line $((apcupsd_priority + 7)) $apcupsd_update_every '' '' 'apcupsd'
  77. DIMENSION output_voltage voltage absolute 1 100
  78. DIMENSION output_voltage_nominal nominal absolute 1 100
  79. CHART apcupsd_${host}.load '' "UPS Load" "percentage" ups apcupsd.load area $((apcupsd_priority)) $apcupsd_update_every '' '' 'apcupsd'
  80. DIMENSION load load absolute 1 100
  81. CHART apcupsd_${host}.load_usage '' "UPS Load Usage" "Watts" ups apcupsd.load_usage area $((apcupsd_priority + 1)) $apcupsd_update_every '' '' 'apcupsd'
  82. DIMENSION load_usage load absolute 1 100
  83. CHART apcupsd_${host}.temp '' "UPS Temperature" "Celsius" ups apcupsd.temperature line $((apcupsd_priority + 8)) $apcupsd_update_every '' '' 'apcupsd'
  84. DIMENSION temp temp absolute 1 100
  85. CHART apcupsd_${host}.time '' "UPS Time Remaining" "Minutes" ups apcupsd.time area $((apcupsd_priority + 3)) $apcupsd_update_every '' '' 'apcupsd'
  86. DIMENSION time time absolute 1 100
  87. CHART apcupsd_${host}.online '' "UPS ONLINE flag" "boolean" ups apcupsd.online line $((apcupsd_priority + 9)) $apcupsd_update_every '' '' 'apcupsd'
  88. DIMENSION online online absolute 1 1
  89. CHART apcupsd_${host}.selftest '' "UPS Self-Test status" "status" ups apcupsd.selftest line $((apcupsd_priority + 10)) $apcupsd_update_every '' '' 'apcupsd'
  90. DIMENSION selftest_OK 'OK' absolute 1 1
  91. DIMENSION selftest_NO 'NO' absolute 1 1
  92. DIMENSION selftest_BT 'BT' absolute 1 1
  93. DIMENSION selftest_NG 'NG' absolute 1 1
  94. CHART apcupsd_${host}.status '' "UPS Status" "status" ups apcupsd.status line $((apcupsd_priority + 11)) $apcupsd_update_every '' '' 'apcupsd'
  95. DIMENSION status_ONLINE 'ONLINE' absolute 1 1
  96. DIMENSION status_ONBATT 'ONBATT' absolute 1 1
  97. DIMENSION status_OVERLOAD 'OVERLOAD' absolute 1 1
  98. DIMENSION status_LOWBATT 'LOWBATT' absolute 1 1
  99. DIMENSION status_REPLACEBATT 'REPLACEBATT' absolute 1 1
  100. DIMENSION status_NOBATT 'NOBATT' absolute 1 1
  101. DIMENSION status_SLAVE 'SLAVE' absolute 1 1
  102. DIMENSION status_SLAVEDOWN 'SLAVEDOWN' absolute 1 1
  103. DIMENSION status_COMMLOST 'COMMLOST' absolute 1 1
  104. DIMENSION status_CAL 'CAL' absolute 1 1
  105. DIMENSION status_TRIM 'TRIM' absolute 1 1
  106. DIMENSION status_BOOST 'BOOST' absolute 1 1
  107. DIMENSION status_SHUTTING_DOWN 'SHUTTING_DOWN' absolute 1 1
  108. EOF
  109. done
  110. return 0
  111. }
  112. apcupsd_update() {
  113. # the first argument to this function is the microseconds since last update
  114. # pass this parameter to the BEGIN statement (see below).
  115. # do all the work to collect / calculate the values
  116. # for each dimension
  117. # remember: KEEP IT SIMPLE AND SHORT
  118. local host working=0 failed=0
  119. for host in "${!apcupsd_sources[@]}"; do
  120. apcupsd_get "${apcupsd_sources[${host}]}" | awk "
  121. BEGIN {
  122. battery_charge = 0;
  123. battery_voltage = 0;
  124. battery_voltage_nominal = 0;
  125. input_voltage = 0;
  126. input_voltage_min = 0;
  127. input_voltage_max = 0;
  128. input_frequency = 0;
  129. output_voltage = 0;
  130. output_voltage_nominal = 0;
  131. load = 0;
  132. temp = 0;
  133. time = 0;
  134. nompower = 0;
  135. load_usage = 0;
  136. selftest_OK = 0;
  137. selftest_NO = 0;
  138. selftest_BT = 0;
  139. selftest_NG = 0;
  140. status_ONLINE = 0;
  141. status_CAL = 0;
  142. status_TRIM = 0;
  143. status_BOOST = 0;
  144. status_ONBATT = 0;
  145. status_OVERLOAD = 0;
  146. status_LOWBATT = 0;
  147. status_REPLACEBATT = 0;
  148. status_NOBATT = 0;
  149. status_SLAVE = 0;
  150. status_SLAVEDOWN = 0;
  151. status_COMMLOST = 0;
  152. status_SHUTTING_DOWN = 0;
  153. }
  154. /^BCHARGE.*/ { battery_charge = \$3 * 100 };
  155. /^BATTV.*/ { battery_voltage = \$3 * 100 };
  156. /^NOMBATTV.*/ { battery_voltage_nominal = \$3 * 100 };
  157. /^LINEV.*/ { input_voltage = \$3 * 100 };
  158. /^MINLINEV.*/ { input_voltage_min = \$3 * 100 };
  159. /^MAXLINEV.*/ { input_voltage_max = \$3 * 100 };
  160. /^LINEFREQ.*/ { input_frequency = \$3 * 100 };
  161. /^OUTPUTV.*/ { output_voltage = \$3 * 100 };
  162. /^NOMOUTV.*/ { output_voltage_nominal = \$3 * 100 };
  163. /^LOADPCT.*/ { load = \$3 * 100 };
  164. /^ITEMP.*/ { temp = \$3 * 100 };
  165. /^NOMPOWER.*/ { nompower = \$3 };
  166. /^TIMELEFT.*/ { time = \$3 * 100 };
  167. /^STATUS.*/ { online=(\$3 != \"COMMLOST\" && !(\$3 == \"SHUTTING\" && \$4 == \"DOWN\"))?1:0; };
  168. /^SELFTEST.*/ { selftest_OK = (\$3 == \"OK\") ? 1 : 0;
  169. selftest_NO = (\$3 == \"NO\") ? 1 : 0;
  170. selftest_BT = (\$3 == \"BT\") ? 1 : 0;
  171. selftest_NG = (\$3 == \"NG\") ? 1 : 0;
  172. };
  173. /^STATUS.*/ { status_ONLINE = (\$3 == \"ONLINE\") ? 1 : 0;
  174. status_CAL = (\$3 == \"CAL\") ? 1 : 0;
  175. status_TRIM = (\$3 == \"TRIM\") ? 1 : 0;
  176. status_BOOST = (\$3 == \"BOOST\") ? 1 : 0;
  177. status_ONBATT = (\$3 == \"ONBATT\") ? 1 : 0;
  178. status_OVERLOAD = (\$3 == \"OVERLOAD\") ? 1 : 0;
  179. status_LOWBATT = (\$3 == \"LOWBATT\") ? 1 : 0;
  180. status_REPLACEBATT = (\$3 == \"REPLACEBATT\") ? 1 : 0;
  181. status_NOBATT = (\$3 == \"NOBATT\") ? 1 : 0;
  182. status_SLAVE = (\$3 == \"SLAVE\") ? 1 : 0;
  183. status_SLAVEDOWN = (\$3 == \"SLAVEDOWN\") ? 1 : 0;
  184. status_COMMLOST = (\$3 == \"COMMLOST\") ? 1 : 0;
  185. status_SHUTTING_DOWN = (\$3 == \"SHUTTING\" && \$4 == \"DOWN\") ? 1 : 0;
  186. };
  187. END {
  188. { load_usage = nompower * load / 100 };
  189. print \"BEGIN apcupsd_${host}.online $1\";
  190. print \"SET online = \" online;
  191. print \"END\"
  192. if (online == 1) {
  193. print \"BEGIN apcupsd_${host}.charge $1\";
  194. print \"SET battery_charge = \" battery_charge;
  195. print \"END\"
  196. print \"BEGIN apcupsd_${host}.battery_voltage $1\";
  197. print \"SET battery_voltage = \" battery_voltage;
  198. print \"SET battery_voltage_nominal = \" battery_voltage_nominal;
  199. print \"END\"
  200. print \"BEGIN apcupsd_${host}.input_voltage $1\";
  201. print \"SET input_voltage = \" input_voltage;
  202. print \"SET input_voltage_min = \" input_voltage_min;
  203. print \"SET input_voltage_max = \" input_voltage_max;
  204. print \"END\"
  205. print \"BEGIN apcupsd_${host}.input_frequency $1\";
  206. print \"SET input_frequency = \" input_frequency;
  207. print \"END\"
  208. print \"BEGIN apcupsd_${host}.output_voltage $1\";
  209. print \"SET output_voltage = \" output_voltage;
  210. print \"SET output_voltage_nominal = \" output_voltage_nominal;
  211. print \"END\"
  212. print \"BEGIN apcupsd_${host}.load $1\";
  213. print \"SET load = \" load;
  214. print \"END\"
  215. print \"BEGIN apcupsd_${host}.load_usage $1\";
  216. print \"SET load_usage = \" load_usage;
  217. print \"END\"
  218. print \"BEGIN apcupsd_${host}.temp $1\";
  219. print \"SET temp = \" temp;
  220. print \"END\"
  221. print \"BEGIN apcupsd_${host}.time $1\";
  222. print \"SET time = \" time;
  223. print \"END\"
  224. print \"BEGIN apcupsd_${host}.selftest $1\";
  225. print \"SET selftest_OK = \" selftest_OK;
  226. print \"SET selftest_NO = \" selftest_NO;
  227. print \"SET selftest_BT = \" selftest_BT;
  228. print \"SET selftest_NG = \" selftest_NG;
  229. print \"END\"
  230. print \"BEGIN apcupsd_${host}.status $1\";
  231. print \"SET status_ONLINE = \" status_ONLINE;
  232. print \"SET status_ONBATT = \" status_ONBATT;
  233. print \"SET status_OVERLOAD = \" status_OVERLOAD;
  234. print \"SET status_LOWBATT = \" status_LOWBATT;
  235. print \"SET status_REPLACEBATT = \" status_REPLACEBATT;
  236. print \"SET status_NOBATT = \" status_NOBATT;
  237. print \"SET status_SLAVE = \" status_SLAVE;
  238. print \"SET status_SLAVEDOWN = \" status_SLAVEDOWN;
  239. print \"SET status_COMMLOST = \" status_COMMLOST;
  240. print \"SET status_CAL = \" status_CAL;
  241. print \"SET status_TRIM = \" status_TRIM;
  242. print \"SET status_BOOST = \" status_BOOST;
  243. print \"SET status_SHUTTING_DOWN = \" status_SHUTTING_DOWN;
  244. print \"END\";
  245. }
  246. }"
  247. # shellcheck disable=SC2181
  248. if [ $? -ne 0 ]; then
  249. failed=$((failed + 1))
  250. error "failed to get values for APC UPS ${host} on ${apcupsd_sources[${host}]}" && return 1
  251. else
  252. working=$((working + 1))
  253. fi
  254. done
  255. [ $working -eq 0 ] && error "failed to get values from all APC UPSes" && return 1
  256. return 0
  257. }