add plugin for Technicolor TC8715D cable modem stats
This commit is contained in:
parent
1fc177ce9a
commit
6abc523a58
|
@ -0,0 +1,233 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
=pod
|
||||
|
||||
=encoding utf8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
technicolor_tc8715d - Munin plugin for graphing statistics from
|
||||
Technicolor TC8715D cable modems.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
The following values are graphed:
|
||||
|
||||
=over
|
||||
|
||||
=item *
|
||||
|
||||
upstream and downstream power levels
|
||||
|
||||
=item *
|
||||
|
||||
downstream signal to noise ratio
|
||||
|
||||
=item *
|
||||
|
||||
downstream signal statistics (codeword counts)
|
||||
|
||||
=back
|
||||
|
||||
=head1 USAGE
|
||||
|
||||
Install as you would with any Munin plugin. No configuration is
|
||||
needed. Requires the multigraph and dirtyconfig capabilities available
|
||||
in munin 2.0 and newer.
|
||||
|
||||
=head1 NOTES
|
||||
|
||||
Developed and tested with Python 3.7.3, Technicolor TC8715D cable
|
||||
modem hardware revision 1.1, software image name
|
||||
TC8715D-01.EF.04.38.00-180405-S-FF9-D.img, advanced services
|
||||
2.6.30-1.0.11mp1-g24a0ad5-dirty.
|
||||
|
||||
=head1 DEVELOPMENT
|
||||
|
||||
The latest version of this plugin can be found in the munin contrib
|
||||
repository at https://github.com/munin-monitoring/contrib. Issues
|
||||
with this plugin may be reported there. Patches accepted through the
|
||||
normal github process of forking the repository and submitting a
|
||||
pull request with your commits.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Copyright © 2019 Kenyon Ralph <kenyon@kenyonralph.com>
|
||||
|
||||
=head1 LICENSE
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
=cut
|
||||
|
||||
"""
|
||||
|
||||
import html.parser
|
||||
import urllib.request
|
||||
import sys
|
||||
|
||||
|
||||
class TechnicolorHTMLParser(html.parser.HTMLParser):
|
||||
def __init__(self):
|
||||
html.parser.HTMLParser.__init__(self)
|
||||
self.signaldatapage = list()
|
||||
|
||||
# Number of downstream channels.
|
||||
self.downstream_channels = 0
|
||||
|
||||
# Number of upstream channels.
|
||||
self.upstream_channels = 0
|
||||
|
||||
self.downstream_SNRs = list()
|
||||
self.downstream_powers = list()
|
||||
self.upstream_powers = list()
|
||||
self.unerrored_codewords = list()
|
||||
self.correctable_codewords = list()
|
||||
self.uncorrectable_codewords = list()
|
||||
|
||||
def handle_data(self, data):
|
||||
data = data.strip()
|
||||
if data != "":
|
||||
self.signaldatapage.append(data)
|
||||
|
||||
def process(self):
|
||||
# Delete the junk before the statistics start. This list
|
||||
# should start with 'Downstream' after this deletion.
|
||||
del self.signaldatapage[0:119]
|
||||
|
||||
index_positions = [i for i, x in enumerate(self.signaldatapage) if x == "Index"]
|
||||
lock_status_positions = [
|
||||
i for i, x in enumerate(self.signaldatapage) if x == "Lock Status"
|
||||
]
|
||||
self.downstream_channels = lock_status_positions[0] - index_positions[0] - 1
|
||||
self.upstream_channels = lock_status_positions[1] - index_positions[1] - 1
|
||||
|
||||
self.downstream_SNRs = self.signaldatapage[
|
||||
6 + 3 * self.downstream_channels : 22 + 3 * self.downstream_channels
|
||||
]
|
||||
self.downstream_SNRs = [x.split()[0] for x in self.downstream_SNRs]
|
||||
|
||||
self.downstream_powers = self.signaldatapage[
|
||||
7 + 4 * self.downstream_channels : 23 + 4 * self.downstream_channels
|
||||
]
|
||||
self.downstream_powers = [x.split()[0] for x in self.downstream_powers]
|
||||
|
||||
self.upstream_powers = self.signaldatapage[
|
||||
15
|
||||
+ 6 * self.downstream_channels
|
||||
+ 4 * self.upstream_channels : 15
|
||||
+ 6 * self.downstream_channels
|
||||
+ 5 * self.upstream_channels
|
||||
]
|
||||
self.upstream_powers = [x.split()[0] for x in self.upstream_powers]
|
||||
|
||||
self.unerrored_codewords = self.signaldatapage[
|
||||
19
|
||||
+ 6 * self.downstream_channels
|
||||
+ 7 * self.upstream_channels : 19
|
||||
+ 7 * self.downstream_channels
|
||||
+ 7 * self.upstream_channels
|
||||
]
|
||||
|
||||
self.correctable_codewords = self.signaldatapage[
|
||||
20
|
||||
+ 7 * self.downstream_channels
|
||||
+ 7 * self.upstream_channels : 20
|
||||
+ 8 * self.downstream_channels
|
||||
+ 7 * self.upstream_channels
|
||||
]
|
||||
|
||||
self.uncorrectable_codewords = self.signaldatapage[
|
||||
21
|
||||
+ 8 * self.downstream_channels
|
||||
+ 7 * self.upstream_channels : 21
|
||||
+ 9 * self.downstream_channels
|
||||
+ 7 * self.upstream_channels
|
||||
]
|
||||
|
||||
|
||||
if len(sys.argv) != 2 or sys.argv[1] != "config":
|
||||
print(
|
||||
"Error: plugin designed for the dirtyconfig protocol, must be run with the config argument"
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
parser = TechnicolorHTMLParser()
|
||||
|
||||
for line in urllib.request.urlopen("http://192.168.100.1/vendor_network.asp"):
|
||||
parser.feed(line.decode())
|
||||
|
||||
parser.process()
|
||||
|
||||
print(
|
||||
"""multigraph technicolor_tc8715d_power
|
||||
graph_title Technicolor TC8715D Cable Modem Power
|
||||
graph_vlabel Signal Strength (dBmV)
|
||||
graph_info This graph shows the channel power values reported by a Technicolor TC8715D cable modem.
|
||||
graph_category network"""
|
||||
)
|
||||
|
||||
for i in range(parser.downstream_channels):
|
||||
print(
|
||||
f"""ds_power_{i+1}.label Channel {i+1} Downstream Power
|
||||
ds_power_{i+1}.type GAUGE
|
||||
ds_power_{i+1}.value {parser.downstream_powers[i]}"""
|
||||
)
|
||||
|
||||
for i in range(parser.upstream_channels):
|
||||
print(
|
||||
f"""us_power_{i+1}.label Channel {i+1} Upstream Power
|
||||
us_power_{i+1}.type GAUGE
|
||||
us_power_{i+1}.value {parser.upstream_powers[i]}"""
|
||||
)
|
||||
|
||||
print(
|
||||
"""multigraph technicolor_tc8715d_snr
|
||||
graph_title Technicolor TC8715D Cable Modem SNR
|
||||
graph_vlabel Signal-to-Noise Ratio (dB)
|
||||
graph_info This graph shows the downstream signal-to-noise ratio reported by a Technicolor TC8715D cable modem.
|
||||
graph_category network"""
|
||||
)
|
||||
|
||||
for i in range(parser.downstream_channels):
|
||||
print(
|
||||
f"""snr_{i+1}.label Channel {i+1} SNR
|
||||
snr_{i+1}.type GAUGE
|
||||
snr_{i+1}.value {parser.downstream_SNRs[i]}"""
|
||||
)
|
||||
|
||||
print(
|
||||
"""multigraph technicolor_tc8715d_codewords
|
||||
graph_title Technicolor TC8715D Cable Modem Codewords
|
||||
graph_vlabel Codewords/${graph_period}
|
||||
graph_info This graph shows the downstream codeword rates reported by a Technicolor TC8715D cable modem.
|
||||
graph_category network"""
|
||||
)
|
||||
|
||||
for i in range(parser.downstream_channels):
|
||||
print(
|
||||
f"""unerr_{i+1}.label Channel {i+1} Unerrored Codewords
|
||||
unerr_{i+1}.type DERIVE
|
||||
unerr_{i+1}.min 0
|
||||
unerr_{i+1}.value {parser.unerrored_codewords[i]}
|
||||
corr_{i+1}.label Channel {i+1} Correctable Codewords
|
||||
corr_{i+1}.type DERIVE
|
||||
corr_{i+1}.min 0
|
||||
corr_{i+1}.value {parser.correctable_codewords[i]}
|
||||
uncorr_{i+1}.label Channel {i+1} Uncorrectable Codewords
|
||||
uncorr_{i+1}.type DERIVE
|
||||
uncorr_{i+1}.min 0
|
||||
uncorr_{i+1}.value {parser.uncorrectable_codewords[i]}"""
|
||||
)
|
Loading…
Reference in New Issue