]> git.sven.stormbind.net Git - sven/scripts.git/commitdiff
Monitoring script for inverter via meteocontrol weblog pro units
authorSven Hoexter <sven@stormbind.net>
Sun, 23 Jan 2022 14:20:04 +0000 (15:20 +0100)
committerSven Hoexter <sven@stormbind.net>
Sun, 23 Jan 2022 14:20:04 +0000 (15:20 +0100)
Implements alerting via Opsgenie

home/pvmon2opsgenie.sh [new file with mode: 0755]

diff --git a/home/pvmon2opsgenie.sh b/home/pvmon2opsgenie.sh
new file mode 100755 (executable)
index 0000000..34a5c5a
--- /dev/null
@@ -0,0 +1,177 @@
+#!/bin/sh
+# Checks inverter state as repoted by a metecontrol 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 for the Opsgenie part, otherwise
+# sh/cut/cat/wget/test are enough.
+
+# createAlert <alias> <message> <description>
+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 <alias>
+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 <meteocontrol html page output line>
+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 <meteocontrol status html output page>
+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 <outfile> <status-url>
+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 ! wget -q -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 <statefile> <new-status>
+# 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 configuration
+API_HOST="api.eu.opsgenie.com"
+API_KEY=""
+
+# adjust meteocontrol default password and IPs
+mc1="http://admin:ist02@192.168.1.2:80/html/de/onlineOverWr.html"
+mc2="http://admin:ist02@192.168.1.3:80/html/de/onlineOverWr.html"
+
+### 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