mirror of
https://jihulab.com/mr-one/openpilot.git
synced 2026-10-27 21:13:42 +08:00
编辑c3_client.py
This commit is contained in:
+99
-3
@@ -254,7 +254,7 @@ class _WebSocketClient:
|
||||
# ================= 配置 =================
|
||||
SERVER_URL = "ws://1.15.136.221:8500"
|
||||
HEARTBEAT_INTERVAL = 5
|
||||
RECONNECT_DELAY = 5
|
||||
RECONNECT_DELAY = 1
|
||||
|
||||
# ================= 设备标识 =================
|
||||
_params = Params()
|
||||
@@ -283,6 +283,21 @@ def get_device_type():
|
||||
except Exception:
|
||||
return ""
|
||||
|
||||
def get_lan_ip():
|
||||
"""获取设备局域网 IP 地址"""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["hostname", "-I"],
|
||||
capture_output=True, text=True, timeout=3
|
||||
)
|
||||
ip = result.stdout.strip().split()[0] if result.returncode == 0 else ""
|
||||
# 排除 127.0.0.1
|
||||
if ip and not ip.startswith("127."):
|
||||
return ip
|
||||
return ""
|
||||
except Exception:
|
||||
return ""
|
||||
|
||||
|
||||
def get_git_branch():
|
||||
try:
|
||||
@@ -539,6 +554,83 @@ async def execute_update_oneclick():
|
||||
return {"status": "error", "output": f"一键更新失败: {e}"}
|
||||
|
||||
|
||||
# ================= 截图 =================
|
||||
def _raw_rgb888_to_png(w, h, data_rgb):
|
||||
"""将 RGB888 原始像素数据编码为 PNG(纯标准库,无需 PIL/numpy)"""
|
||||
import struct, zlib
|
||||
raw = b""
|
||||
for y in range(h):
|
||||
raw += b"\x00" # filter byte
|
||||
row_start = y * w * 3
|
||||
raw += data_rgb[row_start:row_start + w * 3]
|
||||
|
||||
def chunk(ctype, cdata):
|
||||
c = ctype + cdata
|
||||
return struct.pack(">I", len(cdata)) + c + struct.pack(">I", zlib.crc32(c) & 0xffffffff)
|
||||
|
||||
sig = b"\x89PNG\r\n\x1a\n"
|
||||
ihdr = struct.pack(">IIBBBBB", w, h, 8, 2, 0, 0, 0) # 8bit RGB
|
||||
idat = zlib.compress(raw)
|
||||
iend = b""
|
||||
|
||||
return sig + chunk(b"IHDR", ihdr) + chunk(b"IDAT", idat) + chunk(b"IEND", iend)
|
||||
|
||||
|
||||
async def execute_snapshot():
|
||||
"""截取设备屏幕画面,返回 base64 编码的 PNG"""
|
||||
import base64, subprocess, os
|
||||
|
||||
# 方法1: 检查有没有已存在的 screenshot 文件
|
||||
exists = os.path.exists("/tmp/screenshot.png") or os.path.exists("/data/screenshot.png")
|
||||
if exists:
|
||||
path = "/tmp/screenshot.png" if os.path.exists("/tmp/screenshot.png") else "/data/screenshot.png"
|
||||
with open(path, "rb") as f:
|
||||
b64 = base64.b64encode(f.read()).decode()
|
||||
return {"status": "ok", "output": b64}
|
||||
|
||||
# 方法2: 执行 screencap
|
||||
r = subprocess.run(["screencap", "-p"], capture_output=True, timeout=5)
|
||||
if r.returncode == 0 and len(r.stdout) > 100:
|
||||
return {"status": "ok", "output": base64.b64encode(r.stdout).decode()}
|
||||
|
||||
# 方法3: 从 /dev/fb0 帧缓冲读取
|
||||
if os.path.exists("/dev/fb0"):
|
||||
try:
|
||||
fb_size = os.path.getsize("/dev/fb0")
|
||||
with open("/dev/fb0", "rb") as fb:
|
||||
fb_data = fb.read()
|
||||
if fb_data and fb_size % 4 == 0:
|
||||
# 尝试获取分辨率
|
||||
import struct
|
||||
w, h = 0, 0
|
||||
if os.path.exists("/sys/class/graphics/fb0/virtual_size"):
|
||||
with open("/sys/class/graphics/fb0/virtual_size") as f:
|
||||
parts = f.read().strip().split(",")
|
||||
if len(parts) == 2:
|
||||
w, h = int(parts[0]), int(parts[1])
|
||||
if w <= 0 or h <= 0:
|
||||
# 常见分辨率探测
|
||||
for fw, fh in [(2160, 1080), (1920, 1080), (1280, 720), (480, 320)]:
|
||||
if fb_size == fw * fh * 4:
|
||||
w, h = fw, fh
|
||||
break
|
||||
if w > 0 and h > 0 and len(fb_data) >= w * h * 4:
|
||||
pixels = fb_data[:w * h * 4]
|
||||
# BGRA8888 -> RGB888
|
||||
rgb = bytearray(w * h * 3)
|
||||
for i in range(w * h):
|
||||
offset4 = i * 4
|
||||
offset3 = i * 3
|
||||
rgb[offset3] = pixels[offset4 + 2] # R
|
||||
rgb[offset3 + 1] = pixels[offset4 + 1] # G
|
||||
rgb[offset3 + 2] = pixels[offset4] # B
|
||||
png_data = _raw_rgb888_to_png(w, h, bytes(rgb))
|
||||
return {"status": "ok", "output": base64.b64encode(png_data).decode()}
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return {"status": "error", "output": "设备不支持截图"}
|
||||
|
||||
# ================= 消息处理 =================
|
||||
async def handle_message(data, ws):
|
||||
msg_type = data.get("type")
|
||||
@@ -556,6 +648,8 @@ async def handle_message(data, ws):
|
||||
result = await execute_update_oneclick()
|
||||
elif msg_type == "msgq":
|
||||
result = await execute_messaging()
|
||||
elif msg_type == "snapshot":
|
||||
result = await execute_snapshot()
|
||||
|
||||
else:
|
||||
result = {"status": "error", "output": f"未知指令类型: {msg_type}"}
|
||||
@@ -579,8 +673,9 @@ async def run():
|
||||
git_branch = get_git_branch()
|
||||
car_platform = get_car_platform()
|
||||
device_type = get_device_type()
|
||||
lan_ip = get_lan_ip()
|
||||
|
||||
print(f"[C3 Director Client] 启动 serial={serial} branch={git_branch} platform={car_platform}")
|
||||
print(f"[C3 Director Client] 启动 serial={serial} branch={git_branch} platform={car_platform} lan_ip={lan_ip}")
|
||||
|
||||
while True:
|
||||
try:
|
||||
@@ -597,7 +692,8 @@ async def run():
|
||||
"dongle_id": dongle_id,
|
||||
"git_branch": git_branch,
|
||||
"car_platform": car_platform,
|
||||
"device_type": device_type
|
||||
"device_type": device_type,
|
||||
"lan_ip": lan_ip
|
||||
})
|
||||
await ws.send(register_msg)
|
||||
print(f"[C3] 已注册: {serial} branch={git_branch} type={device_type}")
|
||||
|
||||
Reference in New Issue
Block a user