diff --git a/.gitignore b/.gitignore index 0e5ac79..2db7150 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .venv -__pycache__ \ No newline at end of file +__pycache__ +alerting/credentials.json diff --git a/README.md b/README.md index 94cbb2d..afdbfa8 100644 --- a/README.md +++ b/README.md @@ -1 +1,17 @@ # lego-monitoring + +## Prerequisites + +* `pacman -S libolm` +* `pip -r requirements.txt` + +## Configuring + +* Run `alerting/login.py` once to generate credentials file +* Invite the bot account to the room (you have to accept the invite manually) +* Set room ID in `alerting/common.py` + +## Running + +* `prettyprint.py` -- check and print all sensors +* TODO -- launch service diff --git a/alerting/alerts.py b/alerting/alerts.py new file mode 100644 index 0000000..15f0716 --- /dev/null +++ b/alerting/alerts.py @@ -0,0 +1,78 @@ +import json +from dataclasses import dataclass +from enum import Enum, StrEnum +from typing import Optional + +import aiofiles +import nio + +from alerting.common import CREDS_FILE, ROOM_ID + + +class AlertType(StrEnum): + TEST = "TEST" + RAM = "RAM" # TODO + CPU = "CPU" # TODO + TEMP = "TEMP" # TODO + LOGIN = "LOGIN" # TODO + SMART = "SMART" # TODO + RAID = "RAID" # TODO + + +class Severity(Enum): + INFO = 1 + WARNING = 2 + CRITICAL = 3 + + +@dataclass +class Alert: + alert_type: AlertType + message: str + severity: Severity + + +async def get_client() -> nio.AsyncClient: + """ + Returns a Matrix client. + It is better to call get_client once and use it for multiple send_alert calls + """ + async with aiofiles.open(CREDS_FILE) as f: + contents = await f.read() + creds = json.loads(contents) + client = nio.AsyncClient(creds["homeserver"]) + client.access_token = creds["access_token"] + client.user_id = creds["user_id"] + client.device_id = creds["device_id"] + return client + + +def format_message(alert: Alert) -> str: + match alert.severity: + case Severity.INFO: + severity_emoji = "â„šī¸" + case Severity.WARNING: + severity_emoji = "âš ī¸" + case Severity.CRITICAL: + severity_emoji = "🆘" + message = f"{severity_emoji} {alert.alert_type} Alert\n{alert.message}" + return message + + +async def send_alert(alert: Alert, client: Optional[nio.AsyncClient] = None) -> None: + if client is None: + temp_client = True + client = await get_client() + else: + temp_client = False + message = format_message(alert) + await client.room_send( + room_id=ROOM_ID, + message_type="m.room.message", + content={ + "msgtype": "m.text", + "body": message, + }, + ) + if temp_client: + await client.close() diff --git a/alerting/common.py b/alerting/common.py new file mode 100644 index 0000000..15d517b --- /dev/null +++ b/alerting/common.py @@ -0,0 +1,8 @@ +import os +from pathlib import Path + +CREDS_FILE = (Path(os.path.dirname(os.path.realpath(__file__))) / "credentials.json").resolve() +HOMESERVER = "https://matrix.altau.su" +USER_ID = "@AlertBot:altau.su" +DEVICE_NAME = "lego" +ROOM_ID = "!aSCaiSJfLHslrJrHiJ:altau.su" diff --git a/alerting/login.py b/alerting/login.py new file mode 100755 index 0000000..05581df --- /dev/null +++ b/alerting/login.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 + +import asyncio +import getpass +import json +import os + +from common import CREDS_FILE, DEVICE_NAME, HOMESERVER, USER_ID +from nio import AsyncClient, LoginResponse + + +async def main() -> None: + if os.path.exists(CREDS_FILE): + print(f"Creds already configured in {CREDS_FILE}") + raise SystemExit + + client = AsyncClient(HOMESERVER, USER_ID) + password = getpass.getpass() + resp = await client.login(password, device_name=DEVICE_NAME) + await client.close() + if isinstance(resp, LoginResponse): + open(CREDS_FILE, "w").close() + os.chmod(CREDS_FILE, 0o600) + with open(CREDS_FILE, "w") as f: + json.dump( + { + "homeserver": HOMESERVER, + "user_id": resp.user_id, + "device_id": resp.device_id, + "access_token": resp.access_token, + }, + f, + ) + print(f"Logged in as {resp.user_id}. Credentials saved to {CREDS_FILE}") + else: + raise Exception(f"Failed to log in: {resp}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/requirements.txt b/requirements.txt index 69c8e04..ac76115 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ colorama==0.4.6 psutil==5.9.8 +matrix-nio[e2e]==0.24.0