agrobot_base/Python/raspi/multispectral_service.py

147 lines
4.0 KiB
Python

import socket
import json
import numpy as np
import base64
import time
class MultiSpectralService:
def __init__(self, host="192.168.105.6", port=5000, timeout=5):
self.host = host
self.port = port
self.timeout = timeout
self.sock = None
self.file = None
def __enter__(self):
self.connect()
return self
def __exit__(self, exc_type, exc, tb):
self.disconnect()
def connect(self):
if self.sock is not None:
return
self.sock = socket.create_connection((self.host, self.port), timeout=self.timeout)
self.sock.settimeout(self.timeout)
self.file = self.sock.makefile("r", encoding="utf-8")
def disconnect(self):
try:
if self.file:
self.file.close()
except:
pass
try:
if self.sock:
self.sock.close()
except:
pass
self.file = None
self.sock = None
def _send_command(self, payload: dict) -> dict:
if self.sock is None:
self.connect()
data = (json.dumps(payload) + "\n").encode("utf-8")
self.sock.sendall(data)
line = self.file.readline()
if not line:
self.disconnect()
raise RuntimeError("Conexão encerrada pelo servidor")
return json.loads(line.strip())
def ping(self):
return self._send_command({"cmd": "ping"})
def get_status(self):
return self._send_command({"cmd": "get_status"})
def get_config(self):
return self._send_command({"cmd": "get_config"})
def begin(self):
return self._send_command({"cmd": "begin"})
def stop(self):
return self._send_command({"cmd": "stop"})
def set_fps(self, fps: int):
return self._send_command({"cmd": "set_fps", "value": fps})
def set_jpeg_quality(self, quality: int):
return self._send_command({"cmd": "set_jpeg_quality", "value": quality})
def set_resolution(self, width: int, height: int):
return self._send_command({
"cmd": "set_resolution",
"width": width,
"height": height
})
def capture_jpg_disk(self):
return self._send_command({"cmd": "capture_jpg_disk"})
def capture_jpg_bytes(self):
return self._send_command({"cmd": "capture_jpg_bytes"})
def capture_jpg_base64(self):
resp = self._send_command({"cmd": "capture_jpg_base64"})
if not resp.get("ok"):
raise RuntimeError(resp.get("error", "Falha ao capturar JPG"))
return base64.b64decode(resp["data"])
def capture_frame_array(self):
t0 = time.perf_counter()
resp = self._send_command({"cmd": "capture_frame"})
if not resp.get("ok"):
raise RuntimeError(resp.get("error", "Falha ao capturar frame"))
raw = base64.b64decode(resp["data"])
width = resp["width"]
height = resp["height"]
channels = resp["channels"]
arr = np.frombuffer(raw, dtype=np.uint8).reshape(height, width, channels)
t1 = time.perf_counter()
meta = {
"frame_type": resp.get("frame_type"),
"width": width,
"height": height,
"channels": channels,
"dtype": resp.get("dtype"),
"size": resp.get("size"),
# 👇 TELEMETRIA PI
"ts_pi": resp.get("ts_pi"),
"dt_trigger": resp.get("dt_trigger"),
"dt_settle": resp.get("dt_settle"),
"dt_capture": resp.get("dt_capture"),
"dt_total_pi": resp.get("dt_total_pi"),
# 👇 TELEMETRIA PC
"dt_total_pc": t1 - t0,
}
return arr, meta
def start_stream(self, host: str, port: int, fps: float):
return self._send_command({
"cmd": "start_stream",
"host": host,
"port": port,
"fps": fps
})
def stop_stream(self):
return self._send_command({"cmd": "stop_stream"})