zu socket
This commit is contained in:
102
mmp_logger.py
Normal file → Executable file
102
mmp_logger.py
Normal file → Executable file
@ -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()
|
||||
|
||||
Reference in New Issue
Block a user