api-amr/agv_worker.ts
2025-06-04 19:15:02 +08:00

932 lines
28 KiB
TypeScript
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.

// agv_worker.ts
// 捕获未处理的 promise避免 worker 因 grpc 异常退出
globalThis.addEventListener("unhandledrejection", (event) => {
console.error("Unhandled promise rejection:", event.reason);
event.preventDefault();
});
// Deno + npm 包
import * as grpc from "npm:@grpc/grpc-js@1.12.1";
import * as protoLoader from "npm:@grpc/proto-loader";
import { delay } from "https://deno.land/std/async/delay.ts";
import { createWorkerEventHelper } from "./worker_event_helper.ts";
// 创建事件助手
const eventHelper = createWorkerEventHelper("agvWorker");
// Proto 加载
const PROTO_PATH = "./proto/vda5050.proto";
const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true,
});
const proto = grpc.loadPackageDefinition(packageDefinition) as any;
const vda5050 = proto.vda5050 as any;
// 运行时参数 & 设备列表
let SERVER_URL: string;
let devices: Device[] = [];
// 全局 gRPC 流 & AGV 实例映射
let stream: grpc.ClientDuplexStream<any, any> | null = null;
const agvMap = new Map<string, AgvSimulator>();
// gRPC 连接状态标记
let isGrpcConnected = false;
// 全局自增 headerId
let globalHeaderId = 1;
// 设备接口
interface Device {
serialNumber: string;
manufacturer: string;
}
// 新增 AGV 模拟器状态类型定义
interface Position {
x: number;
y: number;
theta: number;
}
interface NodeState {
nodeId: string;
sequenceId: number;
nodeDescription: string;
nodePosition: Position;
released: boolean;
}
interface EdgeState {
edgeId: string;
sequenceId: number;
edgeDescription: string;
released: boolean;
trajectory: Position[];
}
interface AgvPosition {
x: number;
y: number;
theta: number;
mapId: string;
mapDescription: string;
positionInitialized: boolean;
deviationRange: number;
localizationScore: number;
}
interface Velocity {
vx: number;
vy: number;
omega: number;
}
interface BatteryState {
batteryCharge: number;
charging: boolean;
batteryVoltage?: number;
batteryHealth?: number;
reach?: number;
}
interface ErrorState {
errorType: string;
errorDescription: string;
errorLevel: string;
}
interface SafetyState {
eStop: boolean;
fieldViolation: boolean;
}
interface ActionState {
actionId: string;
actionType: string;
actionDescription: string;
actionStatus: string;
resultDescription: string;
}
interface AgvState {
headerId: number;
timestamp: string;
version: string;
manufacturer: string;
serialNumber: string;
orderId: string;
orderUpdateId: number;
lastNodeId: string;
lastNodeSequenceId: number;
driving: boolean;
waitingForInteractionZoneRelease: boolean;
paused: boolean;
forkState?: string;
newBaseRequest: boolean;
distanceSinceLastNode: number;
operatingMode: string;
nodeStates: NodeState[];
edgeStates: EdgeState[];
agvPosition: AgvPosition;
velocity: Velocity;
loads: any[];
batteryState: BatteryState;
errors: ErrorState[];
information: any[];
safetyState: SafetyState;
actionStates: ActionState[];
}
// 建立/重建 gRPC 流
function initGrpcStream() {
try {
if (stream) {
console.log("关闭旧 gRPC 流");
try {
// 移除所有事件监听,避免它们触发重复 reconnectAll
stream.removeAllListeners();
stream.end();
} catch (_) { /* ignore */ }
stream = null;
}
const client = new vda5050.AgvManagement(
SERVER_URL,
grpc.credentials.createInsecure(),
);
stream = client.CommunicationChannel();
console.log("gRPC 流已建立");
isGrpcConnected = true;
if (!stream) {
console.error("无法创建 gRPC 流");
return false;
}
stream.on("data", (msg: any) => {
if(msg) {
const sim = agvMap.get(msg.targetAgvId);
if (!sim) {
console.warn("未知 AGV丢弃消息:", msg.agvId);
return;
}else{
if (msg.order) {
// console.log(`${msg.targetAgvId} << Order`, msg);
sim.handleOrder(msg.order);
} else if (msg.instantActions) {
const acts = msg.instantActions.instantActions || [];
// console.log(`${msg.targetAgvId} << InstantActions`, msg);
sim.handleInstantActions(acts);
}
}
}else{
console.warn("AGV 消息为空,丢弃消息:", msg.agvId);
return;
}
});
stream.on("error", async (err: any) => {
console.error("gRPC 流错误,全体重连");
isGrpcConnected = false;
stream = null; // 清空引用,防止重复使用失效的流
// 发送 gRPC 连接丢失事件
eventHelper.dispatchEvent("grpc-connection-lost", {
error: err.message || "unknown error",
timestamp: Date.now()
});
await reconnectAll();
});
// stream.on("end", async () => {
// console.warn("gRPC 流结束,全体重连");
// isGrpcConnected = false;
// stream = null; // 清空引用,防止重复使用失效的流
// // 发送 gRPC 连接结束事件
// eventHelper.dispatchEvent("grpc-connection-ended", {
// timestamp: Date.now()
// });
// await reconnectAll();
// });
return true;
} catch (err) {
console.error("gRPC 流初始化失败:", err);
stream = null;
return false;
}
}
// 安全发送消息到流
function sendToStream(msg: any): boolean {
if (!stream || !isGrpcConnected) {
console.warn("无法发送消息gRPC 流未初始化");
return false;
}
try {
stream.write(msg);
return true;
} catch (err) {
console.error("发送消息失败:", err);
return false;
}
}
// 重连:停所有定时器,延迟后重建流,重发 Connection 并重启状态上报
async function reconnectAll() {
// 停止所有状态更新
agvMap.forEach((s) => s.stopStatusUpdates());
// 等待一段时间再重连
await delay(500);
// 尝试重建流
let retryCount = 0;
const maxRetries = 5;
while (retryCount < maxRetries) {
console.log(`正在尝试重建 gRPC 流 等待次数 (${retryCount + 1}/${maxRetries})...`);
// if (initGrpcStream()) {
// console.log("gRPC 流重建成功");
// break;
// }
retryCount++;
await delay(100 * retryCount); // 递增等待时间
}
if (!stream) {
console.error(`无法重建 gRPC 流,已达到最大重试等待次数 ${maxRetries}`);
// 使用全局事件系统发送重连请求
eventHelper.dispatchEvent("reconnect-all", {
reason: "grpc-stream-failed",
retryCount: maxRetries,
timestamp: Date.now()
});
self.postMessage({ type: "reconnect-all"});
await delay(10000);
return;
}
// 成功重建流,重新发送所有 Connection 并重启状态更新
for (const sim of agvMap.values()) {
// sim.sendConnection("OFFLINE"); // 主动发送 ONLINE 状态
sim.resetLastOnlineStatus();
sim.startStatusUpdates();
await delay(200);
}
}
// AGV 模拟器
class AgvSimulator {
private batteryLevel: number;
private position = { x: 0, y: 0, theta: 0 };
private orderId = "";
private orderUpdateId = 0;
private state!: AgvState;
private updateIntervalId: number | null = null;
private lastOperatingMode = "NONE";
private lastOnlineStatus = "OFFLINE";
private agvId: string;
private manufacturer: string;
private serialNumber: string;
constructor(
agvId: string,
manufacturer: string,
serialNumber: string,
) {
this.agvId = agvId;
this.manufacturer = manufacturer;
this.serialNumber = serialNumber;
// 随机初始化
this.batteryLevel = 75 + Math.random() * 25;
this.position = {
x: Math.random() * 100,
y: Math.random() * 100,
theta: Math.random() * Math.PI * 2,
};
this.initState();
}
// 构造初始 State
private initState() {
this.state = <AgvState>{
headerId: globalHeaderId++,
timestamp: new Date().toISOString(),
version: "2.0.0",
manufacturer: this.manufacturer,
serialNumber: this.serialNumber,
orderId: this.orderId,
orderUpdateId: this.orderUpdateId,
lastNodeId: "",
lastNodeSequenceId: 0,
driving: false,
waitingForInteractionZoneRelease: false,
paused: false,
forkState: undefined,
newBaseRequest: false,
distanceSinceLastNode: 0,
operatingMode: "NONE", // 初始离线
nodeStates: [],
edgeStates: [],
agvPosition: {
x: this.position.x,
y: this.position.y,
theta: this.position.theta,
mapId: "warehouse",
mapDescription: "",
positionInitialized: true,
deviationRange: 0,
localizationScore: 0.95,
},
velocity: { vx: 0, vy: 0, omega: 0 },
loads: [],
actionStates: [],
batteryState: {
batteryCharge: this.batteryLevel,
batteryVoltage: 24.5,
batteryHealth: 100,
charging: false,
reach: 0,
},
errors: [],
information: [],
safetyState: { eStop: false, fieldViolation: false },
};
}
// 上行 Connection默认为 ONLINE
public sendConnection(state: "ONLINE" | "OFFLINE" = "OFFLINE") {
const msg = {
agvId: this.agvId,
connection: {
headerId: globalHeaderId++,
timestamp: new Date().toISOString(),
version: "2.0.0",
manufacturer: this.manufacturer,
serialNumber: this.serialNumber,
connectionState: state,
},
};
// console.log("发送 Connection 消息", msg);
if (sendToStream(msg)) {
// console.log(`${this.agvId} >> Connection(${state})`);
return true;
}
return false;
}
public resetLastOnlineStatus() {
this.lastOnlineStatus = "OFFLINE";
}
// 定时上报 State
public startStatusUpdates() {
this.stopStatusUpdates();
this.updateIntervalId = setInterval(async () => {
// 检查在线/离线状态
this.checkOnlineStatus();
// console.log(`${this.agvId}:${this.state.operatingMode}:${this.lastOnlineStatus} 状态更新>>>>`);
if (this.lastOnlineStatus === "ONLINE") {
// console.log(`${this.agvId} 状态更新>>>>`);
this.updateAndSendState().catch(err => {
console.error(`${this.agvId} 状态更新失败:`, err);
});
}
}, 1000);
}
private async updateAndSendState() {
// 1) 请求 KV添加随机ID
const requestId = Math.random().toString(36).substring(2, 15);
self.postMessage({
type: "requestKVData",
requestId,
key: `device:${this.manufacturer}/${this.serialNumber}`,
});
}
sendStateToGrpc(data: any) {
// console.log("发送状态到 gRPC 服务器",this.agvId, this.state.serialNumber, data.agvId.serialNumber, data.state.serialNumber);
// console.log("更新状态并发送-->",this.agvId, this.state.serialNumber);
// 若请求失败则保持当前状态
if (data === null) return;
// console.log(`${this.agvId}: KV 数据获取成功`, data);
// 发送设备状态更新事件
// eventHelper.dispatchEvent("device-status-update", {
// agvId: this.agvId,
// batteryLevel: this.batteryLevel,
// operatingMode: data.state?.operatingMode || this.state.operatingMode,
// position: this.position,
// timestamp: Date.now()
// });
// 更新 headerId 和时间戳
this.state.headerId = globalHeaderId++;
this.state.timestamp = new Date(data.lastSeen).toISOString();
// 根据KV数据更新状态
if (data.state) {
// 更新操作模式
if (data.state.operatingMode) {
this.state.operatingMode = data.state.operatingMode;
this.lastOperatingMode = data.state.operatingMode;
}
// 更新电池状态
if (data.state.batteryState) {
const kvBattery = data.state.batteryState;
this.batteryLevel = kvBattery.batteryCharge !== undefined ?
kvBattery.batteryCharge : this.batteryLevel;
// 更新完整的电池状态
this.state.batteryState = {
batteryCharge: this.batteryLevel,
batteryVoltage: kvBattery.batteryVoltage || this.state.batteryState.batteryVoltage,
batteryHealth: kvBattery.batteryHealth || this.state.batteryState.batteryHealth,
charging: kvBattery.charging !== undefined ? kvBattery.charging : this.state.batteryState.charging,
reach: kvBattery.reach !== undefined ? kvBattery.reach : this.state.batteryState.reach
};
} else if (this.state.driving) {
// 如果KV中没有电池数据但AGV在移动模拟电量消耗
this.batteryLevel = Math.max(0, this.batteryLevel - 0.05);
this.state.batteryState.batteryCharge = this.batteryLevel;
}
// 更新位置信息
if (data.state.agvPosition) {
const kvPos = data.state.agvPosition;
// 使用KV中的位置数据
this.position = {
x: kvPos.x !== undefined ? kvPos.x : this.position.x,
y: kvPos.y !== undefined ? kvPos.y : this.position.y,
theta: kvPos.theta !== undefined ? kvPos.theta : this.position.theta
};
// 更新完整的位置状态
this.state.agvPosition = {
x: this.position.x,
y: this.position.y,
theta: this.position.theta,
mapId: kvPos.mapId || this.state.agvPosition.mapId,
mapDescription: kvPos.mapDescription || this.state.agvPosition.mapDescription,
positionInitialized: kvPos.positionInitialized !== undefined ?
kvPos.positionInitialized : this.state.agvPosition.positionInitialized,
deviationRange: kvPos.deviationRange !== undefined ?
kvPos.deviationRange : this.state.agvPosition.deviationRange,
localizationScore: kvPos.localizationScore !== undefined ?
kvPos.localizationScore : this.state.agvPosition.localizationScore
};
} else if (this.state.driving) {
// 如果KV中没有位置数据但AGV在移动模拟位置变化
this.position.x += (Math.random() - 0.5) * 0.5;
this.position.y += (Math.random() - 0.5) * 0.5;
this.position.theta += (Math.random() - 0.5) * 0.1;
this.state.agvPosition.x = this.position.x;
this.state.agvPosition.y = this.position.y;
this.state.agvPosition.theta = this.position.theta;
}
// 更新其他状态字段
if (data.state.orderId !== undefined) {
this.state.orderId = data.state.orderId;
}
if (data.state.orderUpdateId !== undefined) {
this.state.orderUpdateId = data.state.orderUpdateId;
}
if (data.state.lastNodeId !== undefined) {
this.state.lastNodeId = data.state.lastNodeId;
}
if (data.state.lastNodeSequenceId !== undefined) {
this.state.lastNodeSequenceId = data.state.lastNodeSequenceId;
}
if (data.state.driving !== undefined) {
this.state.driving = data.state.driving;
}
if (data.state.waitingForInteractionZoneRelease !== undefined) {
this.state.waitingForInteractionZoneRelease = data.state.waitingForInteractionZoneRelease;
}
if (data.state.paused !== undefined) {
this.state.paused = data.state.paused;
}
if (data.state.nodeStates) {
this.state.nodeStates = data.state.nodeStates;
}
if (data.state.edgeStates) {
this.state.edgeStates = data.state.edgeStates;
}
if (data.state.actionStates) {
this.state.actionStates = data.state.actionStates;
}
if (data.state.errors) {
this.state.errors = data.state.errors;
}
if (data.state.safetyState) {
this.state.safetyState = data.state.safetyState;
}
if (data.state.serialNumber) {
this.state.serialNumber = data.state.serialNumber;
}
if (data.state.manufacturer) {
this.state.manufacturer = data.state.manufacturer;
}
if (data.state.velocity) {
this.state.velocity = data.state.velocity;
}
if (data.state.loads) {
this.state.loads = data.state.loads;
}
if (data.state.information) {
this.state.information = data.state.information;
}
if (data.state.forkState) {
this.state.forkState = data.state.forkState;
}
if (data.state.safetyState) {
this.state.safetyState = data.state.safetyState;
}
if (data.state.actionStates) {
this.state.actionStates = data.state.actionStates;
}
if (data.state.headerId) {
this.state.headerId = data.state.headerId;
}
if (data.state.timestamp) {
this.state.timestamp = data.state.timestamp;
}
if (data.state.version) {
this.state.version = data.state.version;
}
if (data.state.operatingMode) {
this.state.operatingMode = data.state.operatingMode;
}
if (data.state.nodeStates) {
this.state.nodeStates = data.state.nodeStates;
}
if (data.state.edgeStates) {
this.state.edgeStates = data.state.edgeStates;
}
}
// 发送 State按照 gRPC 定义的 AgvMessage 结构
const agvMessage = {
agvId: this.state.serialNumber,
state: this.state
// message_type 会由 oneof 自动处理,我们只需提供 state 字段
};
if (!sendToStream(agvMessage)) {
console.error(`${this.agvId}: 发送状态到 gRPC 服务器失败`);
}
}
public stopStatusUpdates() {
if (this.updateIntervalId != null) {
clearInterval(this.updateIntervalId);
this.updateIntervalId = null;
}
}
// 下行 Order 处理
public handleOrder(order: any) {
// 1) 更新内部状态
// console.log("=====>",order);
this.orderId = order.orderId;
this.orderUpdateId = order.orderUpdateId;
this.state.orderId = this.orderId;
this.state.orderUpdateId = this.orderUpdateId;
this.state.nodeStates = order.nodes.map((n: any, i: number) => ({
nodeId: n.nodeId,
sequenceId: n.sequenceId ?? i,
nodeDescription: n.nodeDescription ?? "",
nodePosition: n.nodePosition,
released: true,
}));
this.state.edgeStates = order.edges.map((e: any, i: number) => ({
edgeId: e.edgeId,
sequenceId: e.sequenceId ?? i,
edgeDescription: e.edgeDescription ?? "",
released: true,
trajectory: e.trajectory,
}));
this.state.driving = true;
// 2) 主动通知主线程收到新 Order
self.postMessage({
type: "orderForwarded",
agvId: this.agvId,
data: {
manufacturer: order.manufacturer,
serialNumber: order.serialNumber,
orderId: this.orderId,
orderUpdateId: this.orderUpdateId,
nodes: this.state.nodeStates,
edges: this.state.edgeStates,
},
});
}
// 下行 InstantActions 处理
public handleInstantActions(actions: any[]) {
// 1) 更新内部状态
// console.log(`${this.agvId} 收到即时动作`, actions);
actions.forEach((a) => {
switch (a.actionType) {
case "STOP":
this.state.driving = false;
break;
case "RESUME":
this.state.driving = true;
break;
case "CHARGE":
this.state.batteryState.charging = true;
break;
case "pick":
console.log("pick");
break;
case "drop":
console.log("drop");
break;
case "stopPause":
this.state.paused = true;
this.state.driving = false;
console.log("stopPause");
break;
case "startPose":
console.log("startPose");
this.state.driving = true;
break;
case "factsheetRequest":
console.log("factsheetRequest");
break;
case "instantActions":
console.log("instantActions");
break;
case "finePositioning":
console.log("finePositioning");
break;
case "startCharging":
console.log("startCharging");
break;
case "stopCharging":
console.log("stopCharging");
break;
case "initPosition":
console.log("initPosition");
break;
case "stateRequst":
console.log("stateRequst");
break;
case "logReport":
console.log("logReport");
break;
case "detectObject":
console.log("detectObject");
break;
case "waitForRtigger":
console.log("waitForRtigger");
break;
case "Standard":
console.log("Standard");
break;
case "switchMap":
console.log("switchMap");
break;
case "reloc":
console.log("reloc");
break;
case "turn":
console.log("turn");
break;
case "confirmLoc":
console.log("confirmLoc");
break;
case "cancelReloc":
console.log("cancelReloc");
break;
case "rotateAgv":
console.log("rotateAgv");
break;
case "rotateLoad":
console.log("rotateLoad");
break;
case "deviceSetup":
console.log("deviceSetup:", a);
break;
case "deviceWrite":
console.log("deviceWrite:", a);
break;
case "deviceDelete":
console.log("deviceDelete:", a);
break;
default:
console.warn(`${this.agvId} 未知即时动作`, a);
}
});
// 2) 主动通知主线程收到 InstantActions
self.postMessage({
type: "instantActionsForwarded",
agvId: this.agvId,
data: actions.map((a) => ({
actionType: a.actionType,
actionParameters: a.actionParameters,
actionDescription: a.actionDescription,
actionId: a.actionId,
blockingType: a.blockingType,
// …你需要的其它字段…
})),
});
}
sendOnlineStatusGrpc(data: any) {
// 若请求失败则保持当前状态
if (data === null) return;
// agvId: { manufacturer: "gateway", serialNumber: "ZKG-2" }
if (data.agvId.manufacturer === this.manufacturer
&& data.agvId.serialNumber === this.agvId
&& this.agvId === this.serialNumber) {
// console.log(`${this.agvId}: KV 数据请求成功`, data);
// 3) 计算是否在线
const lastSeen = data?.lastSeen
? Date.now() - new Date(data.lastSeen).getTime() < 3180 //如果上次 KV 中的 lastSeen 距今超过 3.18 秒,就算离线(无 connection
: false;
const isOnline = lastSeen && data.state === "ONLINE";
const newMode = isOnline ? "ONLINE" : "OFFLINE";
// 只有状态变化时才发送 Connection
if (newMode !== this.lastOnlineStatus) {
this.lastOnlineStatus = newMode;
this.sendConnection(this.lastOnlineStatus as any);
}
}
}
// 检查在线/离线:从主线程取 KV再比较时间若状态变更则发 Connection
private async checkOnlineStatus() {
// console.log(`${this.agvId} 检查在线状态`);
try {
// 1) 请求 KV
const requestId = Math.random().toString(36).substring(2, 15);
self.postMessage({
type: "requestKVDataOnline",
requestId,
key: `device-online:${this.manufacturer}/${this.serialNumber}`,
});
} catch (err) {
console.error(`${this.agvId}: 检查在线状态失败:`, err);
}
}
// 简易状态用于 UI
public getStatus() {
return {
agvId: this.agvId,
batteryCharge: this.batteryLevel,
timestamp: this.state.timestamp,
position: this.state.agvPosition,
driving: this.state.driving,
charging: this.state.batteryState.charging,
operatingMode: this.state.operatingMode,
};
}
}
// 主流程
async function main() {
console.log("agv_workermain");
// 设置事件监听器
eventHelper.addEventListener("test-event", (event) => {
console.log("🧪 AGV Worker 收到测试事件:", event);
});
eventHelper.addEventListener("grpc-reconnect", (event) => {
console.log("🔄 AGV Worker 收到 gRPC 重连指令:", event);
reconnectAll();
});
if (!SERVER_URL || devices.length === 0) {
console.error("缺少 SERVER_URL 或 无设备,无法启动");
return;
}
// 初始化 gRPC 流
if (!initGrpcStream()) {
console.error("gRPC 流初始化失败,无法启动");
return;
}
// 初始化所有 AGV 并发送上线消息
for (const dev of devices) {
const sim = new AgvSimulator(dev.serialNumber, dev.manufacturer, dev.serialNumber);
agvMap.set(dev.serialNumber, sim);
sim.sendConnection("OFFLINE"); // 发送 OFFLINE 状态
sim.startStatusUpdates();
await delay(200);
}
console.log("所有 AGV 已上线并开始状态上报");
// 发送 AGV Worker 启动完成事件
eventHelper.dispatchEvent("agv-worker-ready", {
deviceCount: devices.length,
timestamp: Date.now()
});
// 回主线程汇总状态
setInterval(() => {
const statuses = Array.from(agvMap.values()).map((s) => s.getStatus());
self.postMessage({ type: "devicesStatus", data: statuses });
}, 1000);
}
// worker 接收消息
self.addEventListener("message", (evt: MessageEvent) => {
const msg = evt.data;
if (msg.type === "init") {
SERVER_URL = msg.data.serverUrl;
self.postMessage({ type: "inited"});
console.log("设置 SERVER_URL =", SERVER_URL);
} else if (msg.type === "deviceList") {
devices = msg.data as Device[];
console.log("devices", devices[0]);
main().catch(err => console.error("主流程启动失败:", err));
} else if (msg.type === "shutdown") {
console.log("Shutdown关闭 gRPC 流 & 停止所有 AGV");
if (stream) {
try { stream.end(); } catch (e) { /* 忽略关闭错误 */ }
}
agvMap.forEach((s) => s.stopStatusUpdates());
setTimeout(() => self.close(), 500);
} else if (msg.type === "factsheetResponse") {
// const agvMessage = {
// agvId: msg.data.agvId,
// state: msg.data.factsheet
// // message_type 会由 oneof 自动处理,我们只需提供 state 字段
// };
// message Factsheet {
// uint32 headerId = 1;
// string timestamp = 2;
// string version = 3;
// string manufacturer = 4;
// string serialNumber = 5;
// TypeSpecification typeSpecification = 6;
// PhysicalParameters physicalParameters = 7;
// ProtocolLimits protocolLimits = 8;
// ProtocolFeatures protocolFeatures = 9;
// AgvGeometry agvGeometry = 10;
// LoadSpecification loadSpecification = 11;
// VehicleConfig vehicleConfig = 12;
// }
const factsheetMsg = {
agvId: msg.data.agvId.serialNumber,
factsheet: {
headerId: globalHeaderId++,
timestamp: new Date().toISOString(),
version: "2.0.0",
manufacturer: msg.data.agvId.manufacturer,
serialNumber: msg.data.agvId.serialNumber,
typeSpecification: msg.data.factsheet.typeSpecification,
physicalParameters: msg.data.factsheet.physicalParameters,
},
};
// console.log("==>factsheetResponse", factsheetMsg);
if (!sendToStream(factsheetMsg)) {
console.error(`${msg.data.agvId}: 发送状态到 factsheet 的 gRPC 服务器失败`);
}
} else if (msg.type === "requestKVData") {
// console.log("收到 Worker requestKVData 消息,准备更新设备状态",msg.data.agvId);
if(msg && msg.data && msg.data.agvId && msg.data.agvId.serialNumber) {
const agv = agvMap.get(msg.data.agvId.serialNumber);
if (agv) {
agv.sendStateToGrpc(msg.data);
}
}
} else if (msg.type === "requestKVDataOnline") {
// console.log("收到 Worker requestKVDataOnline 消息,准备更新设备状态",msg.data.agvId);
if(msg && msg.data && msg.data.agvId && msg.data.agvId.serialNumber) {
const agv = agvMap.get(msg.data.agvId.serialNumber);
if (agv) {
agv.sendOnlineStatusGrpc(msg.data);
}
}
}
});