2 # Checks inverter state as repoted by a meteocontrol weblog
3 # device HTML interface, reports issues via Atlassian
4 # Opsgenie. Written with the intention to run via cron on
5 # a LTE Router with either OpenWRT or Teltonika RutOS.
6 # Requires curl other stock sh/cut/cat/test are enough.
8 ### path to the suntime / check for daylight script
9 checkdaylight="./suntime.lua"
11 ### opsgenie configuration
12 API_HOST="api.eu.opsgenie.com"
15 # adjust meteocontrol default password and IPs
16 # meteocontrol devices must be added to the main loop as well
17 mc1="http://admin:ist02@192.168.1.2/html/de/onlineOverWr.html"
18 mc2="http://admin:ist02@192.168.1.3/html/de/onlineOverWr.html"
21 ### check for daylight, otherwise exit early
22 ${checkdaylight} || exit 3
25 # createAlert <alias> <message> <priority> <description>
30 local description="${4}"
33 if [ -z "${alias}" ]; then
34 echo "ERROR: Empty alert alias"
38 if [ -z "${message}" ]; then
39 echo "ERROR: Empty alert message"
43 if [ -z "${priority}" ]; then
47 curl -o /dev/null -s \
48 -X POST https://${API_HOST}/v2/alerts \
49 -H "Content-Type: application/json" \
50 -H "Authorization: GenieKey ${API_KEY}" \
53 \"message\":\"${message}\",
54 \"alias\":\"${alias}\",
55 \"priority\":\"${priority}\",
56 \"description\":\"${description}\",
57 \"note\":\"Localtime ${date}\"
65 if [ -z "${alias}" ]; then
66 echo "ERROR: Empty alert alias"
70 curl -o /dev/null -s \
71 -X POST https://${API_HOST}/v2/alerts/${alias}/close?identifierType=alias \
72 -H "Authorization: GenieKey ${API_KEY}" \
73 -H "Content-Type: application/json" \
78 # parseMcLine <meteocontrol html page output line>
82 local wrleistung="$(echo ${input} | cut -d'>' -f 13 | cut -d'<' -f 1)"
83 local wradresse="$(echo ${input} | cut -d'>' -f 4 | cut -d'<' -f 1)"
84 local wrserial="$(echo ${input} | cut -d'>' -f 7 | cut -d'<' -f 1)"
86 # known bad case e.g. during the night
87 if [ "${wrleistung}" = "---" ]; then
88 echo "No Power Value at WR${wradresse} Serial:${wrserial}"
93 if [ "${wrleistung}" -gt 0 ]; then
98 echo "ERROR: WR${wradresse} ${wrleistung}W Serial:${wrserial}"
102 # parseMcOutput <meteocontrol status html output page>
106 if ! [ -f "${file}" ]; then
107 echo "ERROR: Supplied input ${file} is not a regular file"
111 grep "cLink" "${file}" | while read line; do
112 result="$(parseMcLine \"${line}\")"
114 if [ "${result}" = "OK" ]; then
117 # return failure data
118 echo -n "${result} -- "
122 # getMCstates <outfile> <status-url>
127 if [ -z "${outfile}" ]; then
128 echo "ERROR: no meteocontrol tmp file provided"
132 if [ -z "${url}" ]; then
133 echo "ERROR: no meteocontrol URL provided"
137 # remove eventual remains of prior runs
140 # ready to try to download the data from meteocontrol
141 if ! curl -s -o "${outfile}" "${url}"; then
142 echo "ERROR: could not download ${url} into ${outfile}"
146 # verify we have content to parse in our downloaded file
147 if ! grep -c -q cLink "${outfile}"; then
148 echo "ERROR: no matching cLink lines found in output file ${outfile}"
153 # checkAlertState <statefile> <new-status>
154 # return 0 on alert state change
155 # return 1 if nothing changed
157 local statefile="${1}"
158 local newstatus="${2}"
159 local oldstatus="null"
161 test -f "${statefile}" && oldstatus="$(cat ${statefile})"
162 if [ "${oldstatus}" = "${newstatus}" ]; then
166 # update state file on state change
167 echo "${newstatus}" > "${statefile}"
171 # calcPriority <outfile> <failures>
172 # returns an Opsgenie priority string
173 # If all devies fail return P1, otherwise stick with P3.
176 local failures="${2}"
178 local numWR="$(grep -c cLink ${outfile})"
179 # to be able to count with grep, we've to have our pattern ones per line
180 local numFailed=$(echo "${failures}"| tr ' ' '\n' | grep -c 'WR')
182 if [ "${numWR}" -eq "${numFailed}" ]; then
190 for dev in mc1 mc2; do
191 outfile="/tmp/${dev}.html"
192 statefile="/tmp/pvstate-${dev}"
193 url=$(eval echo \${$dev})
195 # download the html overview page from meteocontrol device
196 getMCstates "${outfile}" "${url}"
198 # parse the overview page and collect failures
199 failures=$(parseMcOutput "${outfile}")
201 # handle failures and alerting
202 if ! [ -z "${failures}" ]; then
203 priority=$(calcPriority "${outfile}" "${failures}")
204 checkAlertState "${statefile}" "FAILED" && \
205 createAlert "${dev}" "PV Ossendorf ${dev}" "${priority}" "${failures}"
209 # update alert state close alert on state change
210 checkAlertState "${statefile}" "OK" && \