forked from munin-monitoring/contrib
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add plugin for Technicolor TC8715D cable modem stats
- Loading branch information
1 parent
1fc177c
commit 6abc523
Showing
1 changed file
with
233 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <[email protected]> | ||
=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]}""" | ||
) |