File: monitor.py

package info (click to toggle)
python-aioemonitor 1.0.5-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 184 kB
  • sloc: xml: 495; python: 265; makefile: 66
file content (113 lines) | stat: -rw-r--r-- 2,914 bytes parent folder | download
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
101
102
103
104
105
106
107
108
109
110
111
112
113
"""Monitor for aioemonitor."""

DEFAULT_REQUEST_TIMEOUT = 55
STATUS_ENDPOINT = "/status.xml"

import re
from dataclasses import dataclass

import xmltodict


@dataclass
class EmonitorChannel:
    number: int
    active: int
    label: str
    ct_size: int
    paired_with_channel: int
    input: int
    max_power: float
    avg_power: float
    inst_power: float


@dataclass
class EmonitorHardware:
    serial_number: str
    firmware_version: str


@dataclass
class EmonitorNetwork:
    mac_address: str
    ip_address: str


@dataclass
class EmonitorStatus:
    hardware: EmonitorHardware
    network: EmonitorNetwork
    channels: list


class Emonitor:
    """Async emonitor api."""

    def __init__(self, host, websession, timeout=DEFAULT_REQUEST_TIMEOUT):
        """Create oncue async api object."""
        self._host = host
        self._websession = websession
        self._timeout = timeout

    async def _get(self, endpoint, params=None):
        """Make a get request."""
        response = await self._websession.request(
            "GET",
            f"http://{self._host}{endpoint}",
            timeout=self._timeout,
            params=params,
        )
        data = await response.read()
        return data.decode("utf-8", "ignore")

    async def async_get_status(self):
        """Call api to get latest status."""
        text = await self._get(STATUS_ENDPOINT)
        # Strip the TLA_number because can can have invalid UTF-8
        data = xmltodict.parse(re.sub("<TLA_number>.*?</TLA_number>", "", text.strip()))
        emonitor = data["emonitor"]
        hardware = emonitor["hardware"]
        emonitor_hardware = EmonitorHardware(
            hardware["serial_number"], hardware["firmware_version"]
        )
        network = emonitor["hardware"]["network"]
        emonitor_network = EmonitorNetwork(
            network["MAC_address"], network["IP_address"]
        )
        emonitor_channels = {
            _as_int(channel["@Number"]): EmonitorChannel(
                _as_int(channel["@Number"]),
                _channel_is_active(channel["active"]),
                channel["label"],
                _as_int(channel["CT_size"]),
                _as_int(channel["paired_with_channel"]) or None,
                _as_int(channel["input"]),
                _as_float(channel["max_power"]),
                _as_float(channel["avg_power"]),
                _as_float(channel["inst_power"]),
            )
            for channel in emonitor["channels"]["channel"]
        }
        return EmonitorStatus(emonitor_hardware, emonitor_network, emonitor_channels)


def _channel_is_active(active):
    try:
        return bool(int(active))
    except TypeError:
        return None


def _as_int(str):
    try:
        return int(str)
    except TypeError:
        return None


def _as_float(str):
    try:
        return float(str)
    except TypeError:
        return None