1
|
#! /usr/bin/env python3
|
2
|
import os
|
3
|
import re
|
4
|
|
5
|
import requests
|
6
|
from requests.auth import HTTPDigestAuth
|
7
|
|
8
|
|
9
|
def scaled_value(value, scale, db_unit):
|
10
|
max_value = 65535
|
11
|
|
12
|
if scale == 1: # Percentage
|
13
|
calculated_value = value / max_value * 100
|
14
|
return calculated_value, "{}%".format(round(calculated_value))
|
15
|
elif scale == 2: # dB
|
16
|
calculated_value = value * 0.001
|
17
|
return calculated_value, "{} {}".format(round(calculated_value, 1), db_unit)
|
18
|
|
19
|
|
20
|
CHECK_MK_STATE_OK = 0
|
21
|
CHECK_MK_STATE_WARNING = 1
|
22
|
CHECK_MK_STATE_CRITICAL = 2
|
23
|
CHECK_MK_STATE_UNKNOWN = 3
|
24
|
|
25
|
username = os.getenv("TVHEADEND_API_USERNAME")
|
26
|
password = os.getenv("TVHEADEND_API_PASSWORD")
|
27
|
timeout = os.getenv("TVHEADEND_API_TIMEOUT", 5)
|
28
|
|
29
|
check_name = os.getenv("TVHEADEND_CHECK_NAME", "Tvheadend_Input_{tuner}")
|
30
|
|
31
|
continuity_errors_critical = int(os.getenv("TVHEADEND_CHECK_CONTINUITY_ERRORS_CRITICAL", 100))
|
32
|
continuity_errors_warning = int(os.getenv("TVHEADEND_CHECK_CONTINUITY_ERRORS_WARNING", 50))
|
33
|
|
34
|
snr_signal_strength_percentage_critical = int(os.getenv("TVHEADEND_CHECK_SNR_SIGNAL_STRENGTH_PERCENTAGE_CRITICAL", 33))
|
35
|
snr_signal_strength_percentage_warning = int(os.getenv("TVHEADEND_CHECK_SNR_SIGNAL_STRENGTH_PERCENTAGE_WARNING", 66))
|
36
|
|
37
|
inputs_response = requests.get("http://localhost:9981/api/status/inputs", auth=HTTPDigestAuth(username, password), timeout=timeout)
|
38
|
|
39
|
inputs_response.raise_for_status()
|
40
|
|
41
|
inputs = inputs_response.json()["entries"]
|
42
|
|
43
|
for input_object in inputs:
|
44
|
tuner_name = re.sub(r"\W+", "_", input_object["input"])
|
45
|
|
46
|
snr = scaled_value(input_object["snr"], input_object["snr_scale"], "dB")
|
47
|
signal_strength = scaled_value(input_object["signal"], input_object["signal_scale"], "dBm")
|
48
|
bandwidth = input_object["bps"]
|
49
|
continuity_errors = input_object["cc"]
|
50
|
ec_bit = input_object["ec_bit"]
|
51
|
tc_bit = input_object["tc_bit"]
|
52
|
unc = input_object["unc"]
|
53
|
transport_errors = input_object["te"]
|
54
|
|
55
|
state = CHECK_MK_STATE_OK
|
56
|
performance_data = {}
|
57
|
details = []
|
58
|
|
59
|
if tc_bit == 0:
|
60
|
ber = input_object["ber"]
|
61
|
else:
|
62
|
ber = ec_bit / tc_bit
|
63
|
|
64
|
if ber != 0:
|
65
|
state = max(state, CHECK_MK_STATE_CRITICAL)
|
66
|
details.append("BER = {} (!!)".format(ber))
|
67
|
|
68
|
performance_data["ber"] = (ber, 1, 1)
|
69
|
|
70
|
if unc != 0:
|
71
|
# TODO: Uncorrected Blocks will always increase while scanning EPG... every day
|
72
|
# state = max(state, CHECK_MK_STATE_CRITICAL)
|
73
|
state = max(state, CHECK_MK_STATE_WARNING)
|
74
|
details.append("Uncorrected Blocks = {} (!!)".format(unc))
|
75
|
|
76
|
performance_data["unc"] = (unc, 1, 1)
|
77
|
|
78
|
if transport_errors != 0:
|
79
|
state = max(state, CHECK_MK_STATE_CRITICAL)
|
80
|
details.append("Transport Errors = {} (!!)".format(transport_errors))
|
81
|
|
82
|
performance_data["transport_errors"] = (transport_errors, 1, 1)
|
83
|
|
84
|
performance_data["bandwidth"] = bandwidth
|
85
|
|
86
|
if bandwidth:
|
87
|
details.append("Bandwidth = {} kb/s".format(bandwidth / 1024))
|
88
|
|
89
|
if continuity_errors > continuity_errors_critical:
|
90
|
# TODO: Continuity Errors will always increase on switching mux and while scanning EPG... every day
|
91
|
# state = max(state, CHECK_MK_STATE_CRITICAL)
|
92
|
state = max(state, CHECK_MK_STATE_WARNING)
|
93
|
details.append("Continuity Errors = {} (!!)".format(continuity_errors))
|
94
|
elif continuity_errors > continuity_errors_warning:
|
95
|
state = max(state, CHECK_MK_STATE_WARNING)
|
96
|
details.append("Continuity Errors = {} (!)".format(continuity_errors))
|
97
|
|
98
|
performance_data["continuity_errors"] = (continuity_errors, continuity_errors_warning, continuity_errors_critical)
|
99
|
|
100
|
if snr is None:
|
101
|
snr_value = 0
|
102
|
snr_string = "N/A"
|
103
|
performance_data["snr"] = 0
|
104
|
else:
|
105
|
snr_value, snr_string = snr
|
106
|
|
107
|
# State calculation currently only possible if SNR is in percent (scale = 1)
|
108
|
if input_object["snr_scale"] == 1:
|
109
|
performance_data["snr"] = (snr_value, snr_signal_strength_percentage_warning, snr_signal_strength_percentage_critical)
|
110
|
# TODO: SNR is currently only at ~24% which is bad but doesn't seem to have any impact right now
|
111
|
# if snr_value <= snr_signal_strength_percentage_critical:
|
112
|
# state = max(state, CHECK_MK_STATE_CRITICAL)
|
113
|
# snr_string = "{} (!!)".format(snr_string)
|
114
|
# elif snr_value <= snr_signal_strength_percentage_warning:
|
115
|
# state = max(state, CHECK_MK_STATE_WARNING)
|
116
|
# snr_string = "{} (!)".format(snr_string)
|
117
|
else:
|
118
|
performance_data["snr"] = snr_value
|
119
|
|
120
|
details.append("SNR = {}".format(snr_string))
|
121
|
|
122
|
if signal_strength is None:
|
123
|
signal_strength_value = 0
|
124
|
signal_strength_string = "N/A"
|
125
|
performance_data["signal_strength"] = 0
|
126
|
else:
|
127
|
signal_strength_value, signal_strength_string = signal_strength
|
128
|
|
129
|
# State calculation currently only possible if signal strength is in percent (scale = 1)
|
130
|
if input_object["signal_scale"] == 1:
|
131
|
performance_data["signal_strength"] = (signal_strength_value, snr_signal_strength_percentage_warning, snr_signal_strength_percentage_critical)
|
132
|
if signal_strength_value <= snr_signal_strength_percentage_critical:
|
133
|
state = max(state, CHECK_MK_STATE_CRITICAL)
|
134
|
signal_strength_string = "{} (!!)".format(signal_strength_string)
|
135
|
elif signal_strength_value <= snr_signal_strength_percentage_warning:
|
136
|
state = max(state, CHECK_MK_STATE_WARNING)
|
137
|
signal_strength_string = "{} (!)".format(signal_strength_string)
|
138
|
else:
|
139
|
performance_data["signal_strength"] = signal_strength_value
|
140
|
|
141
|
details.append("Signal Strength = {}".format(signal_strength_string))
|
142
|
|
143
|
if "stream" in input_object:
|
144
|
active_stream = input_object["stream"]
|
145
|
else:
|
146
|
active_stream = "Stream inactive"
|
147
|
|
148
|
performance_data_string = []
|
149
|
|
150
|
for key, value in performance_data.items():
|
151
|
if type(value) == tuple:
|
152
|
performance_data_string.append("{}={}".format(key, ";".join(map(str, value))))
|
153
|
else:
|
154
|
performance_data_string.append("{}={}".format(key, value))
|
155
|
|
156
|
if len(details):
|
157
|
details_string = "({})".format(", ".join(details))
|
158
|
else:
|
159
|
details_string = ""
|
160
|
|
161
|
print("{state} {check_name} {performance_data} {active_stream} {details}".format(state=state, check_name=check_name.format(tuner=tuner_name), performance_data="|".join(performance_data_string), active_stream=active_stream, details=details_string))
|