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> <description>
29 local description="${3}"
31 if [ -z "${alias}" ]; then
32 echo "ERROR: Empty alert alias"
36 if [ -z "${message}" ]; then
37 echo "ERROR: Empty alert message"
41 curl -o /dev/null -s \
42 -X POST https://${API_HOST}/v2/alerts \
43 -H "Content-Type: application/json" \
44 -H "Authorization: GenieKey ${API_KEY}" \
47 \"message\":\"${message}\",
48 \"alias\":\"${alias}\",
49 \"description\":\"${description}\"
57 if [ -z "${alias}" ]; then
58 echo "ERROR: Empty alert alias"
62 curl -o /dev/null -s \
63 -X POST https://${API_HOST}/v2/alerts/${alias}/close?identifierType=alias \
64 -H "Authorization: GenieKey ${API_KEY}" \
65 -H "Content-Type: application/json" \
70 # parseMcLine <meteocontrol html page output line>
74 local wrleistung="$(echo ${input} | cut -d'>' -f 13 | cut -d'<' -f 1)"
75 local wradresse="$(echo ${input} | cut -d'>' -f 4 | cut -d'<' -f 1)"
76 local wrserial="$(echo ${input} | cut -d'>' -f 7 | cut -d'<' -f 1)"
78 # known bad case e.g. during the night
79 if [ "${wrleistung}" = "---" ]; then
80 echo "No Power Value at WR${wradresse} Serial:${wrserial}"
85 if [ "${wrleistung}" -gt 0 ]; then
90 echo "ERROR: WR${wradresse} ${wrleistung}W Serial:${wrserial}"
94 # parseMcOutput <meteocontrol status html output page>
98 if ! [ -f "${file}" ]; then
99 echo "ERROR: Supplied input ${file} is not a regular file"
103 grep "cLink" "${file}" | while read line; do
104 result="$(parseMcLine \"${line}\")"
106 if [ "${result}" = "OK" ]; then
109 # return failure data
110 echo -n "${result} -- "
114 # getMCstates <outfile> <status-url>
119 if [ -z "${outfile}" ]; then
120 echo "ERROR: no meteocontrol tmp file provided"
124 if [ -z "${url}" ]; then
125 echo "ERROR: no meteocontrol URL provided"
129 # remove eventual remains of prior runs
132 # ready to try to download the data from meteocontrol
133 if ! curl -s -o "${outfile}" "${url}"; then
134 echo "ERROR: could not download ${url} into ${outfile}"
138 # verify we have content to parse in our downloaded file
139 if ! grep -c -q cLink "${outfile}"; then
140 echo "ERROR: no matching cLink lines found in output file ${outfile}"
145 # checkAlertState <statefile> <new-status>
146 # return 0 on alert state change
147 # return 1 if nothing changed
149 local statefile="${1}"
150 local newstatus="${2}"
151 local oldstatus="null"
153 test -f "${statefile}" && oldstatus="$(cat ${statefile})"
154 if [ "${oldstatus}" = "${newstatus}" ]; then
158 # update state file on state change
159 echo "${newstatus}" > "${statefile}"
164 for dev in mc1 mc2; do
165 outfile="/tmp/${dev}.html"
166 statefile="/tmp/pvstate-${dev}"
167 url=$(eval echo \${$dev})
169 # download the html overview page from meteocontrol device
170 getMCstates "${outfile}" "${url}"
172 # parse the overview page and collect failures
173 failures=$(parseMcOutput "${outfile}")
175 # handle failures and alerting
176 if ! [ -z "${failures}" ]; then
177 checkAlertState "${statefile}" "FAILED" && \
178 createAlert "${dev}" "PV ${dev}" "${failures}"
182 # update alert state close alert on state change
183 checkAlertState "${statefile}" "OK" && \