api-amr/agv_worker.ts

932 lines
28 KiB
TypeScript
Raw Normal View History

2025-06-04 19:15:02 +08:00
// 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);
}
}
}
});