From a84497eb3227f5a949fb2a22187b864239df99d5 Mon Sep 17 00:00:00 2001 From: rpwolff Date: Sun, 8 Feb 2026 20:01:06 +0100 Subject: [PATCH] zu socket --- mmp_logger.py | 102 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 72 insertions(+), 30 deletions(-) mode change 100644 => 100755 mmp_logger.py diff --git a/mmp_logger.py b/mmp_logger.py old mode 100644 new mode 100755 index fe39879..b3609f7 --- a/mmp_logger.py +++ b/mmp_logger.py @@ -7,7 +7,7 @@ import json import os import re import sqlite3 -import telnetlib +import socket import time from dataclasses import dataclass from pathlib import Path @@ -207,36 +207,73 @@ def cost_center_for(outlet_name: str, cc_map: Dict[str, str]) -> Tuple[str, str] # Telnet / Fetch / Parse # ------------------------- -def telnet_read_until_prompt(tn: telnetlib.Telnet, timeout: int) -> bytes: - # robust: lesen bis '>' auftaucht, nicht zwingend am Zeilenende - return tn.read_until(PROMPT_END, timeout=timeout) +PROMPT_END = b">" -def telnet_fetch_ostatus(dev: DeviceCfg, cmd: str, connect_timeout: int, prompt_timeout: int, read_timeout: int) -> bytes: +def tcp_read_all(sock: socket.socket, read_timeout: int) -> bytes: """ - Öffnet Telnet, wartet auf Prompt ('>'), sendet cmd, liest Antwort (bis nächstes Prompt). - Optionales Login best-effort, falls Username/Password gesetzt sind. + Liest bis: + - Prompt '>' erkannt wird, ODER + - Gegenseite schließt (recv == b''), ODER + - read_timeout abläuft (socket.timeout) """ - tn = telnetlib.Telnet() - tn.open(dev.host, dev.port, timeout=connect_timeout) + sock.settimeout(read_timeout) + buf = bytearray() + while True: + try: + chunk = sock.recv(4096) + except socket.timeout: + break + if not chunk: + # Session geschlossen + break + buf += chunk + # Prompt irgendwo im Buffer? + if PROMPT_END in buf: + break + return bytes(buf) - buf = telnet_read_until_prompt(tn, timeout=prompt_timeout) +def tcp_fetch_ostatus_raw( + host: str, + port: int, + cmd: str, + connect_timeout: int, + prompt_timeout: int, + read_timeout: int, + enter_first: bool = True, + prompt_pause_sec: float = 2.0, + cmd_pause_sec: float = 0.2, +) -> bytes: + """ + Raw TCP (seriell->TCP). Ablauf: + 1) connect + 2) optional: ENTER senden, kurz warten + 3) kurz lesen (prompt_timeout) + - falls kein '>' kommt: nochmal ENTER, Pause + 4) cmd senden, kurze Pause + 5) lesen bis prompt / close / timeout + """ + with socket.create_connection((host, port), timeout=connect_timeout) as s: + # 1) "Session wecken" + if enter_first: + s.sendall(b"\r\n") + time.sleep(prompt_pause_sec) - # Best-effort login flow - if dev.username: - low = buf.lower() - if b"login" in low or b"user" in low: - tn.write(dev.username.encode("utf-8") + b"\n") - buf = telnet_read_until_prompt(tn, timeout=prompt_timeout) - if dev.password: - low = buf.lower() - if b"pass" in low: - tn.write(dev.password.encode("utf-8") + b"\n") - buf = telnet_read_until_prompt(tn, timeout=prompt_timeout) + # 2) kurzer Versuch: gibt's schon Output/Prompt? + pre = tcp_read_all(s, read_timeout=prompt_timeout) - tn.write(cmd.encode("utf-8") + b"\n") - out = tn.read_until(PROMPT_END, timeout=read_timeout) - tn.close() - return out + # 3) falls kein Prompt: nochmal Enter + Pause + if PROMPT_END not in pre: + s.sendall(b"\r\n") + time.sleep(prompt_pause_sec) + pre += tcp_read_all(s, read_timeout=prompt_timeout) + + # 4) Kommando senden + s.sendall(cmd.encode("utf-8") + b"\r\n") + time.sleep(cmd_pause_sec) + + # 5) Antwort lesen (Bridge kann danach schließen) + out = tcp_read_all(s, read_timeout=read_timeout) + return pre + out def parse_ostatus(text: str) -> List[dict]: """ @@ -317,11 +354,16 @@ def poll_device(con: sqlite3.Connection, dev: DeviceCfg, cc_map: Dict[str, str], fields_filled = 0 try: - raw = telnet_fetch_ostatus(dev, cmd, connect_timeout, prompt_timeout, read_timeout) - text = raw.decode("utf-8", errors="replace") - rows = parse_ostatus(text) - ts = utc_now_iso() - outlets_received = len(rows) + raw = tcp_fetch_ostatus_raw( + host=dev.host, + port=dev.port, + cmd=cmd, + connect_timeout=connect_timeout, + prompt_timeout=prompt_timeout, + read_timeout=read_timeout, + enter_first=True, + prompt_pause_sec=2.0 + ) for r in rows: outlet_name = r["outlet_name"].strip()