Skip to content

Instantly share code, notes, and snippets.

@cnaude
Created June 19, 2023 21:19
Show Gist options
  • Save cnaude/1c69626e20e6f56b41abafb1c5faaf21 to your computer and use it in GitHub Desktop.
Save cnaude/1c69626e20e6f56b41abafb1c5faaf21 to your computer and use it in GitHub Desktop.
Gather Netgear CM1100 metrics and send them to InfluxDB V2
#!/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