X-Git-Url: https://git.sven.stormbind.net/?p=sven%2Fscripts.git;a=blobdiff_plain;f=weblogpro%2Fpvmon2opsgenie.sh;fp=weblogpro%2Fpvmon2opsgenie.sh;h=d1384b9084f04f01af9e6ab48570ef59bbe3ee00;hp=0000000000000000000000000000000000000000;hb=8efa31c1cd9df5d6428a36abcf7a96cf175020a8;hpb=de948ddb204597c6abd5b1403f83a9cbac71a8f0 diff --git a/weblogpro/pvmon2opsgenie.sh b/weblogpro/pvmon2opsgenie.sh new file mode 100755 index 0000000..d1384b9 --- /dev/null +++ b/weblogpro/pvmon2opsgenie.sh @@ -0,0 +1,185 @@ +#!/bin/sh +# Checks inverter state as repoted by a meteocontrol weblog +# device HTML interface, reports issues via Atlassian +# Opsgenie. Written with the intention to run via cron on +# a LTE Router with either OpenWRT or Teltonika RutOS. +# Requires curl other stock sh/cut/cat/test are enough. + +### path to the suntime / check for daylight script +checkdaylight="./suntime.lua" + +### opsgenie configuration +API_HOST="api.eu.opsgenie.com" +API_KEY="" + +# adjust meteocontrol default password and IPs +# meteocontrol devices must be added to the main loop as well +mc1="http://admin:ist02@192.168.1.2/html/de/onlineOverWr.html" +mc2="http://admin:ist02@192.168.1.3/html/de/onlineOverWr.html" + + +### check for daylight, otherwise exit early +${checkdaylight} || exit 3 + + +# createAlert +createAlert() { + local alias="${1}" + local message="${2}" + local description="${3}" + + if [ -z "${alias}" ]; then + echo "ERROR: Empty alert alias" + return + fi + + if [ -z "${message}" ]; then + echo "ERROR: Empty alert message" + return + fi + + curl -o /dev/null -s \ + -X POST https://${API_HOST}/v2/alerts \ + -H "Content-Type: application/json" \ + -H "Authorization: GenieKey ${API_KEY}" \ + -d \ + "{ + \"message\":\"${message}\", + \"alias\":\"${alias}\", + \"description\":\"${description}\" + }" +} + +# closeAlert +closeAlert() { + local alias=${1} + + if [ -z "${alias}" ]; then + echo "ERROR: Empty alert alias" + return + fi + + curl -o /dev/null -s \ + -X POST https://${API_HOST}/v2/alerts/${alias}/close?identifierType=alias \ + -H "Authorization: GenieKey ${API_KEY}" \ + -H "Content-Type: application/json" \ + -d '{}' + +} + +# parseMcLine +parseMcLine() { + local input="${@}" + + local wrleistung="$(echo ${input} | cut -d'>' -f 13 | cut -d'<' -f 1)" + local wradresse="$(echo ${input} | cut -d'>' -f 4 | cut -d'<' -f 1)" + local wrserial="$(echo ${input} | cut -d'>' -f 7 | cut -d'<' -f 1)" + + # known bad case e.g. during the night + if [ "${wrleistung}" = "---" ]; then + echo "No Power Value at WR${wradresse} Serial:${wrserial}" + return 3 + fi + + # known good case + if [ "${wrleistung}" -gt 0 ]; then + echo "OK" + return + fi + + echo "ERROR: WR${wradresse} ${wrleistung}W Serial:${wrserial}" + return 1 +} + +# parseMcOutput +parseMcOutput() { + local file="${1}" + local result="" + if ! [ -f "${file}" ]; then + echo "ERROR: Supplied input ${file} is not a regular file" + return + fi + + grep "cLink" "${file}" | while read line; do + result="$(parseMcLine \"${line}\")" + # good case + if [ "${result}" = "OK" ]; then + continue + fi + # return failure data + echo -n "${result} -- " + done +} + +# getMCstates +getMCstates() { + local outfile="${1}" + local url="${2}" + + if [ -z "${outfile}" ]; then + echo "ERROR: no meteocontrol tmp file provided" + exit 1 + fi + + if [ -z "${url}" ]; then + echo "ERROR: no meteocontrol URL provided" + exit 1 + fi + + # remove eventual remains of prior runs + rm -f "${outfile}" + + # ready to try to download the data from meteocontrol + if ! curl -s -o "${outfile}" "${url}"; then + echo "ERROR: could not download ${url} into ${outfile}" + exit 1 + fi + + # verify we have content to parse in our downloaded file + if ! grep -c -q cLink "${outfile}"; then + echo "ERROR: no matching cLink lines found in output file ${outfile}" + exit 1 + fi +} + +# checkAlertState +# return 0 on alert state change +# return 1 if nothing changed +checkAlertState() { + local statefile="${1}" + local newstatus="${2}" + local oldstatus="null" + + test -f "${statefile}" && oldstatus="$(cat ${statefile})" + if [ "${oldstatus}" = "${newstatus}" ]; then + return 1 + fi + + # update state file on state change + echo "${newstatus}" > "${statefile}" + return 0 +} + +### main loop +for dev in mc1 mc2; do + outfile="/tmp/${dev}.html" + statefile="/tmp/pvstate-${dev}" + url=$(eval echo \${$dev}) + + # download the html overview page from meteocontrol device + getMCstates "${outfile}" "${url}" + + # parse the overview page and collect failures + failures=$(parseMcOutput "${outfile}") + + # handle failures and alerting + if ! [ -z "${failures}" ]; then + checkAlertState "${statefile}" "FAILED" && \ + createAlert "${dev}" "PV ${dev}" "${failures}" + continue + fi + + # update alert state close alert on state change + checkAlertState "${statefile}" "OK" && \ + closeAlert "${dev}" +done