]> git.sven.stormbind.net Git - sven/scripts.git/blob - home/pvmon2opsgenie.sh
Add daylight check based on suntime.lua script
[sven/scripts.git] / home / pvmon2opsgenie.sh
1 #!/bin/sh
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.
7
8 ### path to the suntime / check for daylight script
9 checkdaylight="./suntime.lua"
10
11 ### opsgenie configuration
12 API_HOST="api.eu.opsgenie.com"
13 API_KEY=""
14
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"
19
20
21 ### check for daylight, otherwise exit early
22 ${checkdaylight} || exit 3
23
24
25 # createAlert <alias> <message> <description>
26 createAlert() {
27     local alias="${1}"
28     local message="${2}"
29     local description="${3}"
30
31     if [ -z "${alias}" ]; then
32         echo "ERROR: Empty alert alias"
33         return
34     fi
35
36     if [ -z "${message}" ]; then
37         echo "ERROR: Empty alert message"
38         return
39     fi
40
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}" \
45         -d \
46         "{
47             \"message\":\"${message}\",
48             \"alias\":\"${alias}\",
49             \"description\":\"${description}\"
50         }"
51 }
52
53 # closeAlert <alias>
54 closeAlert() {
55     local alias=${1}
56
57     if [ -z "${alias}" ]; then
58         echo "ERROR: Empty alert alias"
59         return
60     fi
61
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" \
66         -d '{}'
67
68 }
69
70 # parseMcLine <meteocontrol html page output line>
71 parseMcLine() {
72     local input="${@}"
73
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)"
77
78     # known bad case e.g. during the night
79     if [ "${wrleistung}" = "---" ]; then
80         echo "No Power Value at WR${wradresse} Serial:${wrserial}"
81         return 3
82     fi
83
84     # known good case
85     if [ "${wrleistung}" -gt 0 ]; then
86         echo "OK"
87         return
88     fi
89     
90     echo "ERROR: WR${wradresse} ${wrleistung}W Serial:${wrserial}"
91     return 1
92 }
93
94 # parseMcOutput <meteocontrol status html output page>
95 parseMcOutput() {
96     local file="${1}"
97     local result=""
98     if ! [ -f "${file}" ]; then
99         echo "ERROR: Supplied input ${file} is not a regular file"
100         return
101     fi
102
103     grep "cLink" "${file}" | while read line; do
104         result="$(parseMcLine \"${line}\")"
105         # good case
106         if [ "${result}" = "OK" ]; then
107             continue
108         fi
109         # return failure data
110         echo -n "${result} -- "
111     done
112 }
113
114 # getMCstates <outfile> <status-url>
115 getMCstates() {
116     local outfile="${1}"
117     local url="${2}"
118
119     if [ -z "${outfile}" ]; then
120         echo "ERROR: no meteocontrol tmp file provided"
121         exit 1
122     fi
123
124     if [ -z "${url}" ]; then
125         echo "ERROR: no meteocontrol URL provided"
126         exit 1
127     fi
128
129     # remove eventual remains of prior runs
130     rm -f "${outfile}"
131
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}"
135         exit 1
136     fi
137
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}"
141         exit 1
142     fi
143 }
144
145 # checkAlertState <statefile> <new-status>
146 # return 0 on alert state change
147 # return 1 if nothing changed
148 checkAlertState() {
149     local statefile="${1}"
150     local newstatus="${2}"
151     local oldstatus="null"
152
153     test -f "${statefile}" && oldstatus="$(cat ${statefile})"
154     if [ "${oldstatus}" = "${newstatus}" ]; then
155         return 1
156     fi
157
158     # update state file on state change
159     echo "${newstatus}" > "${statefile}"
160     return 0
161 }
162
163 ### main loop
164 for dev in mc1 mc2; do
165     outfile="/tmp/${dev}.html"
166     statefile="/tmp/pvstate-${dev}"
167     url=$(eval echo \${$dev})
168
169     # download the html overview page from meteocontrol device
170     getMCstates "${outfile}" "${url}"
171
172     # parse the overview page and collect failures
173     failures=$(parseMcOutput "${outfile}")
174
175     # handle failures and alerting
176     if ! [ -z "${failures}" ]; then
177         checkAlertState "${statefile}" "FAILED" && \
178         createAlert "${dev}" "PV ${dev}" "${failures}"
179         continue
180     fi
181
182     # update alert state close alert on state change
183     checkAlertState "${statefile}" "OK" && \
184     closeAlert "${dev}"
185 done