Created
June 19, 2023 21:19
-
-
Save cnaude/1c69626e20e6f56b41abafb1c5faaf21 to your computer and use it in GitHub Desktop.
Gather Netgear CM1100 metrics and send them to InfluxDB V2
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
#!/usr/bin/env python3 | |
"""Gather Netgear CM1100 metrics and send them to InfluxDB V2""" | |
import argparse | |
import re | |
import requests | |
from datetime import datetime | |
from influxdb_client import InfluxDBClient | |
from influxdb_client import Point | |
from influxdb_client.client.write_api import SYNCHRONOUS | |
from bs4 import BeautifulSoup | |
def main(influxdb_url): | |
bucket = 'BUCKET_CHANGEME' | |
token = 'TOKEN_CHANGEME' | |
org = 'ORG_CHANGEME' | |
username = 'admin' | |
password = 'PASS_CHANGEME' | |
status_url = 'http://192.168.100.1/DocsisStatus.asp' | |
login_url = 'http://192.168.100.1/goform/GenieLogin' | |
client = InfluxDBClient(url=influxdb_url, token=token, org=org, verify_ssl=False) | |
write_api = client.write_api(write_options=SYNCHRONOUS) | |
s = requests.Session() | |
login_data = {"loginUsername": username, | |
"loginPassword": password, | |
"login": 1, | |
"webToken": "1687088405"} | |
headers = {'Content-Type': 'application/x-www-form-urlencoded'} | |
login_response = s.post(login_url, data=login_data, headers=headers) | |
print("Login response code:") | |
print(login_response.status_code) | |
content_response = s.get(status_url) | |
print("Content response:") | |
print(content_response.text) | |
soup = BeautifulSoup(content_response.text, 'html.parser') | |
data = [] | |
timestamp = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ') | |
ds_table = soup.find_all("table", {"id": "dsTable"}) | |
us_table = soup.find_all("table", {"id": "usTable"}) | |
ds_lock_count = 0 | |
us_lock_count = 0 | |
uptime = soup.find_all("td", {"id": "SystemUpTime"}) | |
print("Uptime") | |
print(uptime) | |
uptime = re.sub(r'[^0-9:]', "", uptime[0].text) | |
uptime = re.sub(r'^:', "", uptime) | |
hms = uptime.split(":") | |
uptime = (int(hms[0]) * 3600) + (int(hms[1]) * 60) + int(hms[2]) | |
connectivity_status = 1 if "OK" in soup.find("td", text="Connectivity State").find_next_sibling("td").text else 0 | |
print("Connectivity State") | |
print(connectivity_status) | |
boot_state_status = 1 if "OK" in soup.find("td", text="Boot State").find_next_sibling("td").text else 0 | |
print("Boot State") | |
print(boot_state_status) | |
# Downstream Bonded Channels | |
for tr in ds_table[0].find_all('tr'): | |
td = tr.find_all('td') | |
if td[0].text == 'Channel': | |
continue | |
channel = td[0].text | |
lock_status = td[1].text | |
if lock_status == 'Locked': | |
ds_lock_count += 1 | |
modulation = td[2].text | |
channel_id = td[3].text | |
frequency = int(re.sub(r'[^0-9]', "", td[4].text)) | |
power = float(re.sub(r'[^0-9\.]', "", td[5].text)) | |
snr = float(re.sub(r'[^0-9\.]', "", td[6].text)) | |
unerrored_codewords = int(td[7].text) | |
correctable_codewords = int(td[7].text) | |
uncorrectable_codewords = int(td[8].text) | |
data.append({ | |
"measurement": "downstream_channels", | |
"tags": { | |
"channel": channel, | |
"lock_status": lock_status, | |
"channel_id": channel_id, | |
"modulation": modulation, | |
}, | |
"time": timestamp, | |
"fields": { | |
"power": power, | |
"snr": snr, | |
"unerrored_codewords": unerrored_codewords, | |
"correctable_codewords": correctable_codewords, | |
"uncorrectable_codewords": uncorrectable_codewords, | |
"frequency": frequency, | |
} | |
}) | |
# Upstream Bonded Channels | |
for tr in us_table[0].find_all('tr'): | |
td = tr.find_all('td') | |
if td[0].text == 'Channel': | |
continue | |
channel = td[0].text | |
lock_status = td[1].text | |
if lock_status == 'Locked': | |
us_lock_count += 1 | |
modulation = td[2].text | |
channel_id = td[3].text | |
frequency = int(re.sub(r'[^0-9]', "", td[4].text)) | |
power = float(re.sub(r'[^0-9\.]', "", td[5].text)) | |
data.append({ | |
"measurement": "upstream_channels", | |
"tags": { | |
"channel": channel, | |
"lock_status": lock_status, | |
"modulation": modulation, | |
"channel_id": channel_id, | |
}, | |
"time": timestamp, | |
"fields": { | |
"frequency": frequency, | |
"power": power, | |
} | |
}) | |
data.append({ | |
"measurement": "details", | |
"time": timestamp, | |
"fields": { | |
"ds_lock_count": ds_lock_count, | |
"us_lock_count": us_lock_count, | |
"uptime": uptime, | |
"connectivity_status": connectivity_status, | |
"boot_state_status": boot_state_status, | |
} | |
}) | |
print("Writing to bucket") | |
write_api.write(bucket, org, data) | |
print("Done") | |
print("Data") | |
def parse_args(): | |
"""Parse the args.""" | |
parser = argparse.ArgumentParser( | |
description='Query Netgear CM1100 cable modem and send metrics to InfluxDB V2') | |
parser.add_argument('--influxdb_url', type=str, required=False, | |
default='https://localhost:8086', | |
help='URL of InfluxDB API') | |
return parser.parse_args() | |
if __name__ == '__main__': | |
args = parse_args() | |
main(influxdb_url=args.influxdb_url) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment