From dc6d671127f7d08afdd0e9faa89471fc3f8fbf78 Mon Sep 17 00:00:00 2001 From: Awin Huang Date: Tue, 11 Feb 2025 10:13:39 +0800 Subject: [PATCH] Remove unused Prometheus data exporter interface and related utility functions --- .../code/awinlib/KasaSmartPowerStrip.py | 239 ------------------ .../code/awinlib/PrometheusDataExporter.py | 121 --------- .../PrometheusDataExporterInterface.py | 10 - .../dataExporter/code/awinlib/__init__.py | 15 -- .../dataExporter/code/awinlib/cpufantemp.py | 54 ---- dockerfiles/dataExporter/code/awinlib/hdd.py | 49 ---- dockerfiles/dataExporter/code/awinlib/tapo.py | 132 ---------- .../dataExporter/code/awinlib/utilities.py | 77 ------ .../code/prometheus_data_exporter.py | 88 ------- 9 files changed, 785 deletions(-) delete mode 100644 dockerfiles/dataExporter/code/awinlib/KasaSmartPowerStrip.py delete mode 100644 dockerfiles/dataExporter/code/awinlib/PrometheusDataExporter.py delete mode 100644 dockerfiles/dataExporter/code/awinlib/PrometheusDataExporterInterface.py delete mode 100644 dockerfiles/dataExporter/code/awinlib/__init__.py delete mode 100644 dockerfiles/dataExporter/code/awinlib/cpufantemp.py delete mode 100644 dockerfiles/dataExporter/code/awinlib/hdd.py delete mode 100644 dockerfiles/dataExporter/code/awinlib/tapo.py delete mode 100644 dockerfiles/dataExporter/code/awinlib/utilities.py delete mode 100644 dockerfiles/dataExporter/code/prometheus_data_exporter.py diff --git a/dockerfiles/dataExporter/code/awinlib/KasaSmartPowerStrip.py b/dockerfiles/dataExporter/code/awinlib/KasaSmartPowerStrip.py deleted file mode 100644 index 661890d..0000000 --- a/dockerfiles/dataExporter/code/awinlib/KasaSmartPowerStrip.py +++ /dev/null @@ -1,239 +0,0 @@ -import socket -import json -import struct -from builtins import bytes - -class SmartPowerStrip(object): - - def __init__(self, ip, device_id=None, timeout=2.0, protocol='tcp'): - self.ip = ip - self.port = 9999 - self.protocol = protocol - self.device_id = device_id - self.sys_info = None - self.timeout = timeout - - self.sys_info = self.get_system_info()['system']['get_sysinfo'] - - if not self.device_id: - self.device_id = self.sys_info['deviceId'] - - def set_wifi_credentials(self, ssid, psk, key_type='3'): - ''' - :param ssid: router ssid - :param psk: router passkey - :param key_type: 3 is WPA2, 2 might be WPA and 1 might be WEP? - :return: command response - ''' - - wifi_command = '{"netif":{"set_stainfo":{"ssid":"' + ssid + '","password":"' + \ - psk + '","key_type":' + key_type + '}}}' - - return self.send_command(wifi_command, self.protocol) - - def set_cloud_server_url(self, server_url=''): - - server_command = '{"cnCloud":{"set_server_url":{"server":"' + server_url + '"}}}' - - return self.send_command(server_command, self.protocol) - - def get_system_info(self): - - return self._udp_send_command('{"system":{"get_sysinfo":{}}}') - - def get_realtime_energy_info(self, plug_num=None, plug_name=None): - - plug_id = self._get_plug_id(plug_num=plug_num, plug_name=plug_name) - - energy_command = '{"context":{"child_ids":["' + plug_id + '"]},"emeter":{"get_realtime":{}}}' - - response = self.send_command(energy_command, self.protocol) - - realtime_energy_data = response['emeter']['get_realtime'] - - return realtime_energy_data - - def get_historical_energy_info(self, month, year, plug_num=None, plug_name=None): - - plug_id = self._get_plug_id(plug_num=plug_num, plug_name=plug_name) - - energy_command = '{"context":{"child_ids":["' + plug_id + '"]},' + \ - '"emeter":{"get_daystat":{"month": ' + month + ',"year":' + year + '}}}' - - response = self.send_command(energy_command, self.protocol) - - historical_energy_data = response['emeter']['get_daystat']['day_list'] - - return historical_energy_data - - def toggle_relay_leds(self, state): - - state_int = self._get_plug_state_int(state, reverse=True) - - led_command = '{"system":{"set_led_off":{"off":' + str(state_int) + '}}}' - - return self.send_command(led_command, self.protocol) - - def set_plug_name(self, plug_num, plug_name): - - plug_id = self._get_plug_id(plug_num=plug_num) - - set_name_command = '{"context":{"child_ids":["' + plug_id + \ - '"]},"system":{"set_dev_alias":{"alias":"' + plug_name + '"}}}' - - return self.send_command(set_name_command, self.protocol) - - def get_plug_info(self, plug_num): - - target_plug = [plug for plug in self.sys_info['children'] if plug['id'] == str(int(plug_num)-1).zfill(2)] - - return target_plug - - # toggle multiple plugs by id or name - def toggle_plugs(self, state, plug_num_list=None, plug_name_list=None): - - state_int = self._get_plug_state_int(state) - - plug_id_list_str = self._get_plug_id_list_str(plug_num_list=plug_num_list, plug_name_list=plug_name_list) - - all_relay_command = '{"context":{"child_ids":' + plug_id_list_str + '},' + \ - '"system":{"set_relay_state":{"state":' + str(state_int) + '}}}' - - return self.send_command(all_relay_command, self.protocol) - - # toggle a single plug - def toggle_plug(self, state, plug_num=None, plug_name=None): - - state_int = self._get_plug_state_int(state) - - plug_id = self._get_plug_id(plug_num=plug_num, plug_name=plug_name) - - relay_command = '{"context":{"child_ids":["' + plug_id + '"]},' + \ - '"system":{"set_relay_state":{"state":' + str(state_int) + '}}}' - - return self.send_command(relay_command, self.protocol) - - def reboot(self, delay=1): - reboot_command = '{"system":{"reboot":{"delay":' + str(delay) + '}}}' - return self.send_command(reboot_command, self.protocol) - - # manually send a command - def send_command(self, command, protocol='tcp'): - - if protocol == 'tcp': - return self._tcp_send_command(command) - elif protocol == 'udp': - return self._udp_send_command(command) - else: - raise ValueError("Protocol must be 'tcp' or 'udp'") - - def _get_plug_state_int(self, state, reverse=False): - - if state.lower() == 'on': - if reverse: - state_int = 0 - else: - state_int = 1 - elif state.lower() == 'off': - if reverse: - state_int = 1 - else: - state_int = 0 - else: - raise ValueError("Invalid state, must be 'on' or 'off'") - - return state_int - - # create a string with a list of plug_ids that can be inserted directly into a command - def _get_plug_id_list_str(self, plug_num_list=None, plug_name_list=None): - - plug_id_list = [] - - if plug_num_list: - for plug_num in plug_num_list: - - # add as str to remove the leading u - plug_id_list.append(str(self._get_plug_id(plug_num=plug_num))) - - elif plug_name_list: - - for plug_name in plug_name_list: - # add as str to remove the leading u - plug_id_list.append(str(self._get_plug_id(plug_name=plug_name))) - - # convert to double quotes and turn the whole list into a string - plug_id_list_str = str(plug_id_list).replace("'", '"') - - return plug_id_list_str - - # get the plug child_id to be used with commands - def _get_plug_id(self, plug_num=None, plug_name=None): - - if plug_num and self.device_id: - plug_id = self.device_id + str(plug_num-1).zfill(2) - - elif plug_name and self.sys_info: - target_plug = [plug for plug in self.sys_info['children'] if plug['alias'] == plug_name] - if target_plug: - plug_id = self.device_id + target_plug[0]['id'] - else: - raise ValueError('Unable to find plug with name ' + plug_name) - else: - raise ValueError('Unable to find plug. Provide a valid plug_num or plug_name') - - return plug_id - - def _tcp_send_command(self, command): - - sock_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock_tcp.settimeout(self.timeout) - sock_tcp.connect((self.ip, self.port)) - - sock_tcp.send(self._encrypt_command(command)) - - data = sock_tcp.recv(2048) - sock_tcp.close() - - # the first 4 chars are the length of the command so can be excluded - return json.loads(self._decrypt_command(data[4:])) - - def _udp_send_command(self, command): - - client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - client_socket.settimeout(self.timeout) - - addr = (self.ip, self.port) - - client_socket.sendto(self._encrypt_command(command, prepend_length=False), addr) - - data, server = client_socket.recvfrom(2048) - - return json.loads(self._decrypt_command(data)) - - @staticmethod - def _encrypt_command(string, prepend_length=True): - - key = 171 - result = b'' - - # when sending get_sysinfo using udp the length of the command is not needed but - # with all other commands using tcp it is - if prepend_length: - result = struct.pack(">I", len(string)) - - for i in bytes(string.encode('latin-1')): - a = key ^ i - key = a - result += bytes([a]) - return result - - @staticmethod - def _decrypt_command(string): - - key = 171 - result = b'' - for i in bytes(string): - a = key ^ i - key = i - result += bytes([a]) - return result.decode('latin-1') diff --git a/dockerfiles/dataExporter/code/awinlib/PrometheusDataExporter.py b/dockerfiles/dataExporter/code/awinlib/PrometheusDataExporter.py deleted file mode 100644 index f947013..0000000 --- a/dockerfiles/dataExporter/code/awinlib/PrometheusDataExporter.py +++ /dev/null @@ -1,121 +0,0 @@ -import asyncio -import weakref - -import awinlib.cpufantemp as cpufantemp -import awinlib.hdd as hdd -import awinlib.PrometheusDataExporterInterface as interface -import awinlib.tapo -import awinlib.utilities -from awinlib.utilities import log - - -class HddTempDataExporter(interface.IPrometheusDataExporter): - DEFAULT_ERROR_HDD_TEMP = -273 - - def export(self): - exportData = [] - - hddTempDict = hdd.getHddTemp() - for hddKey in sorted(hddTempDict.keys()): - hddName = hddKey.replace("/dev/", "") - hddType = hddTempDict[hddKey].get("TYPE", "") - hddTemperature = int(hddTempDict[hddKey].get("temp", HddTempDataExporter.DEFAULT_ERROR_HDD_TEMP)) - # uuid = hddTempDict[hddKey].get("UUID", "").replace("-", "_") - # partUuid = hddTempDict[hddKey].get("PARTUUID", "") - gaugeName = f"{hddName}_{hddType}_celsius" - gaugeDescription = f"HDD temperature of {gaugeName}" - - exportData.append({ - 'name': gaugeName, - 'description': gaugeDescription, - 'value': hddTemperature - }) - return exportData - - -class CpuFanTempDataExporter(interface.IPrometheusDataExporter): - def export(self): - exportData = [] - fanTempDict = cpufantemp.getCpuTempAndFanSpeed() - - if "fan" not in fanTempDict: - return exportData - - for fanKey in sorted(fanTempDict["fan"].keys()): - fanSpeed = fanTempDict["fan"][fanKey] - - gaugeName = f"{fanKey}_rpm" - gaugeDescription = f"Fan RPM of {gaugeName}" - - exportData.append({ - 'name': gaugeName, - 'description': gaugeDescription, - 'value': fanSpeed - }) - return exportData - - -class KasaPowerStripDataExporter(interface.IPrometheusDataExporter): - def __init__(self, areaName, ip): - self.powerStrip = awinlib.tapo.KasaPowerStrip(areaName, ip) - - def export(self): - exportData = [] - powerStripData = self.powerStrip.collectData() - for keyId in sorted(powerStripData.keys()): - for gaugeName in powerStripData[keyId].keys(): - gaugeDesc = powerStripData[keyId][gaugeName]["description"] - gaugeValue = powerStripData[keyId][gaugeName]["value"] - - exportData.append({ - 'name': gaugeName, - 'description': gaugeDesc, - 'value': gaugeValue - }) - return exportData - - -class TapoT315DataExporter(interface.IPrometheusDataExporter): - def __init__(self, ip, username, password, devName, devNameInEnglish=""): - self.devIp = ip - self.devUsername = username - self.devPassword = password - self.devName = devName - self.devNameInEnglish = devNameInEnglish - self.devInstance = awinlib.tapo.TplinkT315(ip, username, password, devName) - if awinlib.utilities.syncRun(self.devInstance.connect()) is True: - log(f'Connected to T315({ip}, {devName})') - self.__finalizer = weakref.finalize(self, self._del, self) - else: - self.devInstance = None - raise ConnectionError(f"Failed to connect to T315({ip}, {devName})") - - @staticmethod - def _del(this): - if this.devInstance: - log('Disconnecting from T315') - awinlib.utilities.syncRun(this.devInstance.disconnect()) - - def export(self): - exportData = [] - - temperatureValue = awinlib.utilities.syncRun(self.devInstance.getTemperature()) - if temperatureValue is not None: - gaugeName = f"{self.normalizeGaugename(self.devNameInEnglish)}_temperature_celsius" if self.devNameInEnglish != "" else "temperature_celsius" - gaugeDescription = "Temperature of T315" - exportData.append({ - 'name': gaugeName, - 'description': gaugeDescription, - 'value': temperatureValue - }) - - humidityValue = awinlib.utilities.syncRun(self.devInstance.getHumidity()) - if humidityValue is not None: - gaugeName = f"{self.normalizeGaugename(self.devNameInEnglish)}_humidity_percent" if self.devNameInEnglish != "" else "humidity_percent" - gaugeDescription = "Humidity of T315" - exportData.append({ - 'name': gaugeName, - 'description': gaugeDescription, - 'value': humidityValue - }) - return exportData diff --git a/dockerfiles/dataExporter/code/awinlib/PrometheusDataExporterInterface.py b/dockerfiles/dataExporter/code/awinlib/PrometheusDataExporterInterface.py deleted file mode 100644 index 7fae5f2..0000000 --- a/dockerfiles/dataExporter/code/awinlib/PrometheusDataExporterInterface.py +++ /dev/null @@ -1,10 +0,0 @@ -import abc - - -class IPrometheusDataExporter: - @abc.abstractmethod - def export(self): - pass - - def normalizeGaugename(self, originalName): - return originalName.replace("-", "_").lower() diff --git a/dockerfiles/dataExporter/code/awinlib/__init__.py b/dockerfiles/dataExporter/code/awinlib/__init__.py deleted file mode 100644 index 8b4ab71..0000000 --- a/dockerfiles/dataExporter/code/awinlib/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -import logging - -from rich.logging import RichHandler - -LOGFORMAT_RICH = '%(message)s' -richHandler = RichHandler( - rich_tracebacks=True, -) -richHandler.setFormatter(logging.Formatter(LOGFORMAT_RICH)) -logging.basicConfig( - level=logging.INFO, - handlers=[ - richHandler, - ] -) diff --git a/dockerfiles/dataExporter/code/awinlib/cpufantemp.py b/dockerfiles/dataExporter/code/awinlib/cpufantemp.py deleted file mode 100644 index 43a408d..0000000 --- a/dockerfiles/dataExporter/code/awinlib/cpufantemp.py +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/python3 -import json -import os - -from .utilities import runCmd - - -def getCpuTempAndFanSpeed(): - if os.name == "nt": - return {} - - cmd = "sensors" - ret = runCmd(cmd).split("\n") - - fanTempDict = { - "cpu": {}, - "fan": {} - } - for line in ret: - if line.startswith("Core"): - line = line.split(":") - if len(line) > 1: - cpuIndex, tempString = line[0], line[1] - tempString = tempString.split(" ") - tempString = [x for x in tempString if x != ""] - if len(tempString) > 1: - temp = float(tempString[0].replace("+", "").replace("°C", "")) - else: - temp = -999.9 - fanTempDict["cpu"][cpuIndex] = temp - - elif line.startswith("fan"): - line = line.split(":") - if len(line) > 1: - fanId, fanNumber = line[0], line[1] - fanNumber = fanNumber.split(" ") - fanNumber = [x for x in fanNumber if x != ""] - if len(fanNumber) > 1: - fanSpeed = int(fanNumber[0]) - else: - fanSpeed = 0 - - if fanSpeed > 0: - fanTempDict["fan"][fanId] = fanSpeed - return fanTempDict - - -def main(): - fanTempDict = getCpuTempAndFanSpeed() - print(f"{json.dumps(fanTempDict, indent=4)}") - - -if __name__ == "__main__": - main() diff --git a/dockerfiles/dataExporter/code/awinlib/hdd.py b/dockerfiles/dataExporter/code/awinlib/hdd.py deleted file mode 100644 index 3e11ff6..0000000 --- a/dockerfiles/dataExporter/code/awinlib/hdd.py +++ /dev/null @@ -1,49 +0,0 @@ -import os - -from .utilities import runCmd - - -def findHddIdInNt(): - return {} - -def findHddIdInPosix(): - hddDict = {} - results = runCmd("blkid").split("\n") - for line in results: - if line == "": - continue - - hddInfoList = line.split(" ") - if len(hddInfoList) > 1 and hddInfoList[0].startswith("/dev/sd"): - hddName = hddInfoList[0].replace(":", "") - hddDict[hddName] = {} - for hddInfoline in hddInfoList[1:]: - kvList = hddInfoline.split("=") - if len(kvList) > 1: - hddDict[hddName][kvList[0].replace("\"", "")] = kvList[1].replace("\"", "") - return hddDict - - -def findHddId(): - hddDict = {} - if os.name == "nt": - hddDict = findHddIdInNt() - elif os.name == "posix": - hddDict = findHddIdInPosix() - return hddDict - - -def findHddTemp(hddDict): - for hddName in sorted(hddDict.keys()): - cmd = f"smartctl -A {hddName} | grep Temperature_Celsius" - hddTempString = runCmd(cmd) - hddTempList = hddTempString.split(" ") - hddTempList = [item for item in hddTempList if item != ""] - if len(hddTempList) > 9: - hddDict[hddName]["temp"] = int(hddTempList[9]) - - -def getHddTemp(): - hddDict = findHddId() - findHddTemp(hddDict) - return hddDict diff --git a/dockerfiles/dataExporter/code/awinlib/tapo.py b/dockerfiles/dataExporter/code/awinlib/tapo.py deleted file mode 100644 index b3e8973..0000000 --- a/dockerfiles/dataExporter/code/awinlib/tapo.py +++ /dev/null @@ -1,132 +0,0 @@ -from kasa import Discover -from kasa.exceptions import KasaException - -from . import KasaSmartPowerStrip -from .utilities import log as log - - -class KasaPowerStrip: - def __init__(self, areaName, ip): - self.areaName = areaName - self.ip = ip - try: - self.powerStrip = KasaSmartPowerStrip.SmartPowerStrip(ip) - except: - self.powerStrip = None - - def collectData(self): - dataDict = {} - devSysInfo = self.powerStrip.get_system_info() - for c in devSysInfo['system']['get_sysinfo']['children']: - try: - cid = int(c['id']) + 1 - except: - continue - - # aliasName = c['alias'].encode('latin1').decode('UTF-8') - gaugeName_Current_ma = f"{self.areaName}_{cid}_current_ma" - gaugeName_Current_ma_desc = f"Current(milliampere) of {self.areaName}:{cid}" - gaugeName_Voltage_mv = f"{self.areaName}_{cid}_voltage_mv" - gaugeName_Voltage_mv_desc = f"Voltage(millivolt) of {self.areaName}:{cid}" - gaugeName_Power_mw = f"{self.areaName}_{cid}_power_mw" - gaugeName_Power_mw_desc = f"Power(milliwatt) of {self.areaName}:{cid}" - gaugeName_TotalWh = f"{self.areaName}_{cid}_total_wh" - gaugeName_TotalWh_desc = f"Total watt-hour of {self.areaName}:{cid}" - - ## Get Data - realtimeInfo = self.powerStrip.get_realtime_energy_info(plug_num=cid) - realTime_current_ma = realtimeInfo.get("current_ma", 0) - realTime_voltage_mv = realtimeInfo.get("voltage_mv", 0) - realTime_power_mw = realtimeInfo.get("power_mw", 0) - realTime_total_wh = realtimeInfo.get("total_wh", 0) - - # log(f"Set {gaugeName_Current_ma}: {realTime_current_ma}") - # log(f"Set {gaugeName_Voltage_mv}: {realTime_voltage_mv}") - # log(f"Set {gaugeName_Power_mw}: {realTime_power_mw}") - # log(f"Set {gaugeName_TotalWh}: {realTime_total_wh}") - - dataDict[cid] = { - gaugeName_Current_ma: { - "description": gaugeName_Current_ma_desc, - "value": realTime_current_ma, - }, - gaugeName_Voltage_mv: { - "description": gaugeName_Voltage_mv_desc, - "value": realTime_voltage_mv, - }, - gaugeName_Power_mw: { - "description": gaugeName_Power_mw_desc, - "value": realTime_power_mw, - }, - gaugeName_TotalWh: { - "description": gaugeName_TotalWh_desc, - "value": realTime_total_wh, - } - } - return dataDict - - -class TplinkT315: - def __init__(self, ip, username, password, devName): - self.ip = ip - self.username = username - self.password = password - self.devName = devName - self.hubDev = None - self.t315Dev = None - - async def connect(self): - try: - self.hubDev = await Discover.discover_single(self.ip, username=self.username, password=self.password) - await self.hubDev.update() - except KasaException as e: - self.hubDev = None - log(f"Hub Error: {e}") - return False - - try: - self.t315Dev = self.hubDev.get_plug_by_name(self.devName) - await self.t315Dev.update() - except KasaException as e: - self.t315Dev = None - log(f"Device Error: {e}") - return False - - return True - - async def getTemperature(self): - temperatureValue = await self.getProperty("temperature") - if temperatureValue is None: - log("temperatureValue is None") - return None - - temperatureValue = float(temperatureValue) - return temperatureValue - - async def getHumidity(self): - humidityValue = await self.getProperty("humidity") - if humidityValue is None: - log("humidityValue is None") - return None - - humidityValue = float(humidityValue) - return humidityValue - - async def getProperty(self, propName): - if self.t315Dev is None: - return None - - await self.hubDev.update() - await self.t315Dev.update() - - featuresOfTempDev = self.t315Dev.features - if propName not in featuresOfTempDev: - return None - - return featuresOfTempDev[propName].value - - async def disconnect(self): - if self.hubDev is None: - return - - await self.hubDev.disconnect() diff --git a/dockerfiles/dataExporter/code/awinlib/utilities.py b/dockerfiles/dataExporter/code/awinlib/utilities.py deleted file mode 100644 index 453028a..0000000 --- a/dockerfiles/dataExporter/code/awinlib/utilities.py +++ /dev/null @@ -1,77 +0,0 @@ -import asyncio -import datetime -import inspect -import json -import logging -import subprocess - -from rich import print as pp - - -def runCmd(cmdString): - result = subprocess.run(cmdString, stdout=subprocess.PIPE, shell=True).stdout.decode('utf-8') - return result - - -def syncRun(coroutine): - loop = asyncio.get_event_loop() - # coroutine = funcInstace() - return loop.run_until_complete(coroutine) - - -def datetimeNow(): - return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") - - -def loadJson(fileanme): - try: - with open(fileanme, "r") as f: - secrets = json.load(f) - - return secrets - except FileNotFoundError: - log(f"File not found: {fileanme}") - return None - - -def log2(message, *args): - frame = inspect.currentframe().f_back - class_name = frame.f_locals.get('self', '').__class__.__name__ - func_name = frame.f_code.co_name - line_no = frame.f_lineno - caller = f"{class_name}::{func_name},{line_no}" - prefix = f"[{datetimeNow()}|{caller}]" - pp(f"{prefix} {message}", end='') - for arg in args: - pp(arg, end='') - pp("") - - -def log(message, *args): - log = logging.getLogger() - log.info(message) - - -def logD(message, *args): - log = logging.getLogger() - log.debug(message) - - -def logI(message, *args): - log = logging.getLogger() - log.info(message) - - -def logW(message, *args): - log = logging.getLogger() - log.warning(message) - - -def logE(message, *args): - log = logging.getLogger() - log.error(message) - - -def logC(message, *args): - log = logging.getLogger() - log.critical(message) diff --git a/dockerfiles/dataExporter/code/prometheus_data_exporter.py b/dockerfiles/dataExporter/code/prometheus_data_exporter.py deleted file mode 100644 index c9fd009..0000000 --- a/dockerfiles/dataExporter/code/prometheus_data_exporter.py +++ /dev/null @@ -1,88 +0,0 @@ -import argparse -import time - -import schedule -from prometheus_client import Gauge, start_http_server - -from awinlib.PrometheusDataExporter import ( - CpuFanTempDataExporter, - HddTempDataExporter, - KasaPowerStripDataExporter, - TapoT315DataExporter, -) -from awinlib.utilities import datetimeNow, loadJson, log - -ENABLE_EXPORTER = True -DEFAULT_PORT = 8087 -DEFAULT_POLLING_INTERVAL = 60 -DEFAULT_SECRET_FILEPATH = "~/.secret" -DEFAULT_CONFIGS = { - "port": DEFAULT_PORT, - "polling_interval": DEFAULT_POLLING_INTERVAL, - "secret_filepath": DEFAULT_SECRET_FILEPATH -} - - -def job_5s(gaugeDict, exporters): - exportData(gaugeDict, exporters) - - -def job_60s(gaugeDict, exporters): - exportData(gaugeDict, exporters) - - -def exportData(gaugeDict, exporters): - for exporter in exporters: - data = exporter.export() - for d in data: - gaugeName = d["name"] - gaugeDesc = d["description"] - gaugeValue = d["value"] - log(f"Set {gaugeName}: {gaugeValue}") - if gaugeName not in gaugeDict: - gaugeDict[gaugeName] = Gauge(gaugeName, gaugeDesc) - - if ENABLE_EXPORTER: - gaugeDict[gaugeName].set(gaugeValue) - - -def main(configs): - log(f"Start: {datetimeNow()}") - secrect = loadJson(configs.get("secret_filepath", DEFAULT_POLLING_INTERVAL)) - if secrect is None: - log(f'Cannot read secret file({configs.get("secret_filepath", DEFAULT_POLLING_INTERVAL)})') - return - - hddTempExporter = HddTempDataExporter() - cpuFanTempExporter = CpuFanTempDataExporter() - powerStripLivingroomExporter = KasaPowerStripDataExporter("livingroom", "192.168.1.203") - powerStripAtticExporter = KasaPowerStripDataExporter("attic", "192.168.1.203") - t315Atticexporter = TapoT315DataExporter(secrect["ip"], secrect["username"], secrect["password"], "鐵皮屋-溫濕度感測器", "attic-sensors") - gaugeDict = {} - - schedule.every( 5).seconds.do(exportData, gaugeDict=gaugeDict, exporters=(hddTempExporter, cpuFanTempExporter, powerStripLivingroomExporter, powerStripAtticExporter)) - schedule.every(60).seconds.do(exportData, gaugeDict=gaugeDict, exporters=(t315Atticexporter,)) - - ## Start Prometheus server - prometheusServerPort = configs.get("port", DEFAULT_PORT) - log(f"Start Prometheus server on port {prometheusServerPort}") - start_http_server(prometheusServerPort) if ENABLE_EXPORTER else None - while True: - try: - schedule.run_pending() - time.sleep(1) - except KeyboardInterrupt: - log("User stopped process.") - break - - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument("-p", "--port", type=int, default=DEFAULT_PORT, help="The port of exportor") - parser.add_argument("-i", "--polling_interval", type=int, default=DEFAULT_POLLING_INTERVAL, help="Polling interval for collect HDD temperature") - parser.add_argument("-f", "--secrect_file", default=".secret", help="The file that contains the secrets") - args = parser.parse_args() - DEFAULT_CONFIGS["port"] = args.port - DEFAULT_CONFIGS["polling_interval"] = args.polling_interval - DEFAULT_CONFIGS["secret_filepath"] = args.secrect_file - main(DEFAULT_CONFIGS)