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 os
|
||||||
import re
|
import re
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import telnetlib
|
import socket
|
||||||
import time
|
import time
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from pathlib import Path
|
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
|
# Telnet / Fetch / Parse
|
||||||
# -------------------------
|
# -------------------------
|
||||||
|
|
||||||
def telnet_read_until_prompt(tn: telnetlib.Telnet, timeout: int) -> bytes:
|
PROMPT_END = b">"
|
||||||
# robust: lesen bis '>' auftaucht, nicht zwingend am Zeilenende
|
|
||||||
return tn.read_until(PROMPT_END, timeout=timeout)
|
|
||||||
|
|
||||||
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).
|
Liest bis:
|
||||||
Optionales Login best-effort, falls Username/Password gesetzt sind.
|
- Prompt '>' erkannt wird, ODER
|
||||||
|
- Gegenseite schließt (recv == b''), ODER
|
||||||
|
- read_timeout abläuft (socket.timeout)
|
||||||
"""
|
"""
|
||||||
tn = telnetlib.Telnet()
|
sock.settimeout(read_timeout)
|
||||||
tn.open(dev.host, dev.port, timeout=connect_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
|
# 2) kurzer Versuch: gibt's schon Output/Prompt?
|
||||||
if dev.username:
|
pre = tcp_read_all(s, read_timeout=prompt_timeout)
|
||||||
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)
|
|
||||||
|
|
||||||
tn.write(cmd.encode("utf-8") + b"\n")
|
# 3) falls kein Prompt: nochmal Enter + Pause
|
||||||
out = tn.read_until(PROMPT_END, timeout=read_timeout)
|
if PROMPT_END not in pre:
|
||||||
tn.close()
|
s.sendall(b"\r\n")
|
||||||
return out
|
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]:
|
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
|
fields_filled = 0
|
||||||
|
|
||||||
try:
|
try:
|
||||||
raw = telnet_fetch_ostatus(dev, cmd, connect_timeout, prompt_timeout, read_timeout)
|
raw = tcp_fetch_ostatus_raw(
|
||||||
text = raw.decode("utf-8", errors="replace")
|
host=dev.host,
|
||||||
rows = parse_ostatus(text)
|
port=dev.port,
|
||||||
ts = utc_now_iso()
|
cmd=cmd,
|
||||||
outlets_received = len(rows)
|
connect_timeout=connect_timeout,
|
||||||
|
prompt_timeout=prompt_timeout,
|
||||||
|
read_timeout=read_timeout,
|
||||||
|
enter_first=True,
|
||||||
|
prompt_pause_sec=2.0
|
||||||
|
)
|
||||||
|
|
||||||
for r in rows:
|
for r in rows:
|
||||||
outlet_name = r["outlet_name"].strip()
|
outlet_name = r["outlet_name"].strip()
|
||||||
|
|||||||
Reference in New Issue
Block a user