aboutsummaryrefslogtreecommitdiffstats
path: root/switch-snmp/snmpOmada.py
blob: f1546a7ab4406f0ed97ac0ef9ea05a604895a38b (plain)
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
# 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
import configparser

from influxdb_client import InfluxDBClient, Point, WritePrecision
from influxdb_client.client.write_api import SYNCHRONOUS

DIVIDE_BY_10_ENDPOINTS = ["tpPoePower", "tpPoeVoltage"]

@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, host):
    port_names = configparser.ConfigParser()
    port_names.read(os.path.join(os.path.dirname(__file__), "omada-switches.conf"))
    port_names = {int(k): v for k, v in port_names[host].items()}

    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, args = (switch_host, ))
    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, "type": "Omada"}, 
            "fields": fields
        })
    
    return points

def get_points():
    if not os.path.exists(os.path.join(os.path.dirname(__file__), "omada-switches.conf")):
        raise FileNotFoundError("Couldn't find config file")
    switches = configparser.ConfigParser()
    switches.read(os.path.join(os.path.dirname(__file__), "omada-switches.conf"))
    points = []
    for switch_host in switches.sections():
        points += readings_to_points(snmp_walk(switch_host), switch_host)
    return points

if __name__ == "__main__":
    import mikrotik
    points = get_points()
    print(points)
    mikrotik.append(points)