450 lines
19 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
VWED.robot 模块 - 机器人相关功能
"""
import json
import asyncio
from typing import Dict, Any, Optional, List
from utils.logger import get_logger
from utils.json_parser import safe_parse_dict
class VWEDRobotModule:
"""VWED.robot 模块 - 机器人相关功能"""
def __init__(self, script_id: str):
self.script_id = script_id
self.logger = get_logger(f"script.{script_id}.robot")
async def _get_auth_token(self, auto_get_token: bool = True) -> Optional[str]:
"""获取认证token的通用方法
Args:
auto_get_token: 是否自动获取登录token默认true
Returns:
Optional[str]: 认证令牌获取失败返回None
"""
if not auto_get_token:
return None
try:
from services.sync_service import refresh_token_if_needed
token = await refresh_token_if_needed()
if token:
self.logger.info(f"脚本 {self.script_id} 成功获取到登录token")
return token
else:
self.logger.warning(f"脚本 {self.script_id} 获取登录token失败继续使用空token")
return None
except Exception as e:
self.logger.warning(f"脚本 {self.script_id} 获取token异常: {str(e)}继续使用空token")
return None
async def is_robot_exist(self, robot_name: str) -> bool:
"""校验机器人是否存在
Args:
robot_name: 机器人名称
Returns:
bool: True表示存在False表示不存在
"""
try:
# 获取认证token
token = await self._get_auth_token()
# 调用获取AMR列表接口
from services.sync_service import get_amr_list
response = await get_amr_list(token)
if response and response.get("success") and response.get("result"):
# 检查机器人名称是否在列表中
amr_list = response.get("result", {}).get("records", [])
for amr in amr_list:
if amr.get("name") == robot_name:
self.logger.info(f"脚本 {self.script_id} 机器人存在: {robot_name}")
return True
self.logger.info(f"脚本 {self.script_id} 机器人不存在: {robot_name}")
return False
else:
self.logger.warning(f"脚本 {self.script_id} 获取机器人信息失败")
return False
except Exception as e:
self.logger.error(f"脚本 {self.script_id} 校验机器人是否存在异常: {str(e)}")
return False
async def get_lite_robots_status(self) -> str:
"""获取机器人基本信息
Returns:
str: JSON格式的机器人信息列表
"""
try:
# 获取认证token
token = await self._get_auth_token()
# 调用获取AMR列表接口
from services.sync_service import get_amr_list
response = await get_amr_list(token)
if response and response.get("success") and response.get("result"):
amr_list = response.get("result", {}).get("records", [])
# 转换所有字段为蛇形命名
robots_info = []
for amr in amr_list:
robot_info = {
"id": amr.get("id", ""),
"tenant_id": amr.get("tenantId", ""),
"brand_id": amr.get("brandId", ""),
"type_id": amr.get("typeId", ""),
"ip_address": amr.get("ipAddress", ""),
"name": amr.get("name", ""),
"scene_id": amr.get("sceneId", ""),
"group_id": amr.get("groupId", ""),
"online_station_id": amr.get("onlineStationId", ""),
"is_online": amr.get("isOnline", 0),
"is_simulation": amr.get("isSimulation", 0),
"is_available": amr.get("isAvailable", 0),
"is_accept_task": amr.get("isAcceptTask", 0),
"length": amr.get("length", 0.0),
"width": amr.get("width", 0.0),
"min_power": amr.get("minPower", 0),
"max_power": amr.get("maxPower", 0),
"charge_power": amr.get("chargePower", 0),
"task_power": amr.get("taskPower", 0),
"exchange_power": amr.get("exchangePower", 0),
"amr_status": amr.get("amrStatus", 0),
"create_by": amr.get("createBy", ""),
"create_time": amr.get("createTime", "")
}
robots_info.append(robot_info)
result = json.dumps(robots_info, ensure_ascii=False)
self.logger.info(f"脚本 {self.script_id} 成功获取机器人信息,共 {len(robots_info)} 个机器人")
return result
else:
self.logger.warning(f"脚本 {self.script_id} 获取机器人信息失败")
return json.dumps([], ensure_ascii=False)
except Exception as e:
self.logger.error(f"脚本 {self.script_id} 获取机器人信息异常: {str(e)}")
return json.dumps([], ensure_ascii=False)
async def get_lite_robots_status_by_id(self, agv_id: str) -> str:
"""根据ID获取机器人基本信息
Args:
agv_id: 机器人ID
Returns:
str: JSON格式的机器人信息
"""
try:
# 获取认证token
token = await self._get_auth_token()
# 调用获取AMR列表接口
from services.sync_service import get_amr_list
response = await get_amr_list(token)
if response and response.get("success") and response.get("result"):
amr_list = response.get("result", {}).get("records", [])
# 查找指定ID的机器人
for amr in amr_list:
if amr.get("id") == agv_id or amr.get("name") == agv_id:
robot_info = {
"id": amr.get("id", ""),
"tenant_id": amr.get("tenantId", ""),
"brand_id": amr.get("brandId", ""),
"type_id": amr.get("typeId", ""),
"ip_address": amr.get("ipAddress", ""),
"name": amr.get("name", ""),
"scene_id": amr.get("sceneId", ""),
"group_id": amr.get("groupId", ""),
"online_station_id": amr.get("onlineStationId", ""),
"is_online": amr.get("isOnline", 0),
"is_simulation": amr.get("isSimulation", 0),
"is_available": amr.get("isAvailable", 0),
"is_accept_task": amr.get("isAcceptTask", 0),
"length": amr.get("length", 0.0),
"width": amr.get("width", 0.0),
"min_power": amr.get("minPower", 0),
"max_power": amr.get("maxPower", 0),
"charge_power": amr.get("chargePower", 0),
"task_power": amr.get("taskPower", 0),
"exchange_power": amr.get("exchangePower", 0),
"amr_status": amr.get("amrStatus", 0),
"create_by": amr.get("createBy", ""),
"create_time": amr.get("createTime", "")
}
result = json.dumps(robot_info, ensure_ascii=False)
self.logger.info(f"脚本 {self.script_id} 成功获取机器人信息: {agv_id}")
return result
# 未找到机器人,返回空对象
self.logger.warning(f"脚本 {self.script_id} 未找到机器人: {agv_id}")
return "{}"
else:
self.logger.warning(f"脚本 {self.script_id} 获取机器人信息失败")
return "{}"
except Exception as e:
self.logger.error(f"脚本 {self.script_id} 获取机器人信息异常: {str(e)}")
return "{}"
async def get_vehicle_station(self, agv_id: str) -> str:
"""根据机器人ID获取机器人位置
Args:
agv_id: 机器人ID
Returns:
str: JSON格式的位置信息如果与调度断连返回空对象
"""
try:
# 获取认证token
token = await self._get_auth_token()
# 调用获取AMR信息接口
from services.sync_service import get_amr_info
response = await get_amr_info(token)
if response and response.get("success") and response.get("result"):
amr_list = response.get("result", [])
# 查找指定ID的机器人
for amr in amr_list:
if amr.get("id") == agv_id or amr.get("name") == agv_id:
station_info = {
"last_station": amr.get("lastNodeName", ""),
"station": amr.get("lastNodeName", "")
}
result = json.dumps(station_info, ensure_ascii=False)
self.logger.info(f"脚本 {self.script_id} 成功获取机器人位置: {agv_id}")
return result
# 未找到机器人,返回空对象
return "{}"
else:
# 与调度断连,返回空对象
return "{}"
except Exception as e:
self.logger.error(f"脚本 {self.script_id} 获取机器人位置异常: {str(e)}")
return "{}"
async def get_core_alarms(self) -> Optional[str]:
"""获取Core报错信息
Returns:
Optional[str]: JSON格式的报错信息断连时返回None
"""
## TODO
async def get_core_alarms_by_id(self, code: int) -> Optional[str]:
"""根据ID获取Core报错信息
Args:
code: 错误码
Returns:
Optional[str]: JSON格式的报错信息断连时返回None
"""
## TODO
async def get_rbk_alarms(self) -> Optional[str]:
"""获取Rbk报错信息
Returns:
Optional[str]: JSON格式的报错信息断连时返回None
"""
## TODO
async def get_rbk_alarms_by_id(self, code: int) -> Optional[str]:
"""根据ID获取Rbk报错信息
Args:
code: 错误码
Returns:
Optional[str]: JSON格式的报错信息断连时返回None
"""
## TODO
async def set_soft_stop(self, vehicle_id: str, status: bool) -> bool:
"""设置机器人软急停
Args:
vehicle_id: 机器人名称
status: True表示设置软急停False表示取消软急停
Returns:
bool: True表示成功False表示失败
"""
## TODO
async def get_robots_status(self) -> Optional[str]:
"""获取机器人所有信息
Returns:
Optional[str]: JSON格式的详细机器人信息断连时返回None
"""
## TODO
async def query_charge_param(self) -> Optional[str]:
"""查询所有机器人充电阈值
Returns:
Optional[str]: JSON格式的充电阈值信息断连时返回None
"""
try:
# 获取认证token
token = await self._get_auth_token()
# 调用充电参数查询接口
from services.sync_service import get_amr_charge_params
response = await get_amr_charge_params(token)
if response and response.get("success") and response.get("result"):
charge_params = response.get("result", [])
result = json.dumps(charge_params, ensure_ascii=False)
self.logger.info(f"脚本 {self.script_id} 成功查询所有机器人充电阈值,共 {len(charge_params)} 个机器人")
return result
else:
self.logger.warning(f"脚本 {self.script_id} 查询所有机器人充电阈值失败")
return json.dumps([], ensure_ascii=False)
except Exception as e:
self.logger.error(f"脚本 {self.script_id} 查询所有机器人充电阈值异常: {str(e)}")
return None
async def query_charge_param_by_vehicles(self, vehicles: str) -> Optional[str]:
"""查询指定机器人充电阈值
Args:
vehicles: JSON格式的机器人名称列表字符串
Returns:
Optional[str]: JSON格式的充电阈值信息
"""
try:
# 解析机器人列表
vehicle_list = json.loads(vehicles) if isinstance(vehicles, str) else vehicles
# 获取认证token
token = await self._get_auth_token()
# 调用指定机器人充电参数查询接口
from services.sync_service import get_amr_charge_params_by_vehicles
response = await get_amr_charge_params_by_vehicles(vehicle_list, token)
if response and response.get("success") and response.get("result"):
charge_params = response.get("result", [])
result = json.dumps(charge_params, ensure_ascii=False)
self.logger.info(f"脚本 {self.script_id} 成功查询指定机器人充电阈值,共 {len(charge_params)} 个机器人")
return result
else:
self.logger.warning(f"脚本 {self.script_id} 查询指定机器人充电阈值失败")
return json.dumps([], ensure_ascii=False)
except Exception as e:
self.logger.error(f"脚本 {self.script_id} 查询指定机器人充电阈值异常: {str(e)}")
return None
async def modify_charge_param(self, param: str) -> bool:
"""修改机器人充电阈值
Args:
param: JSON格式的修改参数字符串包含id机器人ID或名称和要修改的充电参数
Returns:
bool: True表示修改成功False表示修改失败
"""
try:
# 解析修改参数
param_data = safe_parse_dict(param, self.script_id)
if param_data is None:
return False
# 获取机器人ID或名称
amr_identifier = param_data.get("id")
if not amr_identifier:
self.logger.error(f"脚本 {self.script_id} 修改机器人充电阈值失败: 缺少机器人ID")
return False
# 获取认证token
token = await self._get_auth_token()
# 首先获取所有AMR信息找到对应的机器人并获取当前充电参数
from services.sync_service import get_amr_list
response = await get_amr_list(token)
if not response or not response.get("success") or not response.get("result"):
self.logger.warning(f"脚本 {self.script_id} 获取机器人信息失败")
return False
# 查找对应的机器人获取真实的ID和当前充电参数
amr_list = response.get("result", {}).get("records", [])
actual_amr_id = None
current_charge_params = None
for amr in amr_list:
if amr.get("id") == amr_identifier or amr.get("name") == amr_identifier:
actual_amr_id = amr.get("id")
# 获取当前的充电参数作为默认值
current_charge_params = {
"exchange_power": amr.get("exchangePower", 0),
"task_power": amr.get("taskPower", 0),
"charge_power": amr.get("chargePower", 0),
"min_power": amr.get("minPower", 0),
"max_power": amr.get("maxPower", 0)
}
break
if not actual_amr_id or current_charge_params is None:
self.logger.error(f"脚本 {self.script_id} 修改机器人充电阈值失败: 未找到机器人 {amr_identifier}")
return False
# 准备充电参数 - 从当前参数开始,用用户传入的参数覆盖对应字段
charge_params = current_charge_params.copy()
# 蛇形命名字段列表
snake_fields = ["exchange_power", "task_power", "charge_power", "min_power", "max_power"]
has_changes = False
# 用用户传入的参数覆盖对应字段
for snake_field in snake_fields:
if snake_field in param_data:
charge_params[snake_field] = param_data[snake_field]
has_changes = True
if not has_changes:
self.logger.error(f"脚本 {self.script_id} 修改机器人充电阈值失败: 没有要修改的充电参数")
return False
self.logger.info(f"脚本 {self.script_id} 准备修改机器人 {amr_identifier} 的充电参数: {charge_params}")
# 调用修改充电参数接口使用真实的机器人ID传入完整的5个参数
from services.sync_service import modify_amr_charge_param
response = await modify_amr_charge_param(actual_amr_id, charge_params, token)
if response and response.get("success"):
self.logger.info(f"脚本 {self.script_id} 成功修改机器人充电阈值: {amr_identifier} (ID: {actual_amr_id})")
return True
else:
error_msg = response.get("message", "未知错误") if response else "接口调用失败"
self.logger.warning(f"脚本 {self.script_id} 修改机器人充电阈值失败: {error_msg}")
return False
except Exception as e:
self.logger.error(f"脚本 {self.script_id} 修改机器人充电阈值异常: {str(e)}")
return False