From 110ef12320a85f006168f370180652ba3291dcd8 Mon Sep 17 00:00:00 2001 From: linyimin <18316471919@139.com> Date: Tue, 22 Sep 2026 10:33:52 +0800 Subject: [PATCH] =?UTF-8?q?feat:=201.json=E6=8D=A2=E4=B8=BApb=202.wifi?= =?UTF-8?q?=E3=80=81ota=20=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.yaml | 3 +- ...y_netcore.cpython-311-riscv64-linux-gnu.so | Bin 180512 -> 205272 bytes config.py | 4 +- main.py | 120 +- network.py | 769 +++++----- ota_manager.py | 1318 ++--------------- tcp_messages_pb2.py | 332 +++-- version.py | 2 +- 8 files changed, 868 insertions(+), 1680 deletions(-) diff --git a/app.yaml b/app.yaml index 3cecb59..c54e599 100644 --- a/app.yaml +++ b/app.yaml @@ -1,6 +1,6 @@ id: t11 name: t11 -version: 3.0.5 +version: 3.1.15 author: t11 icon: '' desc: t11 @@ -29,6 +29,7 @@ files: - shoot_manager.py - shot_id_generator.py - target_roi_yolo.py + - tcp_messages_pb2.py - time_sync.py - triangle_positions.json - triangle_target.py diff --git a/archery_netcore.cpython-311-riscv64-linux-gnu.so b/archery_netcore.cpython-311-riscv64-linux-gnu.so index 6c1ca031dedcd00d8ca4aa73d18a877f3ba1110f..187485c9317f1445d67fdd421b152788145597a9 100644 GIT binary patch literal 205272 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

