1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
# wget https://static.tp-link.com/upload/software/2022/202209/20220915/privateMibs(20220831).zip
# cp -v *.mib /home/eden/.snmp/mibs
# sudo apt install snmp
# sudo apt-get install snmp-mibs-downloader
import subprocess
from dataclasses import dataclass
import dotenv
import os
import pandas
from influxdb_client import InfluxDBClient, Point, WritePrecision
from influxdb_client.client.write_api import SYNCHRONOUS
DIVIDE_BY_10_ENDPOINTS = ["tpPoePower", "tpPoeVoltage"]
PORT_NAMES = dotenv.dotenv_values(os.path.join(os.path.dirname(__file__), "port-names.conf"))
PORT_NAMES = {int(k): v for k, v in PORT_NAMES.items()}
@dataclass
class SNMPReading:
endpoint: str
port: int
reading: float
@classmethod
def from_string(cls, str_):
s = str_.split()
if len(s) != 4:
raise Exception("Couldn't parse")
endpoint_and_port, _, type_, reading = s
endpoint, port = endpoint_and_port.split(".")
if reading.isdigit():
reading = int(reading)
if endpoint in DIVIDE_BY_10_ENDPOINTS:
reading = reading / 10
return cls(endpoint, int(port), reading)
def get_alternate_name(port):
try:
return PORT_NAMES[port]
except KeyError:
return port
def snmp_walk(host):
proc = subprocess.Popen(
["snmpwalk", "-Os", "-c", "tplink", "-v", "2c", "-m", "TPLINK-POWER-OVER-ETHERNET-MIB", host, "tplinkPowerOverEthernetMIB"],
stdout = subprocess.PIPE
)
out = []
while True:
line = proc.stdout.readline()
if not line:
break
try:
out.append(SNMPReading.from_string(line.rstrip().decode()))
except Exception:
pass
return out
def readings_to_points(readings, switch_host):
points = []
df = pandas.DataFrame(readings)
df["port_name"] = df["port"].apply(get_alternate_name)
for p, group_df in df.groupby(["port", "port_name"]):
port, port_name = p
fields = dict(zip(group_df['endpoint'], group_df['reading']))
points.append({"measurement": "switch_status", "tags": {"port": port, "port_name": port_name, "switch_host": switch_host}, "fields": fields})
return points
if __name__ == "__main__":
env_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "config.env")
if os.path.exists(env_path):
import dotenv
dotenv.load_dotenv(dotenv_path = env_path)
INFLUXDB_HOST = "dns.athome"
else:
INFLUXDB_HOST = "influxdb"
influxc = InfluxDBClient(
url = "http://%s:8086" % INFLUXDB_HOST,
token = os.environ["DOCKER_INFLUXDB_INIT_ADMIN_TOKEN"],
org = os.environ["DOCKER_INFLUXDB_INIT_ORG"]
)
influxc.ping()
for switch_host in os.environ["OMADA_SWITCHES"].split(","):
points = readings_to_points(snmp_walk(switch_host), switch_host)
write_api = influxc.write_api(write_options = SYNCHRONOUS)
write_api.write(
os.environ["DOCKER_INFLUXDB_INIT_BUCKET"],
os.environ["DOCKER_INFLUXDB_INIT_ORG"],
points,
write_precision = WritePrecision.S
)
|