'v1.2.3'
This commit is contained in:
137
network.py
137
network.py
@@ -679,6 +679,128 @@ class NetworkManager:
|
||||
self.logger.error(f"[WIFI-TCP] 接收数据异常: {e}")
|
||||
return b""
|
||||
|
||||
def _upload_log_file(self, upload_url, wifi_ssid=None, wifi_password=None):
|
||||
"""上传日志文件到指定URL
|
||||
|
||||
Args:
|
||||
upload_url: 上传目标URL,例如 "https://example.com/upload/"
|
||||
wifi_ssid: WiFi SSID(可选,如果未连接WiFi则尝试连接)
|
||||
wifi_password: WiFi 密码(可选)
|
||||
|
||||
Note:
|
||||
该功能仅在 WiFi 连接时可用,4G 网络暂不支持文件上传
|
||||
"""
|
||||
import requests
|
||||
import shutil
|
||||
from datetime import datetime
|
||||
|
||||
try:
|
||||
# 检查 WiFi 连接状态,如果未连接则尝试连接
|
||||
if not self.is_wifi_connected():
|
||||
if wifi_ssid and wifi_password:
|
||||
self.logger.info(f"[LOG_UPLOAD] WiFi 未连接,尝试连接 WiFi: {wifi_ssid}")
|
||||
self.safe_enqueue({"result": "log_upload_connecting_wifi", "ssid": wifi_ssid}, 2)
|
||||
|
||||
ip, error = self.connect_wifi(wifi_ssid, wifi_password)
|
||||
if error:
|
||||
self.logger.error(f"[LOG_UPLOAD] WiFi 连接失败: {error}")
|
||||
self.safe_enqueue({
|
||||
"result": "log_upload_failed",
|
||||
"reason": "wifi_connect_failed",
|
||||
"detail": error
|
||||
}, 2)
|
||||
return
|
||||
|
||||
self.logger.info(f"[LOG_UPLOAD] WiFi 连接成功,IP: {ip}")
|
||||
else:
|
||||
self.logger.warning("[LOG_UPLOAD] WiFi 未连接且未提供 WiFi 凭证,无法上传日志")
|
||||
self.safe_enqueue({
|
||||
"result": "log_upload_failed",
|
||||
"reason": "wifi_not_connected",
|
||||
"detail": "WiFi not connected and no credentials provided"
|
||||
}, 2)
|
||||
return
|
||||
else:
|
||||
self.logger.info("[LOG_UPLOAD] WiFi 已连接,跳过连接步骤")
|
||||
|
||||
self.logger.info(f"[LOG_UPLOAD] 开始上传日志文件...")
|
||||
|
||||
# 获取日志文件路径
|
||||
log_file_path = config.LOG_FILE # /maixapp/apps/t11/app.log
|
||||
|
||||
if not os.path.exists(log_file_path):
|
||||
self.logger.error(f"[LOG_UPLOAD] 日志文件不存在: {log_file_path}")
|
||||
self.safe_enqueue({"result": "log_upload_failed", "reason": "log_file_not_found"}, 2)
|
||||
return
|
||||
|
||||
# 生成带时间戳的文件名
|
||||
# 格式: app_20260131_143025_d19566161359c372.log
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
device_id = self._device_id or "unknown"
|
||||
new_filename = f"app_{timestamp}_{device_id}.log"
|
||||
|
||||
# 创建临时文件(带时间戳的名字)
|
||||
temp_dir = "/tmp"
|
||||
temp_file_path = os.path.join(temp_dir, new_filename)
|
||||
|
||||
# 复制日志文件到临时位置
|
||||
shutil.copy2(log_file_path, temp_file_path)
|
||||
self.logger.info(f"[LOG_UPLOAD] 日志文件已复制到: {temp_file_path}")
|
||||
|
||||
# 使用 multipart/form-data 上传文件
|
||||
with open(temp_file_path, 'rb') as f:
|
||||
files = {'file': (new_filename, f, 'text/plain')}
|
||||
|
||||
# 添加额外的头部信息
|
||||
headers = {
|
||||
'User-Agent': 'Archery-Device/1.0',
|
||||
'X-Device-ID': device_id,
|
||||
}
|
||||
|
||||
# 如果是 ngrok-free.dev,添加绕过警告页面的头
|
||||
if 'ngrok-free.dev' in upload_url or 'ngrok.io' in upload_url:
|
||||
headers['ngrok-skip-browser-warning'] = 'true'
|
||||
|
||||
self.logger.info(f"[LOG_UPLOAD] 正在上传到: {upload_url}")
|
||||
|
||||
# 禁用 SSL 警告(用于自签名证书或 SSL 兼容性问题)
|
||||
import urllib3
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
|
||||
# 发送请求,verify=False 跳过 SSL 证书验证(解决 MaixCAM SSL 兼容性问题)
|
||||
response = requests.post(upload_url, files=files, headers=headers, timeout=60, verify=False)
|
||||
|
||||
if response.status_code in (200, 201, 204):
|
||||
self.logger.info(f"[LOG_UPLOAD] 上传成功! 状态码: {response.status_code}")
|
||||
self.safe_enqueue({
|
||||
"result": "log_upload_ok",
|
||||
"filename": new_filename,
|
||||
"status_code": response.status_code
|
||||
}, 2)
|
||||
else:
|
||||
self.logger.error(f"[LOG_UPLOAD] 上传失败! 状态码: {response.status_code}, 响应: {response.text[:200]}")
|
||||
self.safe_enqueue({
|
||||
"result": "log_upload_failed",
|
||||
"reason": f"http_{response.status_code}",
|
||||
"detail": response.text[:100]
|
||||
}, 2)
|
||||
|
||||
# 清理临时文件
|
||||
try:
|
||||
os.remove(temp_file_path)
|
||||
self.logger.debug(f"[LOG_UPLOAD] 临时文件已删除: {temp_file_path}")
|
||||
except Exception as e:
|
||||
self.logger.warning(f"[LOG_UPLOAD] 删除临时文件失败: {e}")
|
||||
|
||||
except requests.exceptions.Timeout:
|
||||
self.logger.error("[LOG_UPLOAD] 上传超时")
|
||||
self.safe_enqueue({"result": "log_upload_failed", "reason": "timeout"}, 2)
|
||||
except requests.exceptions.ConnectionError as e:
|
||||
self.logger.error(f"[LOG_UPLOAD] 连接失败: {e}")
|
||||
self.safe_enqueue({"result": "log_upload_failed", "reason": "connection_error"}, 2)
|
||||
except Exception as e:
|
||||
self.logger.error(f"[LOG_UPLOAD] 上传异常: {e}")
|
||||
self.safe_enqueue({"result": "log_upload_failed", "reason": str(e)[:100]}, 2)
|
||||
|
||||
def generate_token(self, device_id):
|
||||
"""生成用于 HTTP 接口鉴权的 Token(HMAC-SHA256)"""
|
||||
@@ -970,6 +1092,21 @@ class NetworkManager:
|
||||
time.sleep_ms(2000)
|
||||
os.system("poweroff")
|
||||
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")
|
||||
|
||||
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}")
|
||||
# 在新线程中执行上传,避免阻塞主循环
|
||||
import _thread
|
||||
_thread.start_new_thread(self._upload_log_file, (upload_url, wifi_ssid, wifi_password))
|
||||
else:
|
||||
time.sleep_ms(5)
|
||||
|
||||
|
||||
@@ -4,11 +4,14 @@
|
||||
应用版本号
|
||||
每次 OTA 更新时,只需要更新这个文件中的版本号
|
||||
"""
|
||||
VERSION = '1.2.1'
|
||||
VERSION = '1.2.3'
|
||||
|
||||
# 1.2.0 开始使用C++编译成.so,替换部分代码
|
||||
# 1.2.1 ota使用加密包
|
||||
# 1.2.2 支持wifi ota,并且设定时区,并使用单独线程保存图片
|
||||
# 1.2.3 修改ADC_TRIGGER_THRESHOLD 为2300,支持上传日志到服务器
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user