Xn; 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­{3uEYOQt1s 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

DdD`Ys(0Onx*@pt16F1hQwF{@Y#eK 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 diff --git a/config.py b/config.py index 85474ad..c0dff24 100644 --- a/config.py +++ b/config.py @@ -50,7 +50,7 @@ WIFI_CONFIG_AP_IP = "192.168.66.1" # 与 MaixPy Wifi.start_ap 默认一 # ===== TCP over SSL(TLS) 配置 ===== USE_TCP_SSL = True # True=按手册走 MSSLCFG/MIPCFG 绑定 SSL TCP_LINK_ID = 2 # -TCP_SSL_PORT = 50006 # TLS 端口(不一定必须 443,以服务器为准) +TCP_SSL_PORT = 50007 # TLS 端口(不一定必须 443,以服务器为准) # SSL profile SSL_ID = 1 # ssl_id=1 @@ -362,7 +362,7 @@ PIN_MAPPINGS = { } # ==================== 电源配置 ==================== -AUTO_POWER_OFF_IN_SECONDS = 10 * 60 # 自动关机时间(秒),0表示不自动关机 +AUTO_POWER_OFF_IN_SECONDS = 100 * 60 # 自动关机时间(秒),0表示不自动关机 # 充电时自动关机暂时禁用;需要恢复时改为 True。 CHARGING_AUTO_POWER_OFF_ENABLED = False diff --git a/main.py b/main.py index 1822dfc..4480e66 100644 --- a/main.py +++ b/main.py @@ -13,7 +13,9 @@ from maix import camera, display, image, app, time, uart, pinmap, i2c from maix.peripheral import adc import _thread import os +import sys import json +import shutil import time as wall_time # 导入新模块 @@ -126,7 +128,7 @@ def cmd_str(): # 1. 初始化日志系统(WARNING级别,不打印/写入INFO和DEBUG日志,提高执行流畅度) import logging - logger_manager.init_logging(log_level=logging.WARNING) + logger_manager.init_logging(log_level=logging.DEBUG) logger = logger_manager.logger # 补充:因为初始化的时候,激光会亮,先关了它 @@ -254,6 +256,55 @@ def cmd_str(): # 4. 初始化设备ID(network_manager 内部会自动设置 device_id 和 password) network_manager.read_device_id() + # 4.1 检查是否有 OTA 待更新文件(从临时目录移动到实际目录) + staging_dir = f"{config.APP_DIR}/ota_staging" + if os.path.exists(staging_dir): + try: + moved_count = 0 + for root, dirs, files in os.walk(staging_dir): + for f in files: + src = os.path.join(root, f) + rel = os.path.relpath(src, staging_dir) + dest = os.path.join(config.APP_DIR, rel) + dest_dir = os.path.dirname(dest) + if dest_dir: + try: + os.makedirs(dest_dir, exist_ok=True) + except: + pass + try: + shutil.copy2(src, dest) + moved_count += 1 + except Exception as e: + if logger: + logger.error(f"[OTA] 移动文件失败 {rel}: {e}") + # 删除临时目录 + try: + shutil.rmtree(staging_dir, ignore_errors=True) + except: + pass + if logger: + logger.info(f"[OTA] 已从临时目录更新 {moved_count} 个文件,重启应用...") + # 清理硬件资源,然后重启应用 + try: + laser_manager.turn_off_laser() + except: + pass + try: + camera_manager.release() + except: + pass + try: + os.sync() + except: + pass + import sys + os.execv(sys.executable, [sys.executable, os.path.join(config.APP_DIR, "main.py")]) + return + except Exception as e: + if logger: + logger.error(f"[OTA] 处理临时目录失败: {e}") + # 5. 创建照片存储目录(如果启用图像保存或检测失败时强制保存) if config.SAVE_IMAGE_ENABLED or getattr(config, "SAVE_IMAGE_ON_FAILURE", False): photo_dir = config.PHOTO_DIR @@ -290,6 +341,7 @@ def cmd_str(): trigger_adc_val = 0 # 触发时的气压值,气压需降回此值以下才能再次触发 # 读取一次ADC初始值,防止开机时传感器已有压力导致误触发 enable_check = True + _should_reboot = False try: last_adc_val = hardware_manager.adc_obj.read() except Exception: @@ -345,6 +397,14 @@ def cmd_str(): time.sleep_ms(250) continue + # OTA 完成后需要重启,从主循环退出(由启动时 staging 检测处理重启) + if network_manager.ota_restart_pending: + network_manager.ota_restart_pending = False + _should_reboot = True + if logger: + logger.info("[MAIN] OTA重启标志已设置,退出主循环...") + break + # 不在 OTA 状态下,检测是否空闲足够长,自动关机 # print(f"[MAIN] 空闲时间: {hardware_manager.get_idle_time_in_sec() }秒") # print(f"配置关机时间:{config.AUTO_POWER_OFF_IN_SECONDS} 秒") @@ -430,10 +490,62 @@ def cmd_str(): _flush_pressure_buf("exception") except: pass - time.sleep_ms(1000) # 等待1秒后继续 - - + time.sleep_ms(1000) # 等待1秒后 continue + # 主循环退出后,如果是由 OTA 触发的,移动 staging 文件并重启应用 + if _should_reboot: + staging_dir = f"{config.APP_DIR}/ota_staging" + if os.path.exists(staging_dir): + try: + moved_count = 0 + for root, dirs, files in os.walk(staging_dir): + for f in files: + src = os.path.join(root, f) + rel = os.path.relpath(src, staging_dir) + dest = os.path.join(config.APP_DIR, rel) + dest_dir = os.path.dirname(dest) + if dest_dir: + try: + os.makedirs(dest_dir, exist_ok=True) + except: + pass + try: + shutil.copy2(src, dest) + moved_count += 1 + except Exception as e: + if logger: + logger.error(f"[OTA] 移动文件失败 {rel}: {e}") + try: + shutil.rmtree(staging_dir, ignore_errors=True) + except: + pass + if logger: + logger.info(f"[MAIN] OTA 更新完成,已应用 {moved_count} 个文件,重启应用...") + except Exception as e: + if logger: + logger.error(f"[OTA] 处理 staging 目录失败: {e}") + else: + if logger: + logger.info("[MAIN] OTA 更新完成,重启应用...") + # 清理硬件资源,然后重启应用(不重启设备) + try: + laser_manager.turn_off_laser() + except: + pass + try: + camera_manager.release() + except: + pass + try: + hardware_manager.stop_idle_timer() + except: + pass + try: + os.sync() + except: + pass + import sys + os.execv(sys.executable, [sys.executable, os.path.join(config.APP_DIR, "main.py")]) # 主程序入口 diff --git a/network.py b/network.py index 66b77df..8777486 100644 --- a/network.py +++ b/network.py @@ -13,6 +13,7 @@ import hmac import hashlib import ujson import os +import sys import threading import socket import config @@ -21,15 +22,13 @@ from hardware import hardware_manager from power import get_bus_voltage, voltage_to_percent, is_charging from logger_manager import logger_manager from wifi import wifi_manager -import subprocess -# protobuf 支持 +# protobuf 支持(纯 proto 协议,必须可用) try: import tcp_messages_pb2 as pb - _HAS_PROTO = True except ImportError: - _HAS_PROTO = False print("[NET] tcp_messages_pb2 not found, protobuf disabled") + raise def _wifi_tls_would_block(exc): @@ -77,11 +76,17 @@ class NetworkManager: self._uart4g_lock = threading.Lock() self._device_id = None self._password = None - self._raw_line_data = [] + self._manual_trigger_flag = False - # protobuf 协议支持 - self._use_proto = _HAS_PROTO # 默认启用 proto(如果可用) + # OTA 防重复:上次 OTA 完成时间戳,30秒内不重复 OTA + self._last_ota_time = 0 + self._ota_cooldown_sec = 30 + + # OTA 重启标志:OTA线程设置,主循环检测到后从主循环退出再重启 + self.ota_restart_pending = False + + # protobuf 协议(纯 proto,无 JSON 兼容) # 限制并发命令线程数 self._cmd_thread_lock = threading.Lock() @@ -201,13 +206,7 @@ class NetworkManager: return self._normal_send_queue.pop(0) return None - def _set_raw_line_data(self, data): - """设置原始行数据(内部方法)""" - self._raw_line_data = data - def _get_raw_line_data(self): - """获取原始行数据(内部方法)""" - return self._raw_line_data def get_uart_lock(self): """获取UART锁(用于with语句)""" @@ -626,53 +625,113 @@ class NetworkManager: except Exception as e: self.logger.error(f"[LASER] cmd200 检测异常: {e}") + def _cmd5_ota(self, ota_url): + """后台线程执行 cmd5 OTA""" + hardware_manager.start_idle_timer() + self.logger.info(f"[Ota] cmd5 开始OTA: {ota_url}") + self.safe_enqueue({"result": "ota start..."}, 2) + + try: + from ota_manager import ota_manager + ok, msg = ota_manager.perform_ota(ota_url) + if ok: + self.safe_enqueue({"result": "success"}, 2) + time.sleep_ms(500) + os.execv(sys.executable, [sys.executable, os.path.join(config.APP_DIR, "main.py")]) + else: + self.logger.error(f"[ota] cmd5 失败: {msg}") + self.safe_enqueue({"result": "ota fail", "reason": msg}, 2) + except Exception as e: + self.logger.error(f"[ota] cmd5 异常: {e}") + self.safe_enqueue({"result": "ota fail", "reason": str(e)}, 2) + def _cmd300_ota(self, data_obj): - """后台线程执行 cmd300 OTA,避免阻塞主循环""" + """后台线程执行 cmd300 OTA,避免阻塞主循环 + 流程:检查WiFi → 下载ZIP → 解压覆盖项目 → 重启程序 + """ hardware_manager.start_idle_timer() inner_data = data_obj.get("data", {}) if isinstance(data_obj, dict) else {} self.logger.info(f"[New Ota] cmd300 , data: {inner_data}") - ssid = inner_data.get("ssid") - password = inner_data.get("password") ota_res_url = inner_data.get("url") - try: - for _f in ("/etc/wpa_supplicant.conf", "/boot/wpa_supplicant.conf", "/boot/wifi.ssid", "/boot/wifi.pass"): + + if not ota_res_url: + self.logger.error("[ota] cmd300 缺少 url 参数") + self.safe_enqueue({"cmd": 300, "result": "ota fail", "reason": "missing url"}, 2) + return + + # OTA 冷却期检查:防止服务器重复下发导致无限 OTA 循环 + now = time.time() + if self._last_ota_time > 0: + elapsed = int(now - self._last_ota_time) + if elapsed < self._ota_cooldown_sec: + remaining = self._ota_cooldown_sec - elapsed + self.logger.warning(f"[ota] cmd300 冷却期内,跳过 (剩余 {remaining}s)") try: - os.remove(_f) - except OSError: + pkt = self._make_send_packet(2, {"cmd": 300, "result": "ota skip", "reason": f"cooldown {remaining}s"}) + self.tcp_send_raw(pkt) + except Exception: pass - w = network.wifi.Wifi() - e = w.connect(ssid, password, wait=True, timeout=15) - err.check_raise(e, "connect wifi failed") - if self.logger: - self.logger.info(f"[ota] Connect success, got ip{w.get_ip()}") - self.safe_enqueue( - { + return + + if not wifi_manager.is_wifi_connected(): + self.logger.warning("[ota] cmd300 当前未连接WiFi,拒绝OTA") + self.safe_enqueue({"cmd": 300, "result": "ota fail", "reason": "wifi not connected"}, 2) + return + + self.logger.info(f"[ota] WiFi已连接,开始OTA: {ota_res_url}") + self.safe_enqueue({"cmd": 300, "result": "ota start..."}, 2) + + def _ota_progress(phase, progress): + """OTA进度回调,通过tcp_send_raw直接发送(绕过被暂停的发送队列)""" + try: + if not self._tcp_connected: + self.logger.warning(f"[ota] 进度发送跳过: tcp未连接 phase={phase} progress={progress}") + return + pkt = self._make_send_packet(2, { "cmd": 300, - "result": "ota start...", - "wifi": w.get_ip(), - }, - 2, - ) - subprocess.run( - ["sh", "/maixapp/apps/t11/ota_curl.sh", ota_res_url]) - self.safe_enqueue( - { - "cmd": 300, - "result": "success", - "wifi": w.get_ip(), - }, - 2, - ) + "result": f"ota {phase}", + "progress": progress, + "phase": phase, + }) + ok = self.tcp_send_raw(pkt) + if not ok: + self.logger.warning(f"[ota] 进度发送失败: phase={phase} progress={progress}") + except Exception as e: + self.logger.error(f"[ota] 发送进度异常: {e}") + + try: + from ota_manager import ota_manager + ok, msg = ota_manager.perform_ota(ota_res_url, progress_callback=_ota_progress) + self._last_ota_time = time.time() + if ok: + self.logger.info("[ota] OTA成功,准备重启程序...") + # 直接通过tcp发送success,不走发送队列(主循环可能未drain) + try: + pkt = self._make_send_packet(2, {"cmd": 300, "result": "success", "progress": 51, "phase": "rebooting"}) + ok_send = self.tcp_send_raw(pkt) + self.logger.info(f"[ota] success包发送结果: {ok_send}, tcp_connected={self._tcp_connected}") + except Exception as e: + self.logger.error(f"[ota] 发送success失败: {e}") + # 设置重启标志,由主循环检测到后从主循环退出再重启 + # (后台线程调 os.execv 会导致 ISP 线程残留,新进程摄像头初始化失败) + self.logger.info("[ota] 设置重启标志,等待主循环退出...") + self.ota_restart_pending = True + else: + self.logger.error(f"[ota] cmd300 失败: {msg}") + self._last_ota_time = time.time() + try: + pkt = self._make_send_packet(2, {"cmd": 300, "result": "ota fail", "reason": msg}) + self.tcp_send_raw(pkt) + except Exception as e: + self.logger.error(f"[ota] 发送失败结果异常: {e}") except Exception as e: - self.logger.error(f"[ota] cmd300 失败: {e}") - self.safe_enqueue( - { - "cmd": 300, - "result": "ota fail", - "reason": str(e), - }, - 2, - ) + self.logger.error(f"[ota] cmd300 异常: {e}") + self._last_ota_time = time.time() + try: + pkt = self._make_send_packet(2, {"cmd": 300, "result": "ota fail", "reason": str(e)}) + self.tcp_send_raw(pkt) + except Exception as ex: + self.logger.error(f"[ota] 发送失败结果异常: {ex}") def _cmd600_conn_wifi(self, data_obj): hardware_manager.start_idle_timer() @@ -680,6 +739,7 @@ class NetworkManager: self.logger.info(f"[conn wifi] cmd600 , data: {inner_data}") ssid = inner_data.get("ssid") password = inner_data.get("password") + prev_network_type = self._network_type # 停止旧的WiFi质量监测(无论当前是WiFi还是4G连接) self._stop_wifi_quality_monitor() try: @@ -689,18 +749,10 @@ class NetworkManager: except OSError: pass w = network.wifi.Wifi() - e = w.connect(ssid, password, wait=True, timeout=15) + e = w.connect(ssid, password, wait=True, timeout=5) err.check_raise(e, "connect wifi failed") if self.logger: self.logger.info(f"[ota] Connect success, got ip{w.get_ip()}") - self.safe_enqueue( - { - "cmd": 600, - "result": "success", - "wifi": w.get_ip(), - }, - 2, - ) self._session_force_4g = False self.disconnect_server() self._tcp_connected = False @@ -708,102 +760,175 @@ class NetworkManager: self.logger.info("[conn wifi] WiFi已连接,等待主循环重新登录") except Exception as e: self.logger.error(f"cmd600 失败: {e}") - self.safe_enqueue( - { - "cmd": 600, - "result": "conn fail", - "reason": str(e), - }, - 2, - ) - self._switch_to_4g_due_to_poor_wifi() + # 同步发送失败结果(旧连接仍存活时直接发送) + if prev_network_type == "4g": + pkt = self._make_send_packet(2, {"cmd": 600, "result": "conn fail", "reason": str(e)}) + self.tcp_send_raw(pkt) + else: + self.safe_enqueue( + { + "cmd": 600, + "result": "conn fail", + "reason": str(e), + }, + 2, + ) + # 当前是4G在线,旧连接未断,无需切换;当前是WiFi,旧WiFi已被w.connect()断开,需回退4G + if prev_network_type == "wifi": + self._switch_to_4g_due_to_poor_wifi() def safe_enqueue(self, data_dict, msg_type=2, high=False): """线程安全地将消息加入队列(公共方法)""" self._enqueue((msg_type, data_dict), high) def _make_send_packet(self, msg_type, data_dict): - """根据协议模式构造发送数据包""" - if self._use_proto and _HAS_PROTO: - return self._make_proto_packet(msg_type, data_dict) - return self._netcore.make_packet(msg_type, data_dict) + """使用 protobuf 构造发送数据包""" + return self._make_proto_packet(msg_type, data_dict) + + def _build_logic_body(self, cmd, data_dict): + """根据 cmd 构造对应的 LogicBody oneof payload""" + d = data_dict.get("data", data_dict) if isinstance(data_dict.get("data"), dict) else data_dict + + if cmd == 1: + return pb.LogicBody( + cmd=cmd, + shoot_data=pb.ShootData( + shot_id=d.get("shot_id", ""), + x=d.get("x", 0.0), + y=d.get("y", 0.0), + r=d.get("r", 0.0), + d=d.get("d", 0.0), + adc=d.get("adc", 0.0), + target_class=str(d.get("target_class", "")), + target_class_confidence=d.get("target_class_confidence", 0.0), + d_laser=d.get("d_laser", 0.0), + d_laser_quality=d.get("d_laser_quality", 0.0), + m=d.get("m", ""), + laser_method=d.get("laser_method", ""), + target_x=d.get("target_x", 0.0), + target_y=d.get("target_y", 0.0), + offset_method=d.get("offset_method", ""), + distance_method=d.get("distance_method", ""), + ) + ) + elif cmd == 4: + return pb.LogicBody( + cmd=cmd, + battery_report=pb.BatteryReport( + battery=d.get("battery", 0.0), + voltage=d.get("voltage", 0.0), + net_type=d.get("netType", ""), + charging=d.get("charging", False), + ) + ) + elif cmd == 200: + return pb.LogicBody( + cmd=cmd, + center_point_result=pb.CenterPointResult( + result=d.get("result", ""), + x=d.get("x", 0.0), + y=d.get("y", 0.0), + ) + ) + elif cmd == 201: + return pb.LogicBody( + cmd=cmd, + center_point_set=pb.CenterPointSet( + x=d.get("x", 0.0), + y=d.get("y", 0.0), + ) + ) + + elif cmd == 300: + return pb.LogicBody( + cmd=cmd, + ota_result=pb.OtaResult( + result=d.get("result", ""), + url=d.get("wifi", ""), + progress=d.get("progress", 0), + phase=d.get("phase", ""), + ) + ) + elif cmd == 700: + return pb.LogicBody( + cmd=cmd, + charging_report=pb.ChargingReport(), + ) + else: + result_str = d.get("result", "") + if isinstance(result_str, dict): + import ujson + result_str = ujson.dumps(result_str) + elif not isinstance(result_str, str): + result_str = str(result_str) + return pb.LogicBody( + cmd=cmd, + generic_result=pb.GenericResult(result=result_str), + ) def _make_proto_packet(self, msg_type, data_dict): """使用 protobuf 序列化构造数据包""" - try: - if msg_type == 1: - # 登录消息 - msg = pb.LoginRequest( - device_id=data_dict.get("deviceId", ""), - password=data_dict.get("password", ""), - if_admin=data_dict.get("ifAdmin", False), - version=data_dict.get("version", ""), - vol=data_dict.get("vol", 0), - vol_per=data_dict.get("vol_per", 0), - iccid=data_dict.get("iccid", ""), - ) - elif msg_type == 4: - # 心跳消息 - msg = pb.Heartbeat( - t=data_dict.get("t", 0), - vol=data_dict.get("vol", 0), - vol_per=data_dict.get("vol_per", 0), - ) - elif msg_type == 2: - # 业务逻辑消息 - cmd = data_dict.get("cmd", 0) - inner_data = {k: v for k, v in data_dict.items() if k != "cmd"} - data_bytes = json.dumps(inner_data).encode("utf-8") if inner_data else b"" - msg = pb.LogicBody(cmd=cmd, data=data_bytes) - else: - # 其他消息类型,回退到 JSON - return self._netcore.make_packet(msg_type, data_dict) + if msg_type == 1: + msg = pb.LoginRequest( + device_id=data_dict.get("deviceId", ""), + password=data_dict.get("password", ""), + if_admin=data_dict.get("ifAdmin", False), + version=data_dict.get("version", ""), + vol=data_dict.get("vol", 0), + vol_per=data_dict.get("vol_per", 0), + iccid=data_dict.get("iccid", ""), + ) + elif msg_type == 4: + msg = pb.Heartbeat( + t=data_dict.get("t", 0), + vol=data_dict.get("vol", 0), + vol_per=data_dict.get("vol_per", 0), + ) + elif msg_type == 2: + cmd = data_dict.get("cmd", 0) + msg = self._build_logic_body(cmd, data_dict) + else: + return b"" - body_bytes = msg.SerializeToString() - return self._netcore.make_packet_pb(msg_type, body_bytes) - except Exception as e: - self.logger.error(f"[NET] protobuf 序列化失败,回退到 JSON: {e}") - return self._netcore.make_packet(msg_type, data_dict) + body_bytes = msg.SerializeToString() + return self._netcore.make_packet_pb(msg_type, body_bytes) def _parse_recv(self, payload): """解析接收的数据包,返回 (msg_type, body_dict)""" - if self._use_proto and _HAS_PROTO: - msg_type, body_bytes = self._netcore.parse_packet_raw(payload) - if msg_type is None: - return None, None - try: - body_dict = self._parse_proto_body(msg_type, body_bytes) - return msg_type, body_dict - except Exception as e: - self.logger.error(f"[NET] protobuf 反序列化失败: {e}") - # 回退到 JSON 解析 - return self._netcore.parse_packet(payload) - else: - return self._netcore.parse_packet(payload) + msg_type, body_bytes = self._netcore.parse_packet_raw(payload) + if msg_type is None: + return None, None + try: + body_dict = self._parse_proto_body(msg_type, body_bytes) + return msg_type, body_dict + except Exception as e: + self.logger.error(f"[NET] protobuf 反序列化失败: {e}") + return None, None def _parse_proto_body(self, msg_type, body_bytes): """将 protobuf body bytes 反序列化为 dict""" if msg_type == 1: msg = pb.LoginResponse() msg.ParseFromString(body_bytes) - return {"cmd": msg.cmd, "data": msg.data} + return {"cmd": msg.code, "data": msg.msg} elif msg_type == 4: - # 心跳 ACK 通常无 body return {} elif msg_type == 2: msg = pb.LogicBody() msg.ParseFromString(body_bytes) result = {"cmd": msg.cmd} - if msg.data: - try: - result["data"] = json.loads(msg.data.decode("utf-8")) - except: - result["data"] = {"raw": msg.data.hex()} + payload_name = msg.WhichOneof('payload') + if payload_name: + payload_msg = getattr(msg, payload_name) + data = {} + for field in payload_msg.DESCRIPTOR.fields: + val = getattr(payload_msg, field.name) + if isinstance(val, bytes): + val = val.hex() + data[field.name] = val + result["data"] = data return result - elif msg_type == 40: - msg = pb.OtaFragment() - msg.ParseFromString(body_bytes) - return {"l": msg.l, "d": msg.d, "t": msg.t, "v": msg.v} + elif msg_type == 100: msg = pb.ImageUploadCommand() msg.ParseFromString(body_bytes) @@ -813,11 +938,7 @@ class NetworkManager: msg.ParseFromString(body_bytes) return {"uploadUrl": msg.upload_url, "token": msg.token, "key": msg.key, "outlink": msg.outlink, "archive": msg.archive} else: - # 未知类型,尝试 JSON 解析 - try: - return json.loads(body_bytes.decode("utf-8")) - except: - return {"raw": body_bytes.hex()} + return {"raw": body_bytes.hex()} def connect_server(self): """ @@ -1941,6 +2062,11 @@ class NetworkManager: time.sleep_ms(200) continue + # OTA 完成后需要重启,从主循环退出(由 main.py 执行重启) + if self.ota_restart_pending: + self.logger.info("[ota] 主循环退出,准备重启...") + break + if not self.connect_server(): time.sleep_ms(1000) continue @@ -1950,7 +2076,7 @@ class NetworkManager: login_data = { "deviceId": self.device_id, "password": self.password, - "version": config.APP_VERSION + ("+proto" if self._use_proto else ""), + "version": config.APP_VERSION, "vol": vol_val, "vol_per": voltage_to_percent(vol_val) } @@ -1987,6 +2113,10 @@ class NetworkManager: time.sleep_ms(200) continue + # OTA 完成后需要重启,跳出内层循环 + if self.ota_restart_pending: + break + # 接收数据(根据网络类型选择接收方式) # WiFi 粘包:一次 recv 可能含多条完整包;也可能缓冲里已有完整包但本轮 recv 超时为空 rx_items = [] @@ -2037,7 +2167,7 @@ class NetworkManager: # 处理登录响应 if not logged_in and msg_type == 1: - if body and body.get("cmd") == 1 and body.get("data") == "登录成功": + if body and body.get("cmd") == 0 and body.get("data") == "登录成功": logged_in = True last_heartbeat_ack_time = time.ticks_ms() self.logger.info("登录成功") @@ -2068,32 +2198,7 @@ class NetworkManager: last_heartbeat_ack_time = time.ticks_ms() self.logger.debug("✅ 收到心跳确认") - # 处理命令40(分片下载) - elif logged_in and msg_type == 40: - if isinstance(body, dict): - t = body.get('t', 0) - v = body.get('v') - # 如果是第一个分片,清空之前的缓存 - if len(self._raw_line_data) == 0 or ( - len(self._raw_line_data) > 0 and self._raw_line_data[0].get('v') != v): - self._raw_line_data.clear() - # 或者更简单:每次收到命令40时,如果版本号不同,清空缓存 - if len(self._raw_line_data) > 0: - first_v = self._raw_line_data[0].get('v') - if first_v and first_v != v: - self._raw_line_data.clear() - self._raw_line_data.append(body) - if len(self._raw_line_data) >= int(t): - self.logger.info(f"下载完成") - from ota_manager import ota_manager - stock_array = list(map(lambda x: x.get('d'), self._raw_line_data)) - local_filename = config.LOCAL_FILENAME - with open(local_filename, 'w', encoding='utf-8') as file: - file.write("\n".join(stock_array)) - ota_manager.apply_ota_and_reboot(None, local_filename) - else: - self.safe_enqueue({'data': {'l': len(self._raw_line_data), 'v': v}, 'cmd': 41}) - self.logger.info(f"已下载{len(self._raw_line_data)} 全部:{t} 版本:{v}") + elif logged_in and msg_type == 100: self.logger.info(f"[IMAGE_UPLOAD] 收到图片上传命令 {body}") @@ -2186,215 +2291,151 @@ class NetworkManager: ) # 立即返回已入队确认 self.safe_enqueue({"result": "log_upload_queued"}, 2) - elif logged_in and msg_type == 201: - if self.logger: - self.logger.info(f"[LASER] cmd201:{body}") - raw_x = body.get("x") - raw_y = body.get("y") - try: - from laser_manager import laser_manager - ix, iy = laser_manager.set_hardcoded_laser_point( - raw_x, raw_y - ) - self.safe_enqueue( - { - "cmd": 201, - "result": "laser_point_set", - "x": ix, - "y": iy, - }, - 2, - ) - self.logger.info( - f"[LASER] cmd201 硬编码激光点=({ix}, {iy})" - ) - except Exception as e: - self.logger.error(f"[LASER] cmd201 失败: {e}") - self.safe_enqueue( - { - "cmd": 201, - "result": "laser_point_set_failed", - "reason": str(e), - }, - 2, - ) - hardware_manager.start_idle_timer() - # 处理业务指令 + # 处理业务指令(纯 proto: cmd 在 body 顶层) elif logged_in and isinstance(body, dict): - inner_cmd = None - data_obj = body.get("data") - if isinstance(data_obj, dict): - inner_cmd = data_obj.get("cmd") - if inner_cmd == 2: # 开启激光并校准 - from laser_manager import laser_manager - if not laser_manager.calibration_active: - laser_manager.turn_on_laser() - time.sleep_ms(100) - hardware_manager.stop_idle_timer() # 停表 - if not config.HARDCODE_LASER_POINT: - laser_manager.start_calibration() - self.safe_enqueue({"result": "calibrating"}, 2) - else: - # 写死的逻辑,不需要校准激光点 - self.safe_enqueue({"result": "laser pos set by hard code"}, 2) - elif inner_cmd == 3: # 关闭激光 - from laser_manager import laser_manager - laser_manager.turn_off_laser() - laser_manager.stop_calibration() - hardware_manager.start_idle_timer() # 开表 - self.safe_enqueue({"result": "laser_off"}, 2) - elif inner_cmd == 4: # 上报电量 - voltage = get_bus_voltage() - battery_percent = voltage_to_percent(voltage) - battery_data = { - "battery": battery_percent, - "voltage": round(float(voltage), 3), - "netType": self.network_type, - } - self.safe_enqueue(battery_data, 2) - self.logger.info(f"电量上报: {battery_percent}% 充电: {is_charging()}") - if getattr(config, "CHARGING_AUTO_POWER_OFF_ENABLED", False) and is_charging(): - self.safe_enqueue( - { - "cmd": 700, - }, - 2, - ) - elif inner_cmd == 700: - self.logger.warning("服务器下发关机!!!") - exit(-1) - elif inner_cmd == 5: # OTA 升级 - inner_data = data_obj.get("data", {}) if isinstance(data_obj, dict) else {} - ssid = inner_data.get("ssid") - password = inner_data.get("password") - ota_url = inner_data.get("url") - mode = (inner_data.get("mode") or "").strip().lower() - - if not ota_url: - self.logger.error("ota missing_url") - self.safe_enqueue({"result": "missing_url"}, 2) - _rx_skip_tcp_iteration = True - break - - from ota_manager import ota_manager - if ota_manager.update_thread_started: - self.safe_enqueue({"result": "update_already_started"}, 2) - _rx_skip_tcp_iteration = True - break - - # 自动判断模式:如果没有明确指定,根据WiFi连接状态和凭证决定 - if mode not in ("4g", "wifi"): - self.logger.info("ota missing mode, auto-detecting...") - # 若本次会话已锁定 4G,则 OTA 自动也走 4G,避免后续回切导致体验不一致 - if self._session_force_4g: - mode = "4g" - self.logger.info("ota auto-selected: 4g (session locked on 4g)") - else: - # 只有同时满足:WiFi已连接 且 提供了WiFi凭证,才使用WiFi - if self.is_wifi_connected() and ssid and password: - mode = "wifi" - self.logger.info( - "ota auto-selected: wifi (WiFi connected and credentials provided)") - else: - mode = "4g" - self.logger.info( - "ota auto-selected: 4g (WiFi not available or no credentials)") - - hardware_manager.stop_idle_timer() # 停表,注意OTA停表之后,就没有再开表,因为OTA后面会重启,会重新开表 - - if mode == "4g": - ota_manager._set_ota_url(ota_url) # 记录 OTA URL,供命令7使用 - ota_manager._start_update_thread() - self._spawn_cmd_thread(ota_manager.direct_ota_download_via_4g, (ota_url,)) - else: # mode == "wifi" - if not ssid or not password: - self.logger.error("ota wifi mode requires ssid and password") - self.safe_enqueue({"result": "missing_ssid_or_password"}, 2) - else: - self.logger.info(f"ssid: {ssid}") - self.logger.info(f"password: {password}") - ota_manager._start_update_thread() - self._spawn_cmd_thread(ota_manager.handle_wifi_and_update, - (ssid, password, ota_url)) - elif inner_cmd == 6: - try: - ip = os.popen( - "ifconfig wlan0 2>/dev/null | grep 'inet ' | awk '{print $2}'").read().strip() - ip = ip if ip else "no_ip" - except: - ip = "error_getting_ip" - self.safe_enqueue({"result": "current_ip", "ip": ip}, 2) - elif inner_cmd == 44: # 读 4G 本机号码(AT+CNUM) - cnum = self.get_4g_phone_number() - self.logger.info(f"4G 本机号码: {cnum}") - self.safe_enqueue( - {"result": "cnum", "number": cnum if cnum is not None else ""}, 2) - elif inner_cmd == 45: # 读 MCCID(AT+MCCID) - mccid = self.get_4g_mccid() - self.logger.info(f"4G MCCID: {mccid}") - self.safe_enqueue( - {"result": "mccid", "mccid": mccid if mccid is not None else ""}, 2) - elif inner_cmd == 41: - self.logger.info(f"[TEST] 收到TCP射箭触发命令, {time.time()}") - self._manual_trigger_flag = True - self.safe_enqueue({"result": "trigger_ack"}, 2) - hardware_manager.start_idle_timer() # 重新计时 - elif inner_cmd == 42: # 关机命令 - self.logger.info("[SHUTDOWN] 收到TCP关机命令,准备关机...") - self.safe_enqueue({"result": "shutdown_ack"}, 2) - time.sleep_ms(1000) - self.disconnect_server() - # 尝试关闭4G模块 - try: - with self.get_uart_lock(): - hardware_manager.at_client.send("AT+CFUN=0", "OK", 5000) - except: - pass - time.sleep_ms(2000) - os.system("sync") # 刷新文件系统缓存到磁盘,防止数据丢失 - time.sleep_ms(500) - # os.system("poweroff") - hardware_manager.power_off() - return - elif inner_cmd == 43: # 上传日志命令 - # 格式: {"cmd":43, "data":{"ssid":"xxx","password":"xxx","url":"xxx", ...}} - inner_data = data_obj.get("data", {}) - upload_url = inner_data.get("url") - wifi_ssid = inner_data.get("ssid") - wifi_password = inner_data.get("password") - include_rotated = inner_data.get("include_rotated", True) - max_files = inner_data.get("max_files") - archive_format = inner_data.get("archive", "tgz") # tgz 或 zip - - hardware_manager.start_idle_timer() # 重新计时 - - if not upload_url: - self.logger.error("[LOG_UPLOAD] 缺少 url 参数") - self.safe_enqueue({"result": "log_upload_failed", "reason": "missing_url"}, - 2) + cmd = body.get("cmd") + data_obj = body.get("data") or {} + if cmd == 2: # AimRequest 开启激光并校准 + from laser_manager import laser_manager + if not laser_manager.calibration_active: + laser_manager.turn_on_laser() + time.sleep_ms(100) + hardware_manager.stop_idle_timer() + if not config.HARDCODE_LASER_POINT: + laser_manager.start_calibration() + self.safe_enqueue({"result": "calibrating"}, 2) else: - self.logger.info(f"[LOG_UPLOAD] 收到日志上传命令,目标URL: {upload_url}") - # 在新线程中执行上传,避免阻塞主循环 + self.safe_enqueue({"result": "laser pos set by hard code"}, 2) + elif cmd == 3: # CloseAimRequest 关闭激光 + from laser_manager import laser_manager + laser_manager.turn_off_laser() + laser_manager.stop_calibration() + hardware_manager.start_idle_timer() + self.safe_enqueue({"result": "laser_off"}, 2) + elif cmd == 4: # GetBatteryRequest 上报电量 + voltage = get_bus_voltage() + battery_percent = voltage_to_percent(voltage) + charging = is_charging() + self.safe_enqueue({ + "cmd": 4, + "battery": battery_percent, + "voltage": round(float(voltage), 3), + "netType": self.network_type, + "charging": charging, + }, 2) + self.logger.info(f"电量上报: {battery_percent}% 充电: {charging}") + elif cmd == 700: + self.logger.warning("服务器下发关机!!!") + exit(-1) + elif cmd == 5: # OtaRequest OTA 升级 + ota_url = data_obj.get("url", "") + + if not ota_url: + self.logger.error("ota missing_url") + self.safe_enqueue({"result": "missing_url"}, 2) + _rx_skip_tcp_iteration = True + break + + from ota_manager import ota_manager + if ota_manager.update_thread_started: + self.safe_enqueue({"result": "update_already_started"}, 2) + _rx_skip_tcp_iteration = True + break + + if not wifi_manager.is_wifi_connected(): + self.logger.warning("[ota] cmd5 当前未连接WiFi,拒绝OTA") + self.safe_enqueue({"result": "ota fail", "reason": "wifi not connected"}, 2) + _rx_skip_tcp_iteration = True + break + + hardware_manager.stop_idle_timer() + self._spawn_cmd_thread(self._cmd5_ota, (ota_url,)) + elif cmd == 41: # Ota4gSubCodeRequest 射箭触发 + self.logger.info(f"[TEST] 收到TCP射箭触发命令, {time.time()}") + self._manual_trigger_flag = True + self.safe_enqueue({"result": "trigger_ack"}, 2) + hardware_manager.start_idle_timer() + elif cmd == 42: # ShutdownCommand 关机命令 + self.logger.info("[SHUTDOWN] 收到TCP关机命令,准备关机...") + self.safe_enqueue({"result": "shutdown_ack"}, 2) + time.sleep_ms(1000) + self.disconnect_server() + try: + with self.get_uart_lock(): + hardware_manager.at_client.send("AT+CFUN=0", "OK", 5000) + except: + pass + time.sleep_ms(2000) + os.system("sync") + time.sleep_ms(500) + hardware_manager.power_off() + return + elif cmd == 44: # 读 4G 本机号码 + cnum = self.get_4g_phone_number() + self.logger.info(f"4G 本机号码: {cnum}") + self.safe_enqueue( + {"result": "cnum", "number": cnum if cnum is not None else ""}, 2) + elif cmd == 45: # 读 MCCID + mccid = self.get_4g_mccid() + self.logger.info(f"4G MCCID: {mccid}") + self.safe_enqueue( + {"result": "mccid", "mccid": mccid if mccid is not None else ""}, 2) + elif cmd == 43: # 上传日志命令 + upload_url = data_obj.get("url") + wifi_ssid = data_obj.get("ssid") + wifi_password = data_obj.get("password") + include_rotated = data_obj.get("include_rotated", True) + max_files = data_obj.get("max_files") + archive_format = data_obj.get("archive", "tgz") + + hardware_manager.start_idle_timer() + + if not upload_url: + self.logger.error("[LOG_UPLOAD] 缺少 url 参数") + self.safe_enqueue({"result": "log_upload_failed", "reason": "missing_url"}, 2) + else: + self.logger.info(f"[LOG_UPLOAD] 收到日志上传命令,目标URL: {upload_url}") self._spawn_cmd_thread( self._upload_log_file, (upload_url, wifi_ssid, wifi_password, include_rotated, max_files, archive_format) ) - elif inner_cmd == 200: - self.logger.info("[LASER] cmd200 在后台线程执行检测") - self._spawn_cmd_thread(self._cmd200_detect_laser, ()) - elif inner_cmd == 300: - self.logger.info("[New Ota] cmd300 在后台线程执行OTA") - self._spawn_cmd_thread(self._cmd300_ota, (data_obj,)) - elif inner_cmd == 600: - self.logger.info("[conn wifi] cmd600 在后台线程执行连接wifi: {data_obj}") - self._spawn_cmd_thread(self._cmd600_conn_wifi, (data_obj,)) - elif inner_cmd == 601: - pass - else: # data的结构不是 dict + elif cmd == 200: # GenericResult "init_center_point" 触发激光检测 + self.logger.info("[LASER] cmd200 在后台线程执行检测") + self._spawn_cmd_thread(self._cmd200_detect_laser, ()) + elif cmd == 201: # SetCenterPointRequest 设置中心点 + if self.logger: + self.logger.info(f"[LASER] cmd201:{body}") + raw_x = data_obj.get("x") + raw_y = data_obj.get("y") + try: + from laser_manager import laser_manager + ix, iy = laser_manager.set_hardcoded_laser_point(raw_x, raw_y) + self.safe_enqueue({ + "cmd": 201, + "result": "laser_point_set", + "x": ix, + "y": iy, + }, 2) + self.logger.info(f"[LASER] cmd201 硬编码激光点=({ix}, {iy})") + except Exception as e: + self.logger.error(f"[LASER] cmd201 失败: {e}") + self.safe_enqueue({ + "cmd": 201, + "result": "laser_point_set_failed", + "reason": str(e), + }, 2) + hardware_manager.start_idle_timer() + elif cmd == 300: # OtaRequest 新版OTA + self.logger.info("[New Ota] cmd300 在后台线程执行OTA") + self._spawn_cmd_thread(self._cmd300_ota, ({"data": data_obj},)) + elif cmd == 600: # WifiConnectRequest 连接wifi + self.logger.info(f"[conn wifi] cmd600 在后台线程执行连接wifi: {data_obj}") + self._spawn_cmd_thread(self._cmd600_conn_wifi, ({"data": data_obj},)) + elif cmd == 601: + pass + else: self.logger.info(f"[NET] body={body}, {time.time()}") - else: - self.logger.info(f"[NET] 未知数据 {body}, {time.time()}") if _rx_login_fail: break if _rx_skip_tcp_iteration: diff --git a/ota_manager.py b/ota_manager.py index 1421c5e..b5a2e47 100644 --- a/ota_manager.py +++ b/ota_manager.py @@ -2,1250 +2,239 @@ # -*- coding: utf-8 -*- """ OTA管理器模块 -提供OTA升级的状态管理和主要功能封装 +流程:下载ZIP → 解压覆盖项目 → 重启应用程序 """ import binascii import hashlib -import re import threading import os -import json import shutil -from urllib.parse import urlparse, unquote import requests -from maix import time import config -from hardware import hardware_manager -from network import network_manager from logger_manager import logger_manager -from power import get_bus_voltage, voltage_to_percent - - -# 延迟导入避免循环依赖 -# from network import network_manager class OTAManager: """OTA升级管理器(单例)""" _instance = None - + def __new__(cls): if cls._instance is None: cls._instance = super(OTAManager, cls).__new__(cls) cls._instance._initialized = False return cls._instance - + def __init__(self): if self._initialized: return - - # 私有状态 - self._update_thread_started = False self._ota_in_progress = 0 self._ota_url = None - self._ota_mode = None self._lock = threading.Lock() - self._is_https = False self._initialized = True - - # ==================== 状态访问(只读属性)==================== - + @property def logger(self): - """获取 logger 对象""" return logger_manager.logger - - @property - def update_thread_started(self): - """OTA线程是否已启动""" - return self._update_thread_started - + @property def ota_in_progress(self): - """OTA是否正在进行""" with self._lock: return self._ota_in_progress > 0 - + + @property + def update_thread_started(self): + return self._ota_in_progress > 0 + @property def ota_url(self): - """当前OTA URL""" return self._ota_url - - @property - def ota_mode(self): - """当前OTA模式""" - return self._ota_mode - - # ==================== 内部状态管理方法 ==================== - - def _start_update_thread(self): - """标记OTA线程已启动(内部方法)""" - with self._lock: - if self._update_thread_started: - return False - self._update_thread_started = True - return True - - def _stop_update_thread(self): - """标记OTA线程已停止(内部方法)""" - with self._lock: - self._update_thread_started = False - - def _begin_ota(self, url=None, mode=None): - """开始OTA(增加计数,内部方法)""" + + def _begin_ota(self, url=None): with self._lock: self._ota_in_progress += 1 if url: self._ota_url = url - if mode: - self._ota_mode = mode - + def _end_ota(self): - """结束OTA(减少计数,内部方法)""" with self._lock: self._ota_in_progress = max(0, self._ota_in_progress - 1) - + def _set_ota_url(self, url): - """设置OTA URL(内部方法)""" with self._lock: self._ota_url = url - - def _set_ota_mode(self, mode): - """设置OTA模式(内部方法)""" + + def _start_update_thread(self): with self._lock: - self._ota_mode = mode + if self._ota_in_progress > 0: + return False + self._ota_in_progress += 1 + return True + def _stop_update_thread(self): + self._end_ota() - def is_archive_file(self, filename): + # ==================== 核心方法 ==================== + + def perform_ota(self, url, progress_callback=None): """ - 检查文件是否是ZIP压缩包(通过扩展名判断) - 约定:上传的代码要么是ZIP压缩包(.zip),要么是直接的PY文件(.py) - - Returns: - (is_archive, archive_type): (True/False, 'zip'/None) - """ - if not os.path.exists(filename): - return False, None - - filename_lower = filename.lower() - if filename_lower.endswith('.zip'): - self.logger.info(f"[EXTRACT] 检测到ZIP文件(扩展名: .zip)") - return True, 'zip' - - self.logger.info(f"[EXTRACT] 不是ZIP格式(扩展名: {os.path.splitext(filename)[1] or '无'})") - return False, None - - def extract_zip_archive(self, archive_path, extract_to_dir=None, target_file=None): - """ - 使用系统 unzip 命令解压ZIP文件 + 完整OTA流程:下载ZIP → 解压覆盖项目 + 调用方负责重启程序(os.execv) Args: - archive_path: ZIP文件路径 - extract_to_dir: 解压到的目录(如果为None,解压到压缩包所在目录) - target_file: 目标文件名(如'main.py'),如果指定,只提取该文件;None表示解压所有文件 + url: 固件下载地址 + progress_callback: 进度回调 fn(phase, progress),phase="downloading"/"installing",progress=0-100 Returns: - (success, extracted_dir): 成功则返回(True, 解压目录路径),失败返回(False, None) + (success: bool, message: str) """ - if extract_to_dir is None: - extract_to_dir = os.path.dirname(archive_path) or '/tmp' - - self.logger.info(f"[EXTRACT] 开始解压ZIP文件: {archive_path}") + if not url: + return False, "missing_url" + self._begin_ota(url) try: - os.makedirs(extract_to_dir, exist_ok=True) + tmp_path = f"{config.APP_DIR}/ota_tmp.zip" - if target_file: - cmd = f"unzip -q -o '{archive_path}' '{target_file}' -d '{extract_to_dir}' 2>&1" - else: - cmd = f"unzip -q -o '{archive_path}' -d '{extract_to_dir}' 2>&1" + self.logger.info(f"[OTA] 开始下载: {url}") + if progress_callback: + progress_callback("downloading", 0) + ok, msg = self._download_zip(url, tmp_path, progress_callback) + if not ok: + self.logger.error(f"[OTA] 下载失败: {msg}") + return False, msg + self.logger.info(f"[OTA] 下载完成: {msg}") + if progress_callback: + progress_callback("downloading", 50) - result = os.system(cmd) - - if result != 0: - self.logger.warning(f"[EXTRACT] 直接解压目标文件失败,尝试解压所有文件...") - cmd_all = f"unzip -q -o '{archive_path}' -d '{extract_to_dir}' 2>&1" - result_all = os.system(cmd_all) - - if result_all != 0: - self.logger.error(f"[EXTRACT] 解压失败,退出码: {result_all}") - return False, None - - return True, extract_to_dir + self.logger.info("[OTA] 开始应用更新...") + if progress_callback: + progress_callback("installing", 50) + ok, msg = self._apply_update(tmp_path, progress_callback) + if not ok: + self.logger.error(f"[OTA] 应用更新失败: {msg}") + return False, msg + self.logger.info(f"[OTA] 更新应用成功,共更新 {msg} 个文件") + if progress_callback: + progress_callback("installing", 51) + return True, "success" except Exception as e: - self.logger.error(f"[EXTRACT] 解压过程出错: {e}") - return False, None + self.logger.error(f"[OTA] 异常: {e}") + return False, str(e) + finally: + self._end_ota() - def apply_ota_and_reboot(self, ota_url=None, downloaded_file=None): + def _download_zip(self, url, save_path, progress_callback=None): """ - OTA 文件下载成功后: - 1. 备份应用目录中的所有代码文件 - 2. 如果是ZIP则解压,如果是单个文件则直接使用 - 3. 复制/覆盖所有更新文件到应用目录 - 4. 重启设备 + 下载ZIP文件(流式分块下载,支持进度回调) Args: - ota_url: OTA URL(用于记录) - downloaded_file: 下载的文件路径(如果为None,使用默认的main_tmp.py) + url: 下载地址 + save_path: 保存路径 + progress_callback: 进度回调 fn(phase, progress),progress=0-80 + + Returns: + (success: bool, message: str) """ - - # 在调用前设置状态 - if ota_url: - self._set_ota_url(ota_url) - - if downloaded_file is None: - downloaded_file = config.LOCAL_FILENAME - - ota_pending = f"{config.APP_DIR}/ota_pending.json" - - self.logger.info(f"[OTA] 准备应用OTA更新,下载文件: {downloaded_file}") - try: - if not os.path.exists(downloaded_file): - self.logger.error(f"[OTA] 错误:{downloaded_file} 不存在") - return False + response = requests.get(url, timeout=120, stream=True) + response.raise_for_status() - # ====== 第一步:如果是 AEAD 加密包,先解密成临时 zip(再走原有 unzip 流程) ====== - downloaded_file_original = downloaded_file - decrypted_tmp_zip = None - try: - magic = b"AROTAE1" # must match packager/C++ side - is_enc_ext = downloaded_file.lower().endswith((".enc", ".zip.enc")) - is_enc_magic = False - try: - with open(downloaded_file, "rb") as f: - head = f.read(len(magic)) - is_enc_magic = (head == magic) - except Exception: - is_enc_magic = False + total_size = int(response.headers.get('Content-Length', 0)) + chunk_size = 8192 + downloaded = 0 + md5_hash = hashlib.md5() - if is_enc_ext or is_enc_magic: - # Choose output zip path (same dir) - tmp_zip = downloaded_file - if tmp_zip.lower().endswith(".zip.enc"): - tmp_zip = tmp_zip[:-4] # remove ".enc" -> ".zip" - elif tmp_zip.lower().endswith(".enc"): - tmp_zip = tmp_zip[:-4] - if not tmp_zip.lower().endswith(".zip"): - tmp_zip = tmp_zip + ".zip" - else: - tmp_zip = tmp_zip + ".zip" + with open(save_path, 'wb') as f: + for chunk in response.iter_content(chunk_size=chunk_size): + if chunk: + f.write(chunk) + md5_hash.update(chunk) + downloaded += len(chunk) + if progress_callback and total_size > 0: + percent = min(int(downloaded / total_size * 50), 49) + progress_callback("downloading", percent) - decrypted_tmp_zip = tmp_zip - - # Remove stale tmp if exists - try: - if os.path.exists(decrypted_tmp_zip): - os.remove(decrypted_tmp_zip) - except Exception: - pass - - self.logger.info(f"[OTA] 检测到加密包,开始解密: {downloaded_file} -> {decrypted_tmp_zip}") - ok = False - try: - core = getattr(network_manager, "_netcore", None) - if core and hasattr(core, "decrypt_ota_file"): - ok = bool(core.decrypt_ota_file(downloaded_file, decrypted_tmp_zip)) - else: - import archery_netcore as _netcore - ok = bool(_netcore.decrypt_ota_file(downloaded_file, decrypted_tmp_zip)) - except Exception as e: - self.logger.error(f"[OTA] 解密异常: {e}") - ok = False - - if not ok or (not os.path.exists(decrypted_tmp_zip)): - self.logger.error("[OTA] 解密失败,终止更新") - return False - - downloaded_file = decrypted_tmp_zip - self.logger.info(f"[OTA] 解密成功,后续使用明文ZIP: {downloaded_file}") - except Exception as e: - self.logger.error(f"[OTA] 解密流程异常: {e}") - return False - - # 备份 - backup_base = config.BACKUP_BASE - backup_dir = None - - try: - os.makedirs(backup_base, exist_ok=True) - - counter_file = os.path.join(backup_base, ".counter") - try: - if os.path.exists(counter_file): - with open(counter_file, 'r') as f: - counter = int(f.read().strip()) + 1 - else: - counter = 1 - - with open(counter_file, 'w') as f: - f.write(str(counter)) - - backup_dir = os.path.join(backup_base, f"backup_{counter:04d}") - self.logger.info(f"[OTA] 使用备份目录: {backup_dir} (第{counter}次OTA)") - except Exception as e: - self.logger.error(f"[OTA] 生成备份目录名失败: {e},使用默认目录") - backup_dir = os.path.join(backup_base, "backup_0000") - - # 清理旧备份 - try: - backup_dirs = [] - for item in os.listdir(backup_base): - if item == ".counter": - continue - item_path = os.path.join(backup_base, item) - if os.path.isdir(item_path) and item.startswith("backup_"): - try: - dir_num_str = item.replace("backup_", "") - dir_num = int(dir_num_str) - backup_dirs.append((item, dir_num, item_path)) - except: - pass - - backup_dirs.sort(key=lambda x: x[1], reverse=True) - if len(backup_dirs) > config.MAX_BACKUPS: - for item, dir_num, item_path in backup_dirs[config.MAX_BACKUPS:]: - try: - shutil.rmtree(item_path, ignore_errors=True) - self.logger.info(f"[OTA] 已删除旧备份: {item}") - except Exception as e: - self.logger.warning(f"[OTA] 删除旧备份失败: {e}") - except Exception as e: - self.logger.warning(f"[OTA] 清理旧备份时出错: {e}") - - os.makedirs(backup_dir, exist_ok=True) - - exclude_patterns = ['.pyc', '__pycache__', '.log', 'backups', 'ota_extract', '.bak', 'download'] - backed_up_files = [] - - if os.path.exists(config.APP_DIR): - for root, dirs, files in os.walk(config.APP_DIR): - dirs[:] = [d for d in dirs if not any(ex in d for ex in exclude_patterns)] - - for f in files: - if any(ex in f for ex in exclude_patterns): - continue - - source_path = os.path.join(root, f) - rel_path = os.path.relpath(source_path, config.APP_DIR) - backup_path = os.path.join(backup_dir, rel_path) - - backup_parent = os.path.dirname(backup_path) - if backup_parent != backup_dir: - os.makedirs(backup_parent, exist_ok=True) - - try: - shutil.copy2(source_path, backup_path) - backed_up_files.append(rel_path) - except Exception as e: - self.logger.error(f"[OTA] 备份 {rel_path} 失败: {e}") - - if backed_up_files: - self.logger.info(f"[OTA] 总共备份了 {len(backed_up_files)} 个文件到 {backup_dir}") - else: - self.logger.warning(f"[OTA] 没有备份任何文件") - - except Exception as e: - self.logger.error(f"[OTA] 备份过程出错: {e}") - if not backup_dir: - backup_dir = None - - # 检查是否是ZIP压缩包 - is_archive, archive_type = self.is_archive_file(downloaded_file) - files_to_copy = [] - - if is_archive and archive_type == 'zip': - # 在解压前验证ZIP文件完整性 - try: - with open(downloaded_file, "rb") as f: - zip_header = f.read(4) - if zip_header[:2] != b'PK': - self.logger.error(f"[OTA] ZIP文件头验证失败: {zip_header.hex()}") - return False - file_size = os.path.getsize(downloaded_file) - self.logger.info(f"[OTA] ZIP文件验证通过: 大小={file_size} bytes, 头={zip_header.hex()}") - except Exception as e: - self.logger.error(f"[OTA] ZIP文件验证异常: {e}") - return False - - self.logger.info(f"[OTA] 检测到ZIP压缩包,开始解压...") - extract_dir = "/tmp/ota_extract" - try: - os.makedirs(extract_dir, exist_ok=True) - except: - extract_dir = f"{config.APP_DIR}/ota_extract" - os.makedirs(extract_dir, exist_ok=True) - - success, extracted_dir = self.extract_zip_archive( - downloaded_file, - extract_to_dir=extract_dir, - target_file=None - ) - - if success and extracted_dir and os.path.exists(extracted_dir): - for root, dirs, files in os.walk(extracted_dir): - for f in files: - source_path = os.path.join(root, f) - rel_path = os.path.relpath(source_path, extracted_dir) - files_to_copy.append((source_path, rel_path)) - - if files_to_copy: - self.logger.info(f"[OTA] 解压成功,共 {len(files_to_copy)} 个文件") - else: - self.logger.error(f"[OTA] 解压成功但未找到任何文件") - return False - else: - self.logger.error(f"[OTA] 解压失败") - return False - else: - # 单个文件更新:从下载的文件名推断目标文件名 - filename = os.path.basename(downloaded_file) - - # 如果下载的文件是 main_tmp.py,目标应该是 main.py - # 如果下载的文件是 main.py,目标也是 main.py - # 其他文件名,保持原样 - if filename == "main_tmp.py": - target_rel_path = "main.py" - else: - target_rel_path = filename - - files_to_copy = [(downloaded_file, target_rel_path)] - self.logger.info(f"[OTA] 单个文件更新: {downloaded_file} -> {target_rel_path}") - - # 复制文件 - if not files_to_copy: - self.logger.error(f"[OTA] 没有文件需要复制") - return False - - copied_files = [] - for source_path, rel_path in files_to_copy: - dest_path = os.path.join(config.APP_DIR, rel_path) - - # 检查源文件和目标文件是否是同一个文件(避免复制到自身) - if os.path.abspath(source_path) == os.path.abspath(dest_path): - self.logger.warning(f"[OTA] 源文件和目标文件相同,跳过复制: {rel_path} (文件已在正确位置)") - copied_files.append(rel_path) - continue - - dest_dir = os.path.dirname(dest_path) - if dest_dir: - try: - os.makedirs(dest_dir, exist_ok=True) - except Exception: - pass - - try: - shutil.copy2(source_path, dest_path) - copied_files.append(rel_path) - self.logger.info(f"[OTA] 已复制: {rel_path}") - except Exception as e: - self.logger.error(f"[OTA] 复制 {rel_path} 失败: {e}") - return False - - if copied_files: - self.logger.info(f"[OTA] 成功复制 {len(copied_files)} 个文件到应用目录") - - # 确保写入磁盘 try: os.sync() except: pass - time.sleep_ms(500) - # 写入 pending - try: - pending_obj = { - "ts": 0, # MaixPy time 模块没有 time() 函数,使用 0 - "url": ota_url or "", - "downloaded_file": downloaded_file, - "was_archive": is_archive, - "archive_type": archive_type if is_archive else None, - "backup_dir": backup_dir, - "updated_files": copied_files, - "restart_count": 0, - "max_restarts": 3, - } - with open(ota_pending, "w", encoding="utf-8") as f: - json.dump(pending_obj, f) - try: - os.sync() - except: - pass - except Exception as e: - self.logger.error(f"[OTA] 写入 ota_pending 失败: {e}") - - # 通知服务器(延迟导入避免循环导入) - from network import safe_enqueue - safe_enqueue({"result": "ota_applied_rebooting", "files": copied_files}, 2) - time.sleep_ms(1000) - - # 清理临时解压目录 - if is_archive and 'extract_dir' in locals(): - try: - if os.path.exists(extract_dir): - shutil.rmtree(extract_dir, ignore_errors=True) - self.logger.info(f"[OTA] 已清理临时解压目录: {extract_dir}") - except Exception as e: - self.logger.warning(f"[OTA] 清理临时目录失败(可忽略): {e}") - - # 清理下载文件 - try: - # 删除下载的文件(可能包含:原始加密包 + 临时明文zip) - files_to_remove = [] - try: - if 'downloaded_file_original' in locals() and downloaded_file_original: - files_to_remove.append(downloaded_file_original) - except Exception: - pass - try: - if 'decrypted_tmp_zip' in locals() and decrypted_tmp_zip: - files_to_remove.append(decrypted_tmp_zip) - except Exception: - pass - # 兼容:如果变量不存在,至少清理当前 downloaded_file - if not files_to_remove: - files_to_remove = [downloaded_file] - - removed_any = False - for fp in list(dict.fromkeys(files_to_remove)): - try: - if fp and os.path.exists(fp): - os.remove(fp) - removed_any = True - self.logger.info(f"[OTA] 已删除下载文件: {fp}") - except Exception as e: - self.logger.warning(f"[OTA] 删除下载文件失败(可忽略): {e}") - - # 尝试删除时间戳目录(如果为空) - try: - download_dir = os.path.dirname(files_to_remove[0] if files_to_remove else downloaded_file) - if download_dir.startswith("/tmp/download/"): - # 检查时间戳目录是否为空 - if os.path.exists(download_dir): - try: - files_in_dir = os.listdir(download_dir) - if not files_in_dir: - os.rmdir(download_dir) - self.logger.info(f"[OTA] 已删除空时间戳目录: {download_dir}") - except Exception as e: - self.logger.debug(f"[OTA] 删除时间戳目录失败(可忽略): {e}") - except Exception as e: - self.logger.debug(f"[OTA] 清理时间戳目录时出错(可忽略): {e}") - except Exception as e: - self.logger.warning(f"[OTA] 清理下载文件时出错(可忽略): {e}") - - # 重启设备 - self.logger.info("[OTA] 准备重启设备...") - os.system("reboot") - - return True - - except Exception as e: - self.logger.error(f"[OTA] apply_ota_and_reboot 异常: {e}") - import traceback - self.logger.error(traceback.format_exc()) - return False - - def get_download_timestamp_dir(self): - """ - 获取下载目录(带时间戳),格式:/tmp/download/YYYYMMDD_HHMMSS - 使用时间戳而不是日期,避免跨天问题 - - Returns: - 下载目录路径 - """ - try: - # 尝试从系统获取时间戳 - try: - # 方法1:使用系统 date 命令(精确到秒) - timestamp_str = os.popen("date +%Y%m%d_%H%M%S 2>/dev/null").read().strip() - if timestamp_str and len(timestamp_str) == 15: # YYYYMMDD_HHMMSS = 15字符 - timestamp_dir = timestamp_str - else: - raise ValueError("date command failed") - except: - # 方法2:使用 Python datetime(如果系统时间已同步) - try: - from datetime import datetime - now = datetime.now() - timestamp_dir = now.strftime("%Y%m%d_%H%M%S") - except: - # 方法3:如果都失败,使用默认时间戳 - timestamp_dir = "00000000_000000" - - download_base = "/tmp/download" - download_dir = f"{download_base}/{timestamp_dir}" - - # 确保目录存在 - try: - os.makedirs(download_dir, exist_ok=True) - except Exception as e: - self.logger.warning(f"[OTA] 创建下载目录失败: {e},使用基础目录") - download_dir = download_base - try: - os.makedirs(download_dir, exist_ok=True) - except: - pass - - return download_dir - except Exception as e: - self.logger.error(f"[OTA] 获取下载目录失败: {e},使用默认目录") - return "/tmp/download" - - def get_filename_from_url(self, url, default_name="main_tmp"): - """ - 从URL中提取文件名和扩展名,保存到带时间戳的下载目录 - - Args: - url: 下载URL - default_name: 如果无法从URL提取文件名,使用的默认名称 - - Returns: - 完整的文件路径,例如: "/tmp/download/20250108_143025/main.zip" - """ - try: - # 获取下载目录(带时间戳) - download_dir = self.get_download_timestamp_dir() - - parsed = urlparse(url) - path = parsed.path - filename = os.path.basename(path) - filename = unquote(filename) - - # 如果从URL提取到了文件名(无论是否有扩展名),都使用该文件名 - if filename and filename.strip(): - return f"{download_dir}/{filename}" - else: - # 只有在完全无法提取文件名时,才使用默认名称 - return f"{download_dir}/{default_name}" - except Exception as e: - self.logger.error(f"[OTA] 从URL提取文件名失败: {e},使用默认文件名") - download_dir = self.get_download_timestamp_dir() - return f"{download_dir}/{default_name}" - - def download_file_via_wifi(self, url, filename): - """从指定 URL 下载文件,根据文件类型自动选择文本或二进制模式,并支持MD5校验""" - try: - self.logger.info(f"正在从 {url} 下载文件...") - response = requests.get(url) - response.raise_for_status() - - # 从响应头中提取MD5(如果服务器提供) md5_b64_expected = None if 'Content-Md5' in response.headers: md5_b64_expected = response.headers['Content-Md5'].strip() - self.logger.info(f"[DOWNLOAD] 服务器提供了MD5校验值: {md5_b64_expected}") - - # 根据文件扩展名判断是否为二进制文件 - filename_lower = filename.lower() - is_binary = filename_lower.endswith(('.zip', '.zip.enc', '.enc', '.bin', '.tar', '.gz', '.exe', '.dll', '.so', '.dylib')) - - if is_binary: - # 二进制文件:使用二进制模式写入 - data = response.content - with open(filename, 'wb') as file: - file.write(data) - # 强制刷新到磁盘 - try: - os.sync() - except: - pass - self.logger.info(f"[DOWNLOAD] 使用二进制模式下载: {filename}, 大小: {len(data)} bytes") - else: - # 文本文件:使用文本模式写入 - response.encoding = 'utf-8' - with open(filename, 'w', encoding='utf-8') as file: - file.write(response.text) - self.logger.info(f"[DOWNLOAD] 使用文本模式下载: {filename}") - - # MD5 校验(如果服务器提供了MD5值) - if md5_b64_expected and hashlib is not None: - try: - with open(filename, "rb") as f: - file_data = f.read() - digest = hashlib.md5(file_data).digest() - md5_b64_got = binascii.b2a_base64(digest).decode().strip() - - if md5_b64_got != md5_b64_expected: - self.logger.error(f"[DOWNLOAD] MD5校验失败: 期望={md5_b64_expected}, 实际={md5_b64_got}") - return f"下载失败!MD5校验失败: 期望={md5_b64_expected}, 实际={md5_b64_got}" - else: - self.logger.info(f"[DOWNLOAD] MD5校验通过: {md5_b64_got}") - except Exception as e: - self.logger.warning(f"[DOWNLOAD] MD5校验过程出错: {e}") - # MD5校验出错时,如果是二进制文件(特别是ZIP),应该失败 - if is_binary: - return f"下载失败!MD5校验异常: {e}" - elif is_binary and not md5_b64_expected: - # 二进制文件(特别是ZIP)建议有MD5校验 - self.logger.warning(f"[DOWNLOAD] 警告: 服务器未提供MD5校验值,无法验证文件完整性") - - return f"下载成功!文件已保存为: {filename}" + if md5_b64_expected: + md5_b64_got = binascii.b2a_base64(md5_hash.digest()).decode().strip() + if md5_b64_got != md5_b64_expected: + return False, f"MD5校验失败" + self.logger.info("[OTA] MD5校验通过") + + return True, f"size={downloaded}" except requests.exceptions.RequestException as e: - return f"下载失败!网络请求错误: {e}" + return False, f"网络错误: {e}" except OSError as e: - return f"下载失败!文件写入错误: {e}" - except Exception as e: - return f"下载失败!发生未知错误: {e}" + return False, f"写入错误: {e}" - # def direct_ota_download(self, ota_url): - # """直接执行 OTA 下载(假设已有网络)""" - - # self._set_ota_url(ota_url) - # self._start_update_thread() - - # try: - # if not ota_url: - # from network import safe_enqueue - # safe_enqueue({"result": "ota_failed", "reason": "missing_url"}, 2) - # return - - # parsed_url = urlparse(ota_url) - # host = parsed_url.hostname - # port = parsed_url.port or (443 if parsed_url.scheme == 'https' else 80) - - # if not network_manager.is_server_reachable(host, port, timeout=8): - # from network import safe_enqueue - # safe_enqueue({"result": "ota_failed", "reason": f"无法连接 {host}:{port}"}, 2) - # return - - # downloaded_filename = self.get_filename_from_url(ota_url, default_name="main_tmp") - # self.logger.info(f"[OTA] 下载文件将保存为: {downloaded_filename}") - # self.logger.info(f"[OTA] 开始下载: {ota_url}") - # result_msg = self.download_file(ota_url, downloaded_filename) - # self.logger.info(f"[OTA] {result_msg}") - - # if "成功" in result_msg or "下载成功" in result_msg: - # if self.apply_ota_and_reboot(ota_url, downloaded_filename): - # return - # else: - # from network import safe_enqueue - # safe_enqueue({"result": result_msg}, 2) - - # except Exception as e: - # error_msg = f"OTA 异常: {str(e)}" - # self.logger.error(error_msg) - # from network import safe_enqueue - # safe_enqueue({"result": "ota_failed", "reason": error_msg}, 2) - # finally: - # self._stop_update_thread() - - def download_file_via_4g(self, url, filename, - total_timeout_ms=600000, - retries=3, - debug=False): + def _apply_update(self, zip_path, progress_callback=None): """ - ML307R HTTP 下载(更稳的"固定小块 Range 顺序下载",基于main109.py): - - 只依赖 +MHTTPURC:"header"/"content"(不依赖 MHTTPREAD/cached) - - 每次只请求一个小块 Range(默认 10240B),失败就重试同一块,必要时缩小块大小 - - 每个 chunk 都重新 MHTTPCREATE/MHTTPREQUEST,避免卡在"206 header 但不吐 content"的坏状态 - - 使用二进制模式下载,确保文件完整性 + 解压ZIP到临时目录,重启后由主程序移动到实际目录 + + Returns: + (success: bool, message: str) """ - from urllib.parse import urlparse - from hardware import hardware_manager - - # 小块策略(与main109.py保持一致) - CHUNK_MAX = 10240 - CHUNK_MIN = 128 - CHUNK_RETRIES = 12 - FRAG_SIZE = 1024 - FRAG_DELAY = 10 - - t_func0 = time.ticks_ms() - - parsed = urlparse(url) - host = parsed.hostname - # MHTTPREQUEST 的路径必须包含 query(七牛/ OSS 签名、token 多在 ? 后),否则易 403/HTML,header 无 CL → no_header_or_total - path = parsed.path or "/" - if parsed.query: - path = f"{path}?{parsed.query}" - if parsed.fragment: - path = f"{path}#{parsed.fragment}" - if not host: - return False, "bad_url (no host)" - - # 很多 ML307R 的 MHTTP 对 https 不稳定;对已知域名做降级 - - if isinstance(url, str) and url.startswith("https://static.shelingxingqiu.com/"): - base_url = "http://static.shelingxingqiu.com" - self._is_https = False - else: - base_url = f"http://{host}" - self._is_https = False - self.logger.info(f"base_url: {base_url}, self._is_https: {self._is_https}") - # logger removed - use self.logger instead - - def _log(*a): - if debug: - self.logger.debug(" ".join(str(x) for x in a)) - - def _pwr_log(prefix=""): - """debug 用:输出电压/电量""" - if not debug: - return - try: - v = get_bus_voltage() - p = voltage_to_percent(v) - self.logger.debug(f"[PWR]{prefix} v={v:.3f}V p={p}%") - except Exception as e: - try: - self.logger.debug(f"[PWR]{prefix} read_failed: {e}") - except: - pass - - def _clear_http_events(): - if hardware_manager.at_client: - while hardware_manager.at_client.pop_http_event() is not None: - pass - - def _parse_httpid(resp: str): - m = re.search(r"\+MHTTPCREATE:\s*(\d+)", resp) - return int(m.group(1)) if m else None - - def _get_ip(): - r = hardware_manager.at_client.send("AT+CGPADDR=1", "OK", 3000) - m = re.search(r'\+CGPADDR:\s*1,"([^"]+)"', r) - return m.group(1) if m else "" - - def _ensure_pdp(): - ip = _get_ip() - if ip and ip != "0.0.0.0": - return True, ip - hardware_manager.at_client.send("AT+MIPCALL=1,1", "OK", 15000) - for _ in range(10): - ip = _get_ip() - if ip and ip != "0.0.0.0": - return True, ip - time.sleep(1) - return False, ip - - def _extract_hdr_fields(hdr_text: str): - mlen = re.search(r"Content-Length:\s*(\d+)", hdr_text, re.IGNORECASE) - clen = int(mlen.group(1)) if mlen else None - mmd5 = re.search(r"Content-Md5:\s*([A-Za-z0-9+/=]+)", hdr_text, re.IGNORECASE) - md5_b64 = mmd5.group(1).strip() if mmd5 else None - return clen, md5_b64 - - def _extract_content_range(hdr_text: str): - m = re.search(r"Content-Range:\s*bytes\s*(\d+)\s*-\s*(\d+)\s*/\s*(\d+)", hdr_text, re.IGNORECASE) - if not m: - return None, None, None - try: - return int(m.group(1)), int(m.group(2)), int(m.group(3)) - except: - return None, None, None - - def _hard_reset_http(): - """模块进入"坏状态"时的保守清场""" - _clear_http_events() - for i in range(0, 6): - try: - hardware_manager.at_client.send(f"AT+MHTTPDEL={i}", "OK", 1200) - except: - pass - _clear_http_events() - - def _create_httpid(full_reset=False): - _clear_http_events() - if hardware_manager.at_client: - hardware_manager.at_client.flush() - if full_reset: - _hard_reset_http() - resp = hardware_manager.at_client.send(f'AT+MHTTPCREATE="{base_url}"', "OK", 8000) - hid = _parse_httpid(resp) - if self._is_https: - resp = hardware_manager.at_client.send(f'AT+MHTTPCFG="ssl",{hid},1,1', "OK", 2000) - if "ERROR" in resp or "CME ERROR" in resp: - self.logger.error(f"MHTTPCFG SSL failed: {resp}") - # 尝试https 降级到http - downgraded_base_url = base_url.replace("https://", "http://") - resp = hardware_manager.at_client.send(f'AT+MHTTPCREATE="{downgraded_base_url}"', "OK", 8000) - hid = _parse_httpid(resp) - - return hid, resp - - def _fetch_range_into_buf(start, want_len, out_buf, full_reset=False): - """ - 请求 Range [start, start+want_len),写入 out_buf(bytearray,长度=want_len) - 返回 (ok, msg, total_len, md5_b64, got_len) - """ - end_incl = start + want_len - 1 - hid, cresp = _create_httpid(full_reset=full_reset) - if hid is None: - return False, f"MHTTPCREATE failed: {cresp}", None, None, 0 - - # 降低 URC 压力(分片/延迟) - hardware_manager.at_client.send(f'AT+MHTTPCFG="fragment",{hid},{FRAG_SIZE},{FRAG_DELAY}', "OK", 1500) - # 设置 Range header(inclusive) - hardware_manager.at_client.send(f'AT+MHTTPCFG="header",{hid},"Range: bytes={start}-{end_incl}"', "OK", 3000) - - req = hardware_manager.at_client.send(f'AT+MHTTPREQUEST={hid},1,0,"{path}"', "OK", 15000) - if "ERROR" in req or "CME ERROR" in req: - hardware_manager.at_client.send(f"AT+MHTTPDEL={hid}", "OK", 2000) - return False, f"MHTTPREQUEST failed: {req}", None, None, 0 - - # 等 header + content - hdr_text = None - hdr_accum = "" - code = None - resp_total = None - total_len = None - md5_b64 = None - - got_ranges = set() - last_sum = 0 - t0 = time.ticks_ms() - timeout_ms = 9000 - logged_hdr = False - - while time.ticks_ms() - t0 < timeout_ms: - ev = hardware_manager.at_client.pop_http_event() if hardware_manager.at_client else None - if not ev: - time.sleep_ms(5) - continue - - if ev[0] == "header": - _, ehid, ecode, ehdr = ev - if ehid != hid: - continue - code = ecode - hdr_text = ehdr - if ehdr: - hdr_accum = (hdr_accum + "\n" + ehdr) if hdr_accum else ehdr - - resp_total_tmp, md5_tmp = _extract_hdr_fields(hdr_accum) - if md5_tmp: - md5_b64 = md5_tmp - cr_s, cr_e, cr_total = _extract_content_range(hdr_accum) - if cr_total is not None: - total_len = cr_total - if resp_total_tmp is not None: - resp_total = resp_total_tmp - elif resp_total is None and (cr_s is not None) and (cr_e is not None) and (cr_e >= cr_s): - resp_total = (cr_e - cr_s + 1) - if (not logged_hdr) and (resp_total is not None or total_len is not None): - _log(f"[HDR] id={hid} code={code} clen={resp_total} cr={cr_s}-{cr_e}/{cr_total}") - logged_hdr = True - continue - - if ev[0] == "content": - _, ehid, _total, _sum, _cur, payload = ev - if ehid != hid: - continue - if resp_total is None: - resp_total = _total - if resp_total is None or resp_total <= 0: - continue - start_rel = _sum - _cur - end_rel = _sum - if start_rel < 0 or start_rel >= resp_total: - continue - if end_rel > resp_total: - end_rel = resp_total - actual_len = min(len(payload), end_rel - start_rel) - if actual_len <= 0: - continue - out_buf[start_rel:start_rel + actual_len] = payload[:actual_len] - got_ranges.add((start_rel, start_rel + actual_len)) - if _sum > last_sum: - last_sum = _sum - if debug and (last_sum >= resp_total or (last_sum % 512 == 0)): - _log(f"[CHUNK] {start}+{last_sum}/{resp_total}") - - if last_sum >= resp_total: - break - - # 清理实例(快路径:只删当前 hid) - try: - hardware_manager.at_client.send(f"AT+MHTTPDEL={hid}", "OK", 2000) - except: - pass - - if resp_total is None: - return False, "no_header_or_total", total_len, md5_b64, 0 - - # 计算实际填充长度 - merged = sorted(got_ranges) - merged2 = [] - for s, e in merged: - if not merged2 or s > merged2[-1][1]: - merged2.append((s, e)) - else: - merged2[-1] = (merged2[-1][0], max(merged2[-1][1], e)) - filled = sum(e - s for s, e in merged2) - - if filled < resp_total: - return False, f"incomplete_chunk got={filled} expected={resp_total} code={code}", total_len, md5_b64, filled - - got_len = resp_total - return True, "OK", total_len, md5_b64, got_len + if not os.path.exists(zip_path): + return False, f"文件不存在: {zip_path}" try: - self._begin_ota() + with open(zip_path, "rb") as f: + header = f.read(4) + if header[:2] != b'PK': + return False, f"不是ZIP文件: {header.hex()}" + except Exception as e: + return False, f"读取ZIP失败: {e}" + + staging_dir = f"{config.APP_DIR}/ota_staging" + try: + os.makedirs(staging_dir, exist_ok=True) except: pass - from network import network_manager - with network_manager.get_uart_lock(): - try: - ok_pdp, ip = _ensure_pdp() - if not ok_pdp: - return False, f"PDP not ready (ip={ip})" + try: + self.logger.info(f"[OTA] 开始解压: {zip_path} -> {staging_dir}") + ret = os.system(f"unzip -q -o '{zip_path}' -d '{staging_dir}' 2>&1") + if ret != 0: + return False, f"解压失败: exit={ret}" + self.logger.info("[OTA] 解压完成") + except Exception as e: + return False, f"解压异常: {e}" - # 先清空旧事件,避免串台 - _clear_http_events() + file_count = 0 + for _, _, files in os.walk(staging_dir): + file_count += len(files) - # 为了支持随机写入,先创建空文件 - try: - with open(filename, "wb") as f: - f.write(b"") - except Exception as e: - return False, f"open_file_failed: {e}" - - total_len = None - expect_md5_b64 = None - - offset = 0 - chunk = CHUNK_MAX - t_start = time.ticks_ms() - last_progress_ms = t_start - STALL_TIMEOUT_MS = 60000 - last_pwr_ms = t_start - _pwr_log(prefix=" ota_start") - bad_http_state = 0 - - while True: - now = time.ticks_ms() - if debug and time.ticks_diff(now, last_pwr_ms) >= 5000: - last_pwr_ms = now - _pwr_log(prefix=f" off={offset}/{total_len or '?'}") - if time.ticks_diff(now, t_start) > total_timeout_ms: - return False, f"timeout overall after {total_timeout_ms}ms offset={offset} total={total_len}" - - if time.ticks_diff(now, last_progress_ms) > STALL_TIMEOUT_MS: - return False, f"timeout stalled {STALL_TIMEOUT_MS}ms offset={offset} total={total_len}" - - if total_len is not None and offset >= total_len: - break - - want = chunk - if total_len is not None: - remain = total_len - offset - if remain <= 0: - break - if want > remain: - want = remain - - # 本 chunk 的 buffer(长度=want) - buf = bytearray(want) - - success = False - last_err = "unknown" - md5_seen = None - got_len = 0 - for k in range(1, CHUNK_RETRIES + 1): - do_full_reset = (bad_http_state >= 2) - ok, msg, tlen, md5_b64, got = _fetch_range_into_buf(offset, want, buf, full_reset=do_full_reset) - last_err = msg - if tlen is not None and total_len is None: - total_len = tlen - if md5_b64 and not expect_md5_b64: - expect_md5_b64 = md5_b64 - if ok: - success = True - got_len = got - bad_http_state = 0 - break - - try: - if ("no_header_or_total" in msg) or ("MHTTPREQUEST failed" in msg) or ("MHTTPCREATE failed" in msg): - bad_http_state += 1 - else: - bad_http_state = max(0, bad_http_state - 1) - except: - pass - - if chunk > CHUNK_MIN: - chunk = max(CHUNK_MIN, chunk // 2) - want = min(chunk, want) - buf = bytearray(want) - _log(f"[RETRY] off={offset} want={want} try={k} err={msg}") - _pwr_log(prefix=f" retry{k} off={offset}") - time.sleep_ms(120) - - if not success: - return False, f"chunk_failed off={offset} want={want} err={last_err} total={total_len}" - - # 写入文件(二进制模式) - try: - with open(filename, "r+b") as f: - f.seek(offset) - f.write(bytes(buf)) - except Exception as e: - return False, f"write_failed off={offset}: {e}" - - offset += len(buf) - last_progress_ms = time.ticks_ms() - chunk = CHUNK_MAX - if debug: - _log(f"[OK] offset={offset}/{total_len or '?'}") - - # MD5 校验 - if expect_md5_b64 and hashlib is not None: - try: - with open(filename, "rb") as f: - data = f.read() - digest = hashlib.md5(data).digest() - got_b64 = binascii.b2a_base64(digest).decode().strip() - if got_b64 != expect_md5_b64: - return False, f"md5_mismatch got={got_b64} expected={expect_md5_b64}" - self.logger.debug(f"[4G-DL] MD5 verified: {got_b64}") - except Exception as e: - return False, f"md5_check_failed: {e}" - - t_cost = time.ticks_diff(time.ticks_ms(), t_func0) - self.logger.info(f"[4G-DL] download complete: size={offset} ip={ip} cost_ms={t_cost}") - return True, f"OK size={offset} ip={ip} cost_ms={t_cost}" - - finally: - self._end_ota() - - def direct_ota_download_via_4g(self, ota_url): - """通过 4G 模块下载 OTA(不需要 Wi-Fi)""" - self._set_ota_url(ota_url) - self._set_ota_mode("4g") - self._start_update_thread() - # 延迟导入避免循环依赖 - from network import safe_enqueue + if file_count == 0: + return False, "ZIP中无文件" try: - t_ota0 = time.ticks_ms() - if not ota_url: - safe_enqueue({"result": "ota_failed", "reason": "missing_url"}, 2) - return - - # OTA 全程暂停 TCP(避免心跳/重连抢占 uart4g_lock,导致 server 断链 + HTTP URC 更容易丢) - self._begin_ota() - - # 主动断开 AT TCP,减少 +MIPURC 噪声干扰 HTTP URC 下载 - from network import network_manager - network_manager.disconnect_server() - try: - with network_manager.get_uart_lock(): - hardware_manager.at_client.send("AT+MIPCLOSE=0", "OK", 1500) - except: - pass - - # 从URL中提取文件名(保留原始扩展名) - downloaded_filename = self.get_filename_from_url(ota_url, default_name="main_tmp") - self.logger.info(f"[OTA-4G] 下载文件将保存为: {downloaded_filename}") - - self.logger.info(f"[OTA-4G] 开始通过 4G 下载: {ota_url}") - # 重要说明: - # - AT+MDIALUP / RNDIS 是"USB 主机拨号上网"模式,在不少 ML307R 固件上会占用/切换内部网络栈, - # 从而导致 AT+MIPOPEN / +MIPURC 这套 TCP 连接无法工作(你会看到一直"连接到服务器...")。 - # - 这个设备当前 4G 是走 UART + AT Socket(MIPOPEN),并没有把 4G 变成系统网卡(如 ppp0)。 - # 因此这里不再自动拨号/改路由;只有当系统本来就有 default route(例如 eth0 已联网)时,才尝试走 requests 下载。 - - msg_sys = "" - try: - import power - v = power.get_bus_voltage() - p = power.voltage_to_percent(v) - self.logger.info(f"[OTA-4G][PWR] before_urc v={v:.3f}V p={p}%") - except Exception as e: - self.logger.error(f"[OTA-4G][PWR] before_urc read_failed: {e}") - - t_dl0 = time.ticks_ms() - success, msg = self.download_file_via_4g(ota_url, downloaded_filename, debug=True) - t_dl_cost = time.ticks_diff(time.ticks_ms(), t_dl0) - self.logger.info(f"[OTA-4G] {msg}") - self.logger.info(f"[OTA-4G] download_cost_ms={t_dl_cost}") - - if success and "OK" in msg: - if self.apply_ota_and_reboot(ota_url, downloaded_filename): - return - else: - safe_enqueue({"result": msg_sys or msg}, 2) - - except Exception as e: - error_msg = f"OTA-4G 异常: {str(e)}" - self.logger.error(error_msg) - safe_enqueue({"result": "ota_failed", "reason": error_msg}, 2) - finally: - # 总耗时(注意:若成功并 reboot,这行可能来不及打印) - try: - t_cost = time.ticks_diff(time.ticks_ms(), t_ota0) - self.logger.info(f"[OTA-4G] total_cost_ms={t_cost}") - except: - pass - self._stop_update_thread() - # 对应上面的 _begin_ota() - self._end_ota() - - def handle_wifi_and_update(self, ssid, password, ota_url): - """在子线程中执行 Wi-Fi 连接 + OTA 更新流程""" - self._set_ota_url(ota_url) - self._set_ota_mode("wifi") - self._start_update_thread() - # 延迟导入避免循环导入 - from network import network_manager, safe_enqueue + os.sync() + except: + pass try: - # 与 4G 一致:OTA 期间暂停主循环 / 心跳等 - self._begin_ota() - if not ota_url: - safe_enqueue({"result": "ota_failed", "reason": "missing_url"}, 2) - return - from urllib.parse import urlparse - parsed_url = urlparse(ota_url) - host = parsed_url.hostname - port = parsed_url.port or (443 if parsed_url.scheme == 'https' else 80) + os.remove(zip_path) + except: + pass - # 先连接 WiFi,并把 OTA host:port 作为“可达性验证目标” - # 只有连接成功 + 可访问 OTA 地址,才会把 SSID/PASS 落盘到 /boot/ - ip, error = network_manager.connect_wifi( - ssid, - password, - verify_host=host, - verify_port=port, - persist=True, - ) - if error: - safe_enqueue({"result": "wifi_failed", "error": error}, 2) - return - safe_enqueue({"result": "wifi_connected", "ip": ip}, 2) + self.logger.info(f"[OTA] 已解压 {file_count} 个文件到临时目录,重启后生效") + return True, file_count - downloaded_filename = self.get_filename_from_url(ota_url, default_name="main_tmp") - self.logger.info(f"[OTA] 下载文件将保存为: {downloaded_filename}") - - self.logger.info(f"[NET] 已确认可访问 {host}:{port},开始下载...") - result = self.download_file_via_wifi(ota_url, downloaded_filename) - self.logger.info(result) - - if "成功" in result or "下载成功" in result: - if self.apply_ota_and_reboot(ota_url, downloaded_filename): - return - else: - safe_enqueue({"result": result}, 2) - except Exception as e: - err_msg = f"下载失败: {str(e)}" - safe_enqueue({"result": err_msg}, 2) - self.logger.error(err_msg) - finally: - self._stop_update_thread() - self._end_ota() # 与 4G 一致 - print("[UPDATE] 更新线程执行完毕,即将退出。") - def restore_from_backup(self, backup_dir_path=None): """ 从备份目录恢复所有文件到应用目录 Args: - backup_dir_path: 备份目录路径,如果为None,自动查找最新的备份目录 + backup_dir_path: 备份目录路径,None则自动查找最新备份 Returns: bool: 是否成功恢复 @@ -1265,19 +254,17 @@ class OTAManager: item_path = os.path.join(backup_base, item) if os.path.isdir(item_path) and item.startswith("backup_"): try: - dir_num_str = item.replace("backup_", "") - dir_num = int(dir_num_str) + dir_num = int(item.replace("backup_", "")) backup_dirs.append((item, dir_num)) except: pass if not backup_dirs: - self.logger.error(f"[RESTORE] 没有找到备份目录") + self.logger.error("[RESTORE] 没有找到备份目录") return False backup_dirs.sort(key=lambda x: x[1], reverse=True) - latest_backup = backup_dirs[0][0] - backup_dir_path = os.path.join(backup_base, latest_backup) + backup_dir_path = os.path.join(backup_base, backup_dirs[0][0]) if not os.path.exists(backup_dir_path): self.logger.error(f"[RESTORE] 备份目录不存在: {backup_dir_path}") @@ -1288,26 +275,23 @@ class OTAManager: restored_files = [] for root, dirs, files in os.walk(backup_dir_path): for f in files: - source_path = os.path.join(root, f) - rel_path = os.path.relpath(source_path, backup_dir_path) - dest_path = os.path.join(config.APP_DIR, rel_path) - - dest_dir = os.path.dirname(dest_path) + src = os.path.join(root, f) + rel = os.path.relpath(src, backup_dir_path) + dest = os.path.join(config.APP_DIR, rel) + dest_dir = os.path.dirname(dest) if dest_dir: os.makedirs(dest_dir, exist_ok=True) - try: - shutil.copy2(source_path, dest_path) - restored_files.append(rel_path) - self.logger.info(f"[RESTORE] 已恢复: {rel_path}") + shutil.copy2(src, dest) + restored_files.append(rel) except Exception as e: - self.logger.error(f"[RESTORE] 恢复 {rel_path} 失败: {e}") + self.logger.error(f"[RESTORE] 恢复 {rel} 失败: {e}") if restored_files: self.logger.info(f"[RESTORE] 成功恢复 {len(restored_files)} 个文件") return True else: - self.logger.info(f"[RESTORE] 没有文件被恢复") + self.logger.info("[RESTORE] 没有文件被恢复") return False except Exception as e: @@ -1315,29 +299,19 @@ class OTAManager: return False -# 创建全局单例实例 +# 全局单例 ota_manager = OTAManager() -# ==================== 向后兼容的函数接口 ==================== -# 这些函数会更新 ota_manager 的状态,并调用实际实现 +# ==================== 向后兼容接口 ==================== def apply_ota_and_reboot(ota_url=None, downloaded_file=None): - """应用OTA并重启(向后兼容接口)""" - return ota_manager.apply_ota_and_reboot(ota_url, downloaded_file) - -def direct_ota_download(ota_url): - """直接执行OTA下载(向后兼容接口)""" - return ota_manager.direct_ota_download(ota_url) + return ota_manager.perform_ota(ota_url) def direct_ota_download_via_4g(ota_url): - """通过4G模块下载OTA(向后兼容接口)""" - return ota_manager.direct_ota_download_via_4g(ota_url) + return ota_manager.perform_ota(ota_url) def handle_wifi_and_update(ssid, password, ota_url): - """处理WiFi连接并更新(向后兼容接口)""" - return ota_manager.handle_wifi_and_update(ssid, password, ota_url) + return ota_manager.perform_ota(ota_url) def restore_from_backup(backup_dir_path=None): - """从备份恢复(向后兼容接口)""" return ota_manager.restore_from_backup(backup_dir_path) - diff --git a/tcp_messages_pb2.py b/tcp_messages_pb2.py index 7ffd3ce..1f02081 100644 --- a/tcp_messages_pb2.py +++ b/tcp_messages_pb2.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Generated by the protocol buffer compiler. DO NOT EDIT! -# source: tcp_messages.proto +# source: proto/tcp_messages.proto """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -14,7 +14,7 @@ _sym_db = _symbol_database.Default() -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x12tcp_messages.proto\x12\x03tcp\"\x83\x01\n\x0cLoginRequest\x12\x11\n\tdevice_id\x18\x01 \x01(\t\x12\x10\n\x08password\x18\x02 \x01(\t\x12\x10\n\x08if_admin\x18\x03 \x01(\x08\x12\x0f\n\x07version\x18\x04 \x01(\t\x12\x0b\n\x03vol\x18\x05 \x01(\x01\x12\x0f\n\x07vol_per\x18\x06 \x01(\x01\x12\r\n\x05iccid\x18\x07 \x01(\t\"*\n\rLoginResponse\x12\x0b\n\x03\x63md\x18\x01 \x01(\r\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\t\"4\n\tHeartbeat\x12\t\n\x01t\x18\x01 \x01(\x03\x12\x0b\n\x03vol\x18\x02 \x01(\x01\x12\x0f\n\x07vol_per\x18\x03 \x01(\x01\"&\n\tLogicBody\x12\x0b\n\x03\x63md\x18\x01 \x01(\r\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\")\n\x0cResponseBody\x12\x0b\n\x03\x63md\x18\x01 \x01(\r\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\"@\n\x0bMonitorBody\x12\x11\n\tdevice_id\x18\x01 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x10\n\x08msg_type\x18\x03 \x01(\r\",\n\x16MonitorDevicesResponse\x12\x12\n\ndevice_ids\x18\x01 \x03(\t\"9\n\x0bOtaFragment\x12\t\n\x01l\x18\x01 \x01(\x05\x12\t\n\x01\x64\x18\x02 \x01(\t\x12\t\n\x01t\x18\x03 \x01(\x05\x12\t\n\x01v\x18\x04 \x01(\t\"\xab\x02\n\tShootData\x12\x0f\n\x07shot_id\x18\x01 \x01(\t\x12\t\n\x01x\x18\x02 \x01(\x01\x12\t\n\x01y\x18\x03 \x01(\x01\x12\t\n\x01r\x18\x04 \x01(\x01\x12\t\n\x01\x64\x18\x05 \x01(\x01\x12\x0b\n\x03\x61\x64\x63\x18\x06 \x01(\x01\x12\x14\n\x0ctarget_class\x18\x07 \x01(\t\x12\x1f\n\x17target_class_confidence\x18\x08 \x01(\x01\x12\x0f\n\x07\x64_laser\x18\t \x01(\x01\x12\x17\n\x0f\x64_laser_quality\x18\n \x01(\x01\x12\t\n\x01m\x18\x0b \x01(\t\x12\x14\n\x0claser_method\x18\x0c \x01(\t\x12\x10\n\x08target_x\x18\r \x01(\x01\x12\x10\n\x08target_y\x18\x0e \x01(\x01\x12\x15\n\roffset_method\x18\x0f \x01(\t\x12\x17\n\x0f\x64istance_method\x18\x10 \x01(\t\"!\n\nShootEvent\x12\x13\n\x0bshoot_event\x18\x01 \x01(\t\"C\n\rBatteryReport\x12\x0f\n\x07\x62\x61ttery\x18\x01 \x01(\x01\x12\x0f\n\x07voltage\x18\x02 \x01(\x01\x12\x10\n\x08net_type\x18\x03 \x01(\t\"9\n\x11\x43\x65nterPointResult\x12\x0e\n\x06result\x18\x01 \x01(\t\x12\t\n\x01x\x18\x02 \x01(\x01\x12\t\n\x01y\x18\x03 \x01(\x01\"3\n\x0e\x43\x65nterPointSet\x12\x0b\n\x03\x63md\x18\x01 \x01(\r\x12\t\n\x01x\x18\x02 \x01(\x01\x12\t\n\x01y\x18\x03 \x01(\x01\"(\n\tOtaResult\x12\x0e\n\x06result\x18\x01 \x01(\t\x12\x0b\n\x03url\x18\x02 \x01(\t\"\x1f\n\rGenericResult\x12\x0e\n\x06result\x18\x01 \x01(\t\"&\n\x08IpReport\x12\x0e\n\x06result\x18\x01 \x01(\t\x12\n\n\x02ip\x18\x02 \x01(\t\"Z\n\x12ImageUploadCommand\x12\x12\n\nupload_url\x18\x01 \x01(\t\x12\r\n\x05token\x18\x02 \x01(\t\x12\x10\n\x08shoot_id\x18\x03 \x01(\t\x12\x0f\n\x07outlink\x18\x04 \x01(\t\"d\n\x10LogUploadCommand\x12\x12\n\nupload_url\x18\x01 \x01(\t\x12\r\n\x05token\x18\x02 \x01(\t\x12\x0b\n\x03key\x18\x03 \x01(\t\x12\x0f\n\x07outlink\x18\x04 \x01(\t\x12\x0f\n\x07\x61rchive\x18\x05 \x01(\t\"K\n\x0eOtaRequestData\x12\x0c\n\x04ssid\x18\x01 \x01(\t\x12\x10\n\x08password\x18\x02 \x01(\t\x12\x0b\n\x03url\x18\x03 \x01(\t\x12\x0c\n\x04mode\x18\x04 \x01(\t\"1\n\x0fWifiConnectData\x12\x0c\n\x04ssid\x18\x01 \x01(\t\x12\x10\n\x08password\x18\x02 \x01(\t\"_\n\x11ImageUploadResult\x12\x0e\n\x06result\x18\x01 \x01(\t\x12\x10\n\x08shoot_id\x18\x02 \x01(\t\x12\x0b\n\x03key\x18\x03 \x01(\t\x12\x0e\n\x06reason\x18\x04 \x01(\t\x12\x0b\n\x03via\x18\x05 \x01(\t\"v\n\x0fLogUploadResult\x12\x0e\n\x06result\x18\x01 \x01(\t\x12\x0e\n\x06reason\x18\x02 \x01(\t\x12\x10\n\x08\x66ilename\x18\x03 \x01(\t\x12\x13\n\x0bstatus_code\x18\x04 \x01(\x05\x12\x0c\n\x04ssid\x18\x05 \x01(\t\x12\x0e\n\x06\x64\x65tail\x18\x06 \x01(\t\"J\n\x14\x42\x61tteryQueryResponse\x12\x0f\n\x07\x62\x61ttery\x18\x01 \x01(\x01\x12\x0f\n\x07voltage\x18\x02 \x01(\x01\x12\x10\n\x08net_type\x18\x03 \x01(\t\"\'\n\x0fOta4gSubCodeReq\x12\t\n\x01l\x18\x01 \x01(\x05\x12\t\n\x01v\x18\x02 \x01(\t\"5\n\x10Ota4gSubCodeResp\x12\x0b\n\x03\x63md\x18\x01 \x01(\r\x12\t\n\x01l\x18\x02 \x01(\x05\x12\t\n\x01v\x18\x03 \x01(\t\"\x1e\n\x0fShutdownCommand\x12\x0b\n\x03\x63md\x18\x01 \x01(\r\" \n\x0c\x41utoShutdown\x12\x10\n\x08poweroff\x18\x01 \x01(\tBB\n\rcom.shoot.tcpZ1git.shelingxingqiu.com/shoot-tcp-server/proto;tcpb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x18proto/tcp_messages.proto\x12\x03tcp\"\x83\x01\n\x0cLoginRequest\x12\x11\n\tdevice_id\x18\x01 \x01(\t\x12\x10\n\x08password\x18\x02 \x01(\t\x12\x10\n\x08if_admin\x18\x03 \x01(\x08\x12\x0f\n\x07version\x18\x04 \x01(\t\x12\x0b\n\x03vol\x18\x05 \x01(\x01\x12\x0f\n\x07vol_per\x18\x06 \x01(\x01\x12\r\n\x05iccid\x18\x07 \x01(\t\"*\n\rLoginResponse\x12\x0c\n\x04\x63ode\x18\x01 \x01(\r\x12\x0b\n\x03msg\x18\x02 \x01(\t\"4\n\tHeartbeat\x12\t\n\x01t\x18\x01 \x01(\x03\x12\x0b\n\x03vol\x18\x02 \x01(\x01\x12\x0f\n\x07vol_per\x18\x03 \x01(\x01\"\xb3\n\n\tLogicBody\x12\x0b\n\x03\x63md\x18\x01 \x01(\r\x12$\n\nshoot_data\x18\n \x01(\x0b\x32\x0e.tcp.ShootDataH\x00\x12&\n\x0bshoot_event\x18\x0b \x01(\x0b\x32\x0f.tcp.ShootEventH\x00\x12,\n\x0e\x62\x61ttery_report\x18\x0c \x01(\x0b\x32\x12.tcp.BatteryReportH\x00\x12&\n\x0b\x61im_request\x18\r \x01(\x0b\x32\x0f.tcp.AimRequestH\x00\x12\x31\n\x11\x63lose_aim_request\x18\x0e \x01(\x0b\x32\x14.tcp.CloseAimRequestH\x00\x12&\n\x0bota_request\x18\x0f \x01(\x0b\x32\x0f.tcp.OtaRequestH\x00\x12:\n\x16ota4g_sub_code_request\x18\x10 \x01(\x0b\x32\x18.tcp.Ota4gSubCodeRequestH\x00\x12<\n\x17ota4g_sub_code_response\x18\x11 \x01(\x0b\x32\x19.tcp.Ota4gSubCodeResponseH\x00\x12\x37\n\x14wifi_connect_request\x18\x12 \x01(\x0b\x32\x17.tcp.WifiConnectRequestH\x00\x12\x35\n\x13\x63\x65nter_point_result\x18\x13 \x01(\x0b\x32\x16.tcp.CenterPointResultH\x00\x12/\n\x10\x63\x65nter_point_set\x18\x14 \x01(\x0b\x32\x13.tcp.CenterPointSetH\x00\x12.\n\x0f\x63harging_report\x18\x15 \x01(\x0b\x32\x13.tcp.ChargingReportH\x00\x12,\n\x0egeneric_result\x18\x16 \x01(\x0b\x32\x12.tcp.GenericResultH\x00\x12\x37\n\x14image_upload_command\x18\x17 \x01(\x0b\x32\x17.tcp.ImageUploadCommandH\x00\x12\x33\n\x12log_upload_command\x18\x18 \x01(\x0b\x32\x15.tcp.LogUploadCommandH\x00\x12\x35\n\x13image_upload_result\x18\x19 \x01(\x0b\x32\x16.tcp.ImageUploadResultH\x00\x12\x31\n\x11log_upload_result\x18\x1a \x01(\x0b\x32\x14.tcp.LogUploadResultH\x00\x12$\n\nota_result\x18\x1b \x01(\x0b\x32\x0e.tcp.OtaResultH\x00\x12)\n\x0b\x66ile_string\x18\x1c \x01(\x0b\x32\x12.tcp.FileStringMsgH\x00\x12\"\n\tip_report\x18\x1d \x01(\x0b\x32\r.tcp.IpReportH\x00\x12\x35\n\x13get_battery_request\x18\x1e \x01(\x0b\x32\x16.tcp.GetBatteryRequestH\x00\x12>\n\x18set_center_point_request\x18\x1f \x01(\x0b\x32\x1a.tcp.SetCenterPointRequestH\x00\x12\x30\n\x10shutdown_command\x18 \x01(\x0b\x32\x14.tcp.ShutdownCommandH\x00\x12\x38\n\x15get_shoot_pic_request\x18! \x01(\x0b\x32\x17.tcp.GetShootPicRequestH\x00\x12/\n\x10push_log_request\x18\" \x01(\x0b\x32\x13.tcp.PushLogRequestH\x00\x12\x35\n\x13wifi_status_request\x18# \x01(\x0b\x32\x16.tcp.WifiStatusRequestH\x00\x42\t\n\x07payload\"@\n\x0bMonitorBody\x12\x11\n\tdevice_id\x18\x01 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x10\n\x08msg_type\x18\x03 \x01(\r\",\n\x16MonitorDevicesResponse\x12\x12\n\ndevice_ids\x18\x01 \x03(\t\"9\n\x0bOtaFragment\x12\t\n\x01l\x18\x01 \x01(\x05\x12\t\n\x01\x64\x18\x02 \x01(\t\x12\t\n\x01t\x18\x03 \x01(\x05\x12\t\n\x01v\x18\x04 \x01(\t\"\xab\x02\n\tShootData\x12\x0f\n\x07shot_id\x18\x01 \x01(\t\x12\t\n\x01x\x18\x02 \x01(\x01\x12\t\n\x01y\x18\x03 \x01(\x01\x12\t\n\x01r\x18\x04 \x01(\x01\x12\t\n\x01\x64\x18\x05 \x01(\x01\x12\x0b\n\x03\x61\x64\x63\x18\x06 \x01(\x01\x12\x14\n\x0ctarget_class\x18\x07 \x01(\t\x12\x1f\n\x17target_class_confidence\x18\x08 \x01(\x01\x12\x0f\n\x07\x64_laser\x18\t \x01(\x01\x12\x17\n\x0f\x64_laser_quality\x18\n \x01(\x01\x12\t\n\x01m\x18\x0b \x01(\t\x12\x14\n\x0claser_method\x18\x0c \x01(\t\x12\x10\n\x08target_x\x18\r \x01(\x01\x12\x10\n\x08target_y\x18\x0e \x01(\x01\x12\x15\n\roffset_method\x18\x0f \x01(\t\x12\x17\n\x0f\x64istance_method\x18\x10 \x01(\t\"!\n\nShootEvent\x12\x13\n\x0bshoot_event\x18\x01 \x01(\t\"U\n\rBatteryReport\x12\x0f\n\x07\x62\x61ttery\x18\x01 \x01(\x01\x12\x0f\n\x07voltage\x18\x02 \x01(\x01\x12\x10\n\x08net_type\x18\x03 \x01(\t\x12\x10\n\x08\x63harging\x18\x04 \x01(\x08\"\x0c\n\nAimRequest\"\x11\n\x0f\x43loseAimRequest\"G\n\nOtaRequest\x12\x0c\n\x04ssid\x18\x01 \x01(\t\x12\x10\n\x08password\x18\x02 \x01(\t\x12\x0b\n\x03url\x18\x03 \x01(\t\x12\x0c\n\x04mode\x18\x04 \x01(\t\"+\n\x13Ota4gSubCodeRequest\x12\t\n\x01l\x18\x01 \x01(\x05\x12\t\n\x01v\x18\x02 \x01(\t\",\n\x14Ota4gSubCodeResponse\x12\t\n\x01l\x18\x01 \x01(\x05\x12\t\n\x01v\x18\x02 \x01(\t\"4\n\x12WifiConnectRequest\x12\x0c\n\x04ssid\x18\x01 \x01(\t\x12\x10\n\x08password\x18\x02 \x01(\t\"9\n\x11\x43\x65nterPointResult\x12\x0e\n\x06result\x18\x01 \x01(\t\x12\t\n\x01x\x18\x02 \x01(\x01\x12\t\n\x01y\x18\x03 \x01(\x01\"&\n\x0e\x43\x65nterPointSet\x12\t\n\x01x\x18\x01 \x01(\x01\x12\t\n\x01y\x18\x02 \x01(\x01\"\x10\n\x0e\x43hargingReport\"\x1f\n\rGenericResult\x12\x0e\n\x06result\x18\x01 \x01(\t\"Z\n\x12ImageUploadCommand\x12\x12\n\nupload_url\x18\x01 \x01(\t\x12\r\n\x05token\x18\x02 \x01(\t\x12\x10\n\x08shoot_id\x18\x03 \x01(\t\x12\x0f\n\x07outlink\x18\x04 \x01(\t\"d\n\x10LogUploadCommand\x12\x12\n\nupload_url\x18\x01 \x01(\t\x12\r\n\x05token\x18\x02 \x01(\t\x12\x0b\n\x03key\x18\x03 \x01(\t\x12\x0f\n\x07outlink\x18\x04 \x01(\t\x12\x0f\n\x07\x61rchive\x18\x05 \x01(\t\"_\n\x11ImageUploadResult\x12\x0e\n\x06result\x18\x01 \x01(\t\x12\x10\n\x08shoot_id\x18\x02 \x01(\t\x12\x0b\n\x03key\x18\x03 \x01(\t\x12\x0e\n\x06reason\x18\x04 \x01(\t\x12\x0b\n\x03via\x18\x05 \x01(\t\"v\n\x0fLogUploadResult\x12\x0e\n\x06result\x18\x01 \x01(\t\x12\x0e\n\x06reason\x18\x02 \x01(\t\x12\x10\n\x08\x66ilename\x18\x03 \x01(\t\x12\x13\n\x0bstatus_code\x18\x04 \x01(\x05\x12\x0c\n\x04ssid\x18\x05 \x01(\t\x12\x0e\n\x06\x64\x65tail\x18\x06 \x01(\t\"I\n\tOtaResult\x12\x0e\n\x06result\x18\x01 \x01(\t\x12\x0b\n\x03url\x18\x02 \x01(\t\x12\x10\n\x08progress\x18\x03 \x01(\x05\x12\r\n\x05phase\x18\x04 \x01(\t\";\n\rFileStringMsg\x12\t\n\x01l\x18\x01 \x01(\x05\x12\t\n\x01\x64\x18\x02 \x01(\t\x12\t\n\x01t\x18\x03 \x01(\x05\x12\t\n\x01v\x18\x04 \x01(\t\"&\n\x08IpReport\x12\x0e\n\x06result\x18\x01 \x01(\t\x12\n\n\x02ip\x18\x02 \x01(\t\"\x13\n\x11GetBatteryRequest\"-\n\x15SetCenterPointRequest\x12\t\n\x01x\x18\x01 \x01(\x01\x12\t\n\x01y\x18\x02 \x01(\x01\"\x11\n\x0fShutdownCommand\"&\n\x12GetShootPicRequest\x12\x10\n\x08shoot_id\x18\x01 \x01(\t\"\x10\n\x0ePushLogRequest\"\x13\n\x11WifiStatusRequestBB\n\rcom.shoot.tcpZ1git.shelingxingqiu.com/shoot-tcp-server/proto;tcpb\x06proto3') @@ -22,274 +22,334 @@ _LOGINREQUEST = DESCRIPTOR.message_types_by_name['LoginRequest'] _LOGINRESPONSE = DESCRIPTOR.message_types_by_name['LoginResponse'] _HEARTBEAT = DESCRIPTOR.message_types_by_name['Heartbeat'] _LOGICBODY = DESCRIPTOR.message_types_by_name['LogicBody'] -_RESPONSEBODY = DESCRIPTOR.message_types_by_name['ResponseBody'] _MONITORBODY = DESCRIPTOR.message_types_by_name['MonitorBody'] _MONITORDEVICESRESPONSE = DESCRIPTOR.message_types_by_name['MonitorDevicesResponse'] _OTAFRAGMENT = DESCRIPTOR.message_types_by_name['OtaFragment'] _SHOOTDATA = DESCRIPTOR.message_types_by_name['ShootData'] _SHOOTEVENT = DESCRIPTOR.message_types_by_name['ShootEvent'] _BATTERYREPORT = DESCRIPTOR.message_types_by_name['BatteryReport'] +_AIMREQUEST = DESCRIPTOR.message_types_by_name['AimRequest'] +_CLOSEAIMREQUEST = DESCRIPTOR.message_types_by_name['CloseAimRequest'] +_OTAREQUEST = DESCRIPTOR.message_types_by_name['OtaRequest'] +_OTA4GSUBCODEREQUEST = DESCRIPTOR.message_types_by_name['Ota4gSubCodeRequest'] +_OTA4GSUBCODERESPONSE = DESCRIPTOR.message_types_by_name['Ota4gSubCodeResponse'] +_WIFICONNECTREQUEST = DESCRIPTOR.message_types_by_name['WifiConnectRequest'] _CENTERPOINTRESULT = DESCRIPTOR.message_types_by_name['CenterPointResult'] _CENTERPOINTSET = DESCRIPTOR.message_types_by_name['CenterPointSet'] -_OTARESULT = DESCRIPTOR.message_types_by_name['OtaResult'] +_CHARGINGREPORT = DESCRIPTOR.message_types_by_name['ChargingReport'] _GENERICRESULT = DESCRIPTOR.message_types_by_name['GenericResult'] -_IPREPORT = DESCRIPTOR.message_types_by_name['IpReport'] _IMAGEUPLOADCOMMAND = DESCRIPTOR.message_types_by_name['ImageUploadCommand'] _LOGUPLOADCOMMAND = DESCRIPTOR.message_types_by_name['LogUploadCommand'] -_OTAREQUESTDATA = DESCRIPTOR.message_types_by_name['OtaRequestData'] -_WIFICONNECTDATA = DESCRIPTOR.message_types_by_name['WifiConnectData'] _IMAGEUPLOADRESULT = DESCRIPTOR.message_types_by_name['ImageUploadResult'] _LOGUPLOADRESULT = DESCRIPTOR.message_types_by_name['LogUploadResult'] -_BATTERYQUERYRESPONSE = DESCRIPTOR.message_types_by_name['BatteryQueryResponse'] -_OTA4GSUBCODEREQ = DESCRIPTOR.message_types_by_name['Ota4gSubCodeReq'] -_OTA4GSUBCODERESP = DESCRIPTOR.message_types_by_name['Ota4gSubCodeResp'] +_OTARESULT = DESCRIPTOR.message_types_by_name['OtaResult'] +_FILESTRINGMSG = DESCRIPTOR.message_types_by_name['FileStringMsg'] +_IPREPORT = DESCRIPTOR.message_types_by_name['IpReport'] +_GETBATTERYREQUEST = DESCRIPTOR.message_types_by_name['GetBatteryRequest'] +_SETCENTERPOINTREQUEST = DESCRIPTOR.message_types_by_name['SetCenterPointRequest'] _SHUTDOWNCOMMAND = DESCRIPTOR.message_types_by_name['ShutdownCommand'] -_AUTOSHUTDOWN = DESCRIPTOR.message_types_by_name['AutoShutdown'] +_GETSHOOTPICREQUEST = DESCRIPTOR.message_types_by_name['GetShootPicRequest'] +_PUSHLOGREQUEST = DESCRIPTOR.message_types_by_name['PushLogRequest'] +_WIFISTATUSREQUEST = DESCRIPTOR.message_types_by_name['WifiStatusRequest'] LoginRequest = _reflection.GeneratedProtocolMessageType('LoginRequest', (_message.Message,), { 'DESCRIPTOR' : _LOGINREQUEST, - '__module__' : 'tcp_messages_pb2' + '__module__' : 'proto.tcp_messages_pb2' # @@protoc_insertion_point(class_scope:tcp.LoginRequest) }) _sym_db.RegisterMessage(LoginRequest) LoginResponse = _reflection.GeneratedProtocolMessageType('LoginResponse', (_message.Message,), { 'DESCRIPTOR' : _LOGINRESPONSE, - '__module__' : 'tcp_messages_pb2' + '__module__' : 'proto.tcp_messages_pb2' # @@protoc_insertion_point(class_scope:tcp.LoginResponse) }) _sym_db.RegisterMessage(LoginResponse) Heartbeat = _reflection.GeneratedProtocolMessageType('Heartbeat', (_message.Message,), { 'DESCRIPTOR' : _HEARTBEAT, - '__module__' : 'tcp_messages_pb2' + '__module__' : 'proto.tcp_messages_pb2' # @@protoc_insertion_point(class_scope:tcp.Heartbeat) }) _sym_db.RegisterMessage(Heartbeat) LogicBody = _reflection.GeneratedProtocolMessageType('LogicBody', (_message.Message,), { 'DESCRIPTOR' : _LOGICBODY, - '__module__' : 'tcp_messages_pb2' + '__module__' : 'proto.tcp_messages_pb2' # @@protoc_insertion_point(class_scope:tcp.LogicBody) }) _sym_db.RegisterMessage(LogicBody) -ResponseBody = _reflection.GeneratedProtocolMessageType('ResponseBody', (_message.Message,), { - 'DESCRIPTOR' : _RESPONSEBODY, - '__module__' : 'tcp_messages_pb2' - # @@protoc_insertion_point(class_scope:tcp.ResponseBody) - }) -_sym_db.RegisterMessage(ResponseBody) - MonitorBody = _reflection.GeneratedProtocolMessageType('MonitorBody', (_message.Message,), { 'DESCRIPTOR' : _MONITORBODY, - '__module__' : 'tcp_messages_pb2' + '__module__' : 'proto.tcp_messages_pb2' # @@protoc_insertion_point(class_scope:tcp.MonitorBody) }) _sym_db.RegisterMessage(MonitorBody) MonitorDevicesResponse = _reflection.GeneratedProtocolMessageType('MonitorDevicesResponse', (_message.Message,), { 'DESCRIPTOR' : _MONITORDEVICESRESPONSE, - '__module__' : 'tcp_messages_pb2' + '__module__' : 'proto.tcp_messages_pb2' # @@protoc_insertion_point(class_scope:tcp.MonitorDevicesResponse) }) _sym_db.RegisterMessage(MonitorDevicesResponse) OtaFragment = _reflection.GeneratedProtocolMessageType('OtaFragment', (_message.Message,), { 'DESCRIPTOR' : _OTAFRAGMENT, - '__module__' : 'tcp_messages_pb2' + '__module__' : 'proto.tcp_messages_pb2' # @@protoc_insertion_point(class_scope:tcp.OtaFragment) }) _sym_db.RegisterMessage(OtaFragment) ShootData = _reflection.GeneratedProtocolMessageType('ShootData', (_message.Message,), { 'DESCRIPTOR' : _SHOOTDATA, - '__module__' : 'tcp_messages_pb2' + '__module__' : 'proto.tcp_messages_pb2' # @@protoc_insertion_point(class_scope:tcp.ShootData) }) _sym_db.RegisterMessage(ShootData) ShootEvent = _reflection.GeneratedProtocolMessageType('ShootEvent', (_message.Message,), { 'DESCRIPTOR' : _SHOOTEVENT, - '__module__' : 'tcp_messages_pb2' + '__module__' : 'proto.tcp_messages_pb2' # @@protoc_insertion_point(class_scope:tcp.ShootEvent) }) _sym_db.RegisterMessage(ShootEvent) BatteryReport = _reflection.GeneratedProtocolMessageType('BatteryReport', (_message.Message,), { 'DESCRIPTOR' : _BATTERYREPORT, - '__module__' : 'tcp_messages_pb2' + '__module__' : 'proto.tcp_messages_pb2' # @@protoc_insertion_point(class_scope:tcp.BatteryReport) }) _sym_db.RegisterMessage(BatteryReport) +AimRequest = _reflection.GeneratedProtocolMessageType('AimRequest', (_message.Message,), { + 'DESCRIPTOR' : _AIMREQUEST, + '__module__' : 'proto.tcp_messages_pb2' + # @@protoc_insertion_point(class_scope:tcp.AimRequest) + }) +_sym_db.RegisterMessage(AimRequest) + +CloseAimRequest = _reflection.GeneratedProtocolMessageType('CloseAimRequest', (_message.Message,), { + 'DESCRIPTOR' : _CLOSEAIMREQUEST, + '__module__' : 'proto.tcp_messages_pb2' + # @@protoc_insertion_point(class_scope:tcp.CloseAimRequest) + }) +_sym_db.RegisterMessage(CloseAimRequest) + +OtaRequest = _reflection.GeneratedProtocolMessageType('OtaRequest', (_message.Message,), { + 'DESCRIPTOR' : _OTAREQUEST, + '__module__' : 'proto.tcp_messages_pb2' + # @@protoc_insertion_point(class_scope:tcp.OtaRequest) + }) +_sym_db.RegisterMessage(OtaRequest) + +Ota4gSubCodeRequest = _reflection.GeneratedProtocolMessageType('Ota4gSubCodeRequest', (_message.Message,), { + 'DESCRIPTOR' : _OTA4GSUBCODEREQUEST, + '__module__' : 'proto.tcp_messages_pb2' + # @@protoc_insertion_point(class_scope:tcp.Ota4gSubCodeRequest) + }) +_sym_db.RegisterMessage(Ota4gSubCodeRequest) + +Ota4gSubCodeResponse = _reflection.GeneratedProtocolMessageType('Ota4gSubCodeResponse', (_message.Message,), { + 'DESCRIPTOR' : _OTA4GSUBCODERESPONSE, + '__module__' : 'proto.tcp_messages_pb2' + # @@protoc_insertion_point(class_scope:tcp.Ota4gSubCodeResponse) + }) +_sym_db.RegisterMessage(Ota4gSubCodeResponse) + +WifiConnectRequest = _reflection.GeneratedProtocolMessageType('WifiConnectRequest', (_message.Message,), { + 'DESCRIPTOR' : _WIFICONNECTREQUEST, + '__module__' : 'proto.tcp_messages_pb2' + # @@protoc_insertion_point(class_scope:tcp.WifiConnectRequest) + }) +_sym_db.RegisterMessage(WifiConnectRequest) + CenterPointResult = _reflection.GeneratedProtocolMessageType('CenterPointResult', (_message.Message,), { 'DESCRIPTOR' : _CENTERPOINTRESULT, - '__module__' : 'tcp_messages_pb2' + '__module__' : 'proto.tcp_messages_pb2' # @@protoc_insertion_point(class_scope:tcp.CenterPointResult) }) _sym_db.RegisterMessage(CenterPointResult) CenterPointSet = _reflection.GeneratedProtocolMessageType('CenterPointSet', (_message.Message,), { 'DESCRIPTOR' : _CENTERPOINTSET, - '__module__' : 'tcp_messages_pb2' + '__module__' : 'proto.tcp_messages_pb2' # @@protoc_insertion_point(class_scope:tcp.CenterPointSet) }) _sym_db.RegisterMessage(CenterPointSet) -OtaResult = _reflection.GeneratedProtocolMessageType('OtaResult', (_message.Message,), { - 'DESCRIPTOR' : _OTARESULT, - '__module__' : 'tcp_messages_pb2' - # @@protoc_insertion_point(class_scope:tcp.OtaResult) +ChargingReport = _reflection.GeneratedProtocolMessageType('ChargingReport', (_message.Message,), { + 'DESCRIPTOR' : _CHARGINGREPORT, + '__module__' : 'proto.tcp_messages_pb2' + # @@protoc_insertion_point(class_scope:tcp.ChargingReport) }) -_sym_db.RegisterMessage(OtaResult) +_sym_db.RegisterMessage(ChargingReport) GenericResult = _reflection.GeneratedProtocolMessageType('GenericResult', (_message.Message,), { 'DESCRIPTOR' : _GENERICRESULT, - '__module__' : 'tcp_messages_pb2' + '__module__' : 'proto.tcp_messages_pb2' # @@protoc_insertion_point(class_scope:tcp.GenericResult) }) _sym_db.RegisterMessage(GenericResult) -IpReport = _reflection.GeneratedProtocolMessageType('IpReport', (_message.Message,), { - 'DESCRIPTOR' : _IPREPORT, - '__module__' : 'tcp_messages_pb2' - # @@protoc_insertion_point(class_scope:tcp.IpReport) - }) -_sym_db.RegisterMessage(IpReport) - ImageUploadCommand = _reflection.GeneratedProtocolMessageType('ImageUploadCommand', (_message.Message,), { 'DESCRIPTOR' : _IMAGEUPLOADCOMMAND, - '__module__' : 'tcp_messages_pb2' + '__module__' : 'proto.tcp_messages_pb2' # @@protoc_insertion_point(class_scope:tcp.ImageUploadCommand) }) _sym_db.RegisterMessage(ImageUploadCommand) LogUploadCommand = _reflection.GeneratedProtocolMessageType('LogUploadCommand', (_message.Message,), { 'DESCRIPTOR' : _LOGUPLOADCOMMAND, - '__module__' : 'tcp_messages_pb2' + '__module__' : 'proto.tcp_messages_pb2' # @@protoc_insertion_point(class_scope:tcp.LogUploadCommand) }) _sym_db.RegisterMessage(LogUploadCommand) -OtaRequestData = _reflection.GeneratedProtocolMessageType('OtaRequestData', (_message.Message,), { - 'DESCRIPTOR' : _OTAREQUESTDATA, - '__module__' : 'tcp_messages_pb2' - # @@protoc_insertion_point(class_scope:tcp.OtaRequestData) - }) -_sym_db.RegisterMessage(OtaRequestData) - -WifiConnectData = _reflection.GeneratedProtocolMessageType('WifiConnectData', (_message.Message,), { - 'DESCRIPTOR' : _WIFICONNECTDATA, - '__module__' : 'tcp_messages_pb2' - # @@protoc_insertion_point(class_scope:tcp.WifiConnectData) - }) -_sym_db.RegisterMessage(WifiConnectData) - ImageUploadResult = _reflection.GeneratedProtocolMessageType('ImageUploadResult', (_message.Message,), { 'DESCRIPTOR' : _IMAGEUPLOADRESULT, - '__module__' : 'tcp_messages_pb2' + '__module__' : 'proto.tcp_messages_pb2' # @@protoc_insertion_point(class_scope:tcp.ImageUploadResult) }) _sym_db.RegisterMessage(ImageUploadResult) LogUploadResult = _reflection.GeneratedProtocolMessageType('LogUploadResult', (_message.Message,), { 'DESCRIPTOR' : _LOGUPLOADRESULT, - '__module__' : 'tcp_messages_pb2' + '__module__' : 'proto.tcp_messages_pb2' # @@protoc_insertion_point(class_scope:tcp.LogUploadResult) }) _sym_db.RegisterMessage(LogUploadResult) -BatteryQueryResponse = _reflection.GeneratedProtocolMessageType('BatteryQueryResponse', (_message.Message,), { - 'DESCRIPTOR' : _BATTERYQUERYRESPONSE, - '__module__' : 'tcp_messages_pb2' - # @@protoc_insertion_point(class_scope:tcp.BatteryQueryResponse) +OtaResult = _reflection.GeneratedProtocolMessageType('OtaResult', (_message.Message,), { + 'DESCRIPTOR' : _OTARESULT, + '__module__' : 'proto.tcp_messages_pb2' + # @@protoc_insertion_point(class_scope:tcp.OtaResult) }) -_sym_db.RegisterMessage(BatteryQueryResponse) +_sym_db.RegisterMessage(OtaResult) -Ota4gSubCodeReq = _reflection.GeneratedProtocolMessageType('Ota4gSubCodeReq', (_message.Message,), { - 'DESCRIPTOR' : _OTA4GSUBCODEREQ, - '__module__' : 'tcp_messages_pb2' - # @@protoc_insertion_point(class_scope:tcp.Ota4gSubCodeReq) +FileStringMsg = _reflection.GeneratedProtocolMessageType('FileStringMsg', (_message.Message,), { + 'DESCRIPTOR' : _FILESTRINGMSG, + '__module__' : 'proto.tcp_messages_pb2' + # @@protoc_insertion_point(class_scope:tcp.FileStringMsg) }) -_sym_db.RegisterMessage(Ota4gSubCodeReq) +_sym_db.RegisterMessage(FileStringMsg) -Ota4gSubCodeResp = _reflection.GeneratedProtocolMessageType('Ota4gSubCodeResp', (_message.Message,), { - 'DESCRIPTOR' : _OTA4GSUBCODERESP, - '__module__' : 'tcp_messages_pb2' - # @@protoc_insertion_point(class_scope:tcp.Ota4gSubCodeResp) +IpReport = _reflection.GeneratedProtocolMessageType('IpReport', (_message.Message,), { + 'DESCRIPTOR' : _IPREPORT, + '__module__' : 'proto.tcp_messages_pb2' + # @@protoc_insertion_point(class_scope:tcp.IpReport) }) -_sym_db.RegisterMessage(Ota4gSubCodeResp) +_sym_db.RegisterMessage(IpReport) + +GetBatteryRequest = _reflection.GeneratedProtocolMessageType('GetBatteryRequest', (_message.Message,), { + 'DESCRIPTOR' : _GETBATTERYREQUEST, + '__module__' : 'proto.tcp_messages_pb2' + # @@protoc_insertion_point(class_scope:tcp.GetBatteryRequest) + }) +_sym_db.RegisterMessage(GetBatteryRequest) + +SetCenterPointRequest = _reflection.GeneratedProtocolMessageType('SetCenterPointRequest', (_message.Message,), { + 'DESCRIPTOR' : _SETCENTERPOINTREQUEST, + '__module__' : 'proto.tcp_messages_pb2' + # @@protoc_insertion_point(class_scope:tcp.SetCenterPointRequest) + }) +_sym_db.RegisterMessage(SetCenterPointRequest) ShutdownCommand = _reflection.GeneratedProtocolMessageType('ShutdownCommand', (_message.Message,), { 'DESCRIPTOR' : _SHUTDOWNCOMMAND, - '__module__' : 'tcp_messages_pb2' + '__module__' : 'proto.tcp_messages_pb2' # @@protoc_insertion_point(class_scope:tcp.ShutdownCommand) }) _sym_db.RegisterMessage(ShutdownCommand) -AutoShutdown = _reflection.GeneratedProtocolMessageType('AutoShutdown', (_message.Message,), { - 'DESCRIPTOR' : _AUTOSHUTDOWN, - '__module__' : 'tcp_messages_pb2' - # @@protoc_insertion_point(class_scope:tcp.AutoShutdown) +GetShootPicRequest = _reflection.GeneratedProtocolMessageType('GetShootPicRequest', (_message.Message,), { + 'DESCRIPTOR' : _GETSHOOTPICREQUEST, + '__module__' : 'proto.tcp_messages_pb2' + # @@protoc_insertion_point(class_scope:tcp.GetShootPicRequest) }) -_sym_db.RegisterMessage(AutoShutdown) +_sym_db.RegisterMessage(GetShootPicRequest) + +PushLogRequest = _reflection.GeneratedProtocolMessageType('PushLogRequest', (_message.Message,), { + 'DESCRIPTOR' : _PUSHLOGREQUEST, + '__module__' : 'proto.tcp_messages_pb2' + # @@protoc_insertion_point(class_scope:tcp.PushLogRequest) + }) +_sym_db.RegisterMessage(PushLogRequest) + +WifiStatusRequest = _reflection.GeneratedProtocolMessageType('WifiStatusRequest', (_message.Message,), { + 'DESCRIPTOR' : _WIFISTATUSREQUEST, + '__module__' : 'proto.tcp_messages_pb2' + # @@protoc_insertion_point(class_scope:tcp.WifiStatusRequest) + }) +_sym_db.RegisterMessage(WifiStatusRequest) if _descriptor._USE_C_DESCRIPTORS == False: DESCRIPTOR._options = None DESCRIPTOR._serialized_options = b'\n\rcom.shoot.tcpZ1git.shelingxingqiu.com/shoot-tcp-server/proto;tcp' - _LOGINREQUEST._serialized_start=28 - _LOGINREQUEST._serialized_end=159 - _LOGINRESPONSE._serialized_start=161 - _LOGINRESPONSE._serialized_end=203 - _HEARTBEAT._serialized_start=205 - _HEARTBEAT._serialized_end=257 - _LOGICBODY._serialized_start=259 - _LOGICBODY._serialized_end=297 - _RESPONSEBODY._serialized_start=299 - _RESPONSEBODY._serialized_end=340 - _MONITORBODY._serialized_start=342 - _MONITORBODY._serialized_end=406 - _MONITORDEVICESRESPONSE._serialized_start=408 - _MONITORDEVICESRESPONSE._serialized_end=452 - _OTAFRAGMENT._serialized_start=454 - _OTAFRAGMENT._serialized_end=511 - _SHOOTDATA._serialized_start=514 - _SHOOTDATA._serialized_end=813 - _SHOOTEVENT._serialized_start=815 - _SHOOTEVENT._serialized_end=848 - _BATTERYREPORT._serialized_start=850 - _BATTERYREPORT._serialized_end=917 - _CENTERPOINTRESULT._serialized_start=919 - _CENTERPOINTRESULT._serialized_end=976 - _CENTERPOINTSET._serialized_start=978 - _CENTERPOINTSET._serialized_end=1029 - _OTARESULT._serialized_start=1031 - _OTARESULT._serialized_end=1071 - _GENERICRESULT._serialized_start=1073 - _GENERICRESULT._serialized_end=1104 - _IPREPORT._serialized_start=1106 - _IPREPORT._serialized_end=1144 - _IMAGEUPLOADCOMMAND._serialized_start=1146 - _IMAGEUPLOADCOMMAND._serialized_end=1236 - _LOGUPLOADCOMMAND._serialized_start=1238 - _LOGUPLOADCOMMAND._serialized_end=1338 - _OTAREQUESTDATA._serialized_start=1340 - _OTAREQUESTDATA._serialized_end=1415 - _WIFICONNECTDATA._serialized_start=1417 - _WIFICONNECTDATA._serialized_end=1466 - _IMAGEUPLOADRESULT._serialized_start=1468 - _IMAGEUPLOADRESULT._serialized_end=1563 - _LOGUPLOADRESULT._serialized_start=1565 - _LOGUPLOADRESULT._serialized_end=1683 - _BATTERYQUERYRESPONSE._serialized_start=1685 - _BATTERYQUERYRESPONSE._serialized_end=1759 - _OTA4GSUBCODEREQ._serialized_start=1761 - _OTA4GSUBCODEREQ._serialized_end=1800 - _OTA4GSUBCODERESP._serialized_start=1802 - _OTA4GSUBCODERESP._serialized_end=1855 - _SHUTDOWNCOMMAND._serialized_start=1857 - _SHUTDOWNCOMMAND._serialized_end=1887 - _AUTOSHUTDOWN._serialized_start=1889 - _AUTOSHUTDOWN._serialized_end=1921 + _LOGINREQUEST._serialized_start=34 + _LOGINREQUEST._serialized_end=165 + _LOGINRESPONSE._serialized_start=167 + _LOGINRESPONSE._serialized_end=209 + _HEARTBEAT._serialized_start=211 + _HEARTBEAT._serialized_end=263 + _LOGICBODY._serialized_start=266 + _LOGICBODY._serialized_end=1597 + _MONITORBODY._serialized_start=1599 + _MONITORBODY._serialized_end=1663 + _MONITORDEVICESRESPONSE._serialized_start=1665 + _MONITORDEVICESRESPONSE._serialized_end=1709 + _OTAFRAGMENT._serialized_start=1711 + _OTAFRAGMENT._serialized_end=1768 + _SHOOTDATA._serialized_start=1771 + _SHOOTDATA._serialized_end=2070 + _SHOOTEVENT._serialized_start=2072 + _SHOOTEVENT._serialized_end=2105 + _BATTERYREPORT._serialized_start=2107 + _BATTERYREPORT._serialized_end=2192 + _AIMREQUEST._serialized_start=2194 + _AIMREQUEST._serialized_end=2206 + _CLOSEAIMREQUEST._serialized_start=2208 + _CLOSEAIMREQUEST._serialized_end=2225 + _OTAREQUEST._serialized_start=2227 + _OTAREQUEST._serialized_end=2298 + _OTA4GSUBCODEREQUEST._serialized_start=2300 + _OTA4GSUBCODEREQUEST._serialized_end=2343 + _OTA4GSUBCODERESPONSE._serialized_start=2345 + _OTA4GSUBCODERESPONSE._serialized_end=2389 + _WIFICONNECTREQUEST._serialized_start=2391 + _WIFICONNECTREQUEST._serialized_end=2443 + _CENTERPOINTRESULT._serialized_start=2445 + _CENTERPOINTRESULT._serialized_end=2502 + _CENTERPOINTSET._serialized_start=2504 + _CENTERPOINTSET._serialized_end=2542 + _CHARGINGREPORT._serialized_start=2544 + _CHARGINGREPORT._serialized_end=2560 + _GENERICRESULT._serialized_start=2562 + _GENERICRESULT._serialized_end=2593 + _IMAGEUPLOADCOMMAND._serialized_start=2595 + _IMAGEUPLOADCOMMAND._serialized_end=2685 + _LOGUPLOADCOMMAND._serialized_start=2687 + _LOGUPLOADCOMMAND._serialized_end=2787 + _IMAGEUPLOADRESULT._serialized_start=2789 + _IMAGEUPLOADRESULT._serialized_end=2884 + _LOGUPLOADRESULT._serialized_start=2886 + _LOGUPLOADRESULT._serialized_end=3004 + _OTARESULT._serialized_start=3006 + _OTARESULT._serialized_end=3079 + _FILESTRINGMSG._serialized_start=3081 + _FILESTRINGMSG._serialized_end=3140 + _IPREPORT._serialized_start=3142 + _IPREPORT._serialized_end=3180 + _GETBATTERYREQUEST._serialized_start=3182 + _GETBATTERYREQUEST._serialized_end=3201 + _SETCENTERPOINTREQUEST._serialized_start=3203 + _SETCENTERPOINTREQUEST._serialized_end=3248 + _SHUTDOWNCOMMAND._serialized_start=3250 + _SHUTDOWNCOMMAND._serialized_end=3267 + _GETSHOOTPICREQUEST._serialized_start=3269 + _GETSHOOTPICREQUEST._serialized_end=3307 + _PUSHLOGREQUEST._serialized_start=3309 + _PUSHLOGREQUEST._serialized_end=3325 + _WIFISTATUSREQUEST._serialized_start=3327 + _WIFISTATUSREQUEST._serialized_end=3346 # @@protoc_insertion_point(module_scope) diff --git a/version.py b/version.py index 3ccc2bc..877bded 100644 --- a/version.py +++ b/version.py @@ -4,6 +4,6 @@ 应用版本号 每次 OTA 更新时,只需要更新这个文件中的版本号 """ -VERSION = '3.0.5' +VERSION = '3.1.15'