@7365admin1/core 3.132.0 → 3.133.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -424,6 +424,7 @@ __export(src_exports, {
424
424
  claimReadsAsStale: () => claimReadsAsStale,
425
425
  clampChassis: () => clampChassis,
426
426
  clampPtzSpeed: () => clampPtzSpeed,
427
+ clearOunitechCaches: () => clearOunitechCaches,
427
428
  clearPadbotCache: () => clearPadbotCache,
428
429
  clearRobotBrands: () => clearRobotBrands,
429
430
  clockDriftSeconds: () => clockDriftSeconds,
@@ -617,10 +618,19 @@ __export(src_exports, {
617
618
  orgQualifiesForOwnerRepair: () => orgQualifiesForOwnerRepair,
618
619
  orgRoleSets: () => orgRoleSets,
619
620
  orgSchema: () => orgSchema,
621
+ ounitechAlertRecord: () => ounitechAlertRecord,
620
622
  ounitechCleaning: () => ounitechCleaning,
623
+ ounitechConsumable: () => ounitechConsumable,
624
+ ounitechCurrentMap: () => ounitechCurrentMap,
621
625
  ounitechFault: () => ounitechFault,
622
626
  ounitechJobWords: () => ounitechJobWords,
627
+ ounitechMapShare: () => ounitechMapShare,
628
+ ounitechMapView: () => ounitechMapView,
629
+ ounitechPowerPlan: () => ounitechPowerPlan,
630
+ ounitechReadings: () => ounitechReadings,
623
631
  ounitechRobotFromHomeRow: () => ounitechRobotFromHomeRow,
632
+ ounitechTaskRecord: () => ounitechTaskRecord,
633
+ ounitechTime: () => ounitechTime,
624
634
  overnight_parking_requests_namespace_collection: () => overnight_parking_requests_namespace_collection,
625
635
  padbotAccountKey: () => padbotAccountKey,
626
636
  padbotAlarmFault: () => padbotAlarmFault,
@@ -673,6 +683,7 @@ __export(src_exports, {
673
683
  platform_terms_namespace_collection: () => platform_terms_namespace_collection,
674
684
  playbackRelays: () => playbackRelays,
675
685
  playbackWindowRefusal: () => playbackWindowRefusal,
686
+ pngSize: () => pngSize,
676
687
  promoCodeRefusal: () => promoCodeRefusal,
677
688
  promoCodeSchema: () => promoCodeSchema,
678
689
  promoCodeStatusSchema: () => promoCodeStatusSchema,
@@ -3388,10 +3399,10 @@ function useOccurrenceEntryRepo() {
3388
3399
  const cacheKey = (0, import_node_server_utils10.makeCacheKey)(namespace_collection3, {
3389
3400
  dailyOccurrenceBookId
3390
3401
  });
3391
- const cached3 = await getCache(cacheKey);
3392
- if (cached3) {
3402
+ const cached4 = await getCache(cacheKey);
3403
+ if (cached4) {
3393
3404
  import_node_server_utils10.logger.info(`Cache hit for key: ${cacheKey}`);
3394
- return cached3;
3405
+ return cached4;
3395
3406
  }
3396
3407
  const bookId = typeof dailyOccurrenceBookId === "string" ? new import_mongodb9.ObjectId(dailyOccurrenceBookId) : dailyOccurrenceBookId;
3397
3408
  const data = await collection.findOne(
@@ -18939,13 +18950,13 @@ function useFileRepo() {
18939
18950
  }
18940
18951
  const cacheKey = (0, import_node_server_utils51.makeCacheKey)(namespace_collection3, { _id: String(_id) });
18941
18952
  try {
18942
- const cached3 = await getCache(cacheKey);
18943
- if (cached3) {
18953
+ const cached4 = await getCache(cacheKey);
18954
+ if (cached4) {
18944
18955
  import_node_server_utils51.logger.log({
18945
18956
  level: "info",
18946
18957
  message: `Cache hit for getById file: ${cacheKey}`
18947
18958
  });
18948
- return cached3;
18959
+ return cached4;
18949
18960
  }
18950
18961
  const result = await collection.findOne({
18951
18962
  _id
@@ -23041,9 +23052,9 @@ function useCameraViewService() {
23041
23052
  async function refreshProbe(target, channel) {
23042
23053
  if (!target?.enabled)
23043
23054
  return null;
23044
- const cached3 = await cachedProbe(target, channel);
23045
- if (cached3)
23046
- return cached3;
23055
+ const cached4 = await cachedProbe(target, channel);
23056
+ if (cached4)
23057
+ return cached4;
23047
23058
  const probe = await probeDeviceCapabilities({
23048
23059
  adapter: createDeviceHttpAdapter({ target, budget: authBudget }),
23049
23060
  channel
@@ -23414,9 +23425,9 @@ function useCameraViewService() {
23414
23425
  };
23415
23426
  }
23416
23427
  const cacheKey = `device:${resolved.device.host}:${resolved.device.port}`;
23417
- const cached3 = await getCache(cacheKey);
23418
- const reachable = typeof cached3 === "boolean" ? cached3 : await probeDevice(resolved.device);
23419
- if (typeof cached3 !== "boolean") {
23428
+ const cached4 = await getCache(cacheKey);
23429
+ const reachable = typeof cached4 === "boolean" ? cached4 : await probeDevice(resolved.device);
23430
+ if (typeof cached4 !== "boolean") {
23420
23431
  setCache(cacheKey, reachable, cacheSeconds).catch(
23421
23432
  (error) => import_node_server_utils56.logger.info(`Camera device health cache write failed: ${error?.message}`)
23422
23433
  );
@@ -23449,10 +23460,10 @@ function useCameraViewService() {
23449
23460
  const subtype = knownNoSubStream ? 0 : wanted;
23450
23461
  const fellBackFromCache = subtype !== wanted;
23451
23462
  const cacheKey = `snapshot:${params.cameraId}:${subtype}`;
23452
- const cached3 = await getCache(cacheKey);
23453
- if (cached3) {
23463
+ const cached4 = await getCache(cacheKey);
23464
+ if (cached4) {
23454
23465
  return {
23455
- buffer: Buffer.from(cached3, "base64"),
23466
+ buffer: Buffer.from(cached4, "base64"),
23456
23467
  cached: true,
23457
23468
  stream: subtype === 0 ? "main" : "sub",
23458
23469
  fellBackToMain: fellBackFromCache
@@ -23542,9 +23553,9 @@ function useCameraViewService() {
23542
23553
  };
23543
23554
  }
23544
23555
  const cacheKey = `device:${resolved.device.host}:${resolved.device.port}`;
23545
- const cached3 = await getCache(cacheKey);
23546
- const reachable = typeof cached3 === "boolean" ? cached3 : await probeDevice(resolved.device);
23547
- if (typeof cached3 !== "boolean") {
23556
+ const cached4 = await getCache(cacheKey);
23557
+ const reachable = typeof cached4 === "boolean" ? cached4 : await probeDevice(resolved.device);
23558
+ if (typeof cached4 !== "boolean") {
23548
23559
  setCache(cacheKey, reachable, DEVICE_HEALTH_CACHE_SECONDS).catch(
23549
23560
  (error) => import_node_server_utils56.logger.info(`Camera device health cache write failed: ${error?.message}`)
23550
23561
  );
@@ -26788,13 +26799,13 @@ function usePersonRepo() {
26788
26799
  _id: String(_id)
26789
26800
  });
26790
26801
  try {
26791
- const cached3 = await getCache(cacheKey);
26792
- if (cached3) {
26802
+ const cached4 = await getCache(cacheKey);
26803
+ if (cached4) {
26793
26804
  import_node_server_utils64.logger.log({
26794
26805
  level: "info",
26795
26806
  message: `Cache hit for getById person: ${cacheKey}`
26796
26807
  });
26797
- return cached3;
26808
+ return cached4;
26798
26809
  }
26799
26810
  const result = await collection.findOne({
26800
26811
  _id
@@ -27220,13 +27231,13 @@ function usePersonRepo() {
27220
27231
  user: userId
27221
27232
  });
27222
27233
  try {
27223
- const cached3 = await getCache(cacheKey);
27224
- if (cached3) {
27234
+ const cached4 = await getCache(cacheKey);
27235
+ if (cached4) {
27225
27236
  import_node_server_utils64.logger.log({
27226
27237
  level: "info",
27227
27238
  message: `Cache hit for getByUserId person: ${cacheKey}`
27228
27239
  });
27229
- return cached3;
27240
+ return cached4;
27230
27241
  }
27231
27242
  const result = await collection.findOne({
27232
27243
  user
@@ -37773,13 +37784,13 @@ function useBuildingUnitRepo() {
37773
37784
  message: `Cache key for getAll building units: ${cacheKey}`
37774
37785
  });
37775
37786
  try {
37776
- const cached3 = await getCache(cacheKey);
37777
- if (cached3) {
37787
+ const cached4 = await getCache(cacheKey);
37788
+ if (cached4) {
37778
37789
  import_node_server_utils113.logger.log({
37779
37790
  level: "info",
37780
37791
  message: `Cache hit for getAll building units: ${cacheKey}`
37781
37792
  });
37782
- return cached3;
37793
+ return cached4;
37783
37794
  }
37784
37795
  const pipeline = [
37785
37796
  { $match: query2 },
@@ -37914,13 +37925,13 @@ function useBuildingUnitRepo() {
37914
37925
  message: `Cache key for getAll building units: ${cacheKey}`
37915
37926
  });
37916
37927
  try {
37917
- const cached3 = await getCache(cacheKey);
37918
- if (cached3) {
37928
+ const cached4 = await getCache(cacheKey);
37929
+ if (cached4) {
37919
37930
  import_node_server_utils113.logger.log({
37920
37931
  level: "info",
37921
37932
  message: `Cache hit for getAll building units: ${cacheKey}`
37922
37933
  });
37923
- return cached3;
37934
+ return cached4;
37924
37935
  }
37925
37936
  const items = await collection.aggregate(
37926
37937
  [
@@ -38009,13 +38020,13 @@ function useBuildingUnitRepo() {
38009
38020
  level: level2
38010
38021
  });
38011
38022
  try {
38012
- const cached3 = await getCache(cacheKey);
38013
- if (cached3) {
38023
+ const cached4 = await getCache(cacheKey);
38024
+ if (cached4) {
38014
38025
  import_node_server_utils113.logger.log({
38015
38026
  level: "info",
38016
38027
  message: `Cache hit for getById building unit: ${cacheKey}`
38017
38028
  });
38018
- return cached3;
38029
+ return cached4;
38019
38030
  }
38020
38031
  const result = await collection.findOne({
38021
38032
  building,
@@ -38082,13 +38093,13 @@ function useBuildingUnitRepo() {
38082
38093
  building: String(building)
38083
38094
  });
38084
38095
  try {
38085
- const cached3 = await getCache(cacheKey);
38086
- if (cached3) {
38096
+ const cached4 = await getCache(cacheKey);
38097
+ if (cached4) {
38087
38098
  import_node_server_utils113.logger.log({
38088
38099
  level: "info",
38089
38100
  message: `Cache hit for getById building unit: ${cacheKey}`
38090
38101
  });
38091
- return cached3;
38102
+ return cached4;
38092
38103
  }
38093
38104
  const result = await collection.findOne({
38094
38105
  building,
@@ -38294,13 +38305,13 @@ function useBuildingUnitRepo() {
38294
38305
  cacheOptions
38295
38306
  );
38296
38307
  try {
38297
- const cached3 = await getCache(cacheKey);
38298
- if (cached3) {
38308
+ const cached4 = await getCache(cacheKey);
38309
+ if (cached4) {
38299
38310
  import_node_server_utils113.logger.log({
38300
38311
  level: "info",
38301
38312
  message: `Cache hit for getById building unit: ${cacheKey}`
38302
38313
  });
38303
- return cached3;
38314
+ return cached4;
38304
38315
  }
38305
38316
  const result = await collection.findOne(query2, {
38306
38317
  session
@@ -38340,13 +38351,13 @@ function useBuildingUnitRepo() {
38340
38351
  level: level2
38341
38352
  });
38342
38353
  try {
38343
- const cached3 = await getCache(cacheKey);
38344
- if (cached3) {
38354
+ const cached4 = await getCache(cacheKey);
38355
+ if (cached4) {
38345
38356
  import_node_server_utils113.logger.log({
38346
38357
  level: "info",
38347
38358
  message: `Cache hit for getById building unit: ${cacheKey}`
38348
38359
  });
38349
- return cached3;
38360
+ return cached4;
38350
38361
  }
38351
38362
  const query2 = {
38352
38363
  site,
@@ -38712,9 +38723,9 @@ function useVehicleService() {
38712
38723
  const siteZones = /* @__PURE__ */ new Map();
38713
38724
  async function siteTimezone(site) {
38714
38725
  const key = String(site ?? "");
38715
- const cached3 = siteZones.get(key);
38716
- if (cached3 && Date.now() - cached3.at < 5 * 6e4)
38717
- return cached3.zone;
38726
+ const cached4 = siteZones.get(key);
38727
+ if (cached4 && Date.now() - cached4.at < 5 * 6e4)
38728
+ return cached4.zone;
38718
38729
  let zone = resolveSiteTimezone(null);
38719
38730
  if (key) {
38720
38731
  try {
@@ -41587,13 +41598,13 @@ function useBuildingRepo() {
41587
41598
  message: `Cache key for getAll buildings: ${cacheKey}`
41588
41599
  });
41589
41600
  try {
41590
- const cached3 = await getCache(cacheKey);
41591
- if (cached3) {
41601
+ const cached4 = await getCache(cacheKey);
41602
+ if (cached4) {
41592
41603
  import_node_server_utils121.logger.log({
41593
41604
  level: "info",
41594
41605
  message: `Cache hit for getAll buildings: ${cacheKey}`
41595
41606
  });
41596
- return cached3;
41607
+ return cached4;
41597
41608
  }
41598
41609
  const items = await collection.aggregate(
41599
41610
  [
@@ -41722,13 +41733,13 @@ function useBuildingRepo() {
41722
41733
  _id: String(_id)
41723
41734
  });
41724
41735
  try {
41725
- const cached3 = await getCache(cacheKey);
41726
- if (cached3) {
41736
+ const cached4 = await getCache(cacheKey);
41737
+ if (cached4) {
41727
41738
  import_node_server_utils121.logger.log({
41728
41739
  level: "info",
41729
41740
  message: `Cache hit for getById building: ${cacheKey}`
41730
41741
  });
41731
- return cached3;
41742
+ return cached4;
41732
41743
  }
41733
41744
  const result = await collection.findOne({
41734
41745
  _id
@@ -41792,13 +41803,13 @@ function useBuildingRepo() {
41792
41803
  const cacheOptions = { ...query2 };
41793
41804
  const cacheKey = (0, import_node_server_utils121.makeCacheKey)(buildings_namespace_collection, cacheOptions);
41794
41805
  try {
41795
- const cached3 = await getCache(cacheKey);
41796
- if (cached3) {
41806
+ const cached4 = await getCache(cacheKey);
41807
+ if (cached4) {
41797
41808
  import_node_server_utils121.logger.log({
41798
41809
  level: "info",
41799
41810
  message: `Cache hit for getById building: ${cacheKey}`
41800
41811
  });
41801
- return cached3;
41812
+ return cached4;
41802
41813
  }
41803
41814
  const result = await collection.findOne(query2);
41804
41815
  setCache(cacheKey, result, 300).then(() => {
@@ -42281,13 +42292,13 @@ function useBuildingLevelRepo() {
42281
42292
  message: `Cache key for getAll building levels: ${cacheKey}`
42282
42293
  });
42283
42294
  try {
42284
- const cached3 = await getCache(cacheKey);
42285
- if (cached3) {
42295
+ const cached4 = await getCache(cacheKey);
42296
+ if (cached4) {
42286
42297
  import_node_server_utils124.logger.log({
42287
42298
  level: "info",
42288
42299
  message: `Cache hit for getAll building levels: ${cacheKey}`
42289
42300
  });
42290
- return cached3;
42301
+ return cached4;
42291
42302
  }
42292
42303
  const sortStage = Object.keys(sort).length > 0 ? { $sort: sort } : { $sort: { name: 1 } };
42293
42304
  const items = await collection.aggregate(
@@ -42332,13 +42343,13 @@ function useBuildingLevelRepo() {
42332
42343
  const cacheKey = (0, import_node_server_utils124.makeCacheKey)(building_level_namespace_collection, {
42333
42344
  _id
42334
42345
  });
42335
- const cached3 = await getCache(cacheKey);
42336
- if (cached3) {
42346
+ const cached4 = await getCache(cacheKey);
42347
+ if (cached4) {
42337
42348
  import_node_server_utils124.logger.log({
42338
42349
  level: "info",
42339
42350
  message: `Cache hit for getById building level: ${cacheKey}`
42340
42351
  });
42341
- return cached3;
42352
+ return cached4;
42342
42353
  }
42343
42354
  try {
42344
42355
  _id = new import_mongodb88.ObjectId(_id);
@@ -46002,7 +46013,7 @@ function useCameraViewController() {
46002
46013
  }
46003
46014
  async function snapshot2(req, res, next) {
46004
46015
  try {
46005
- const { buffer, cached: cached3, stream, fellBackToMain } = await getSnapshot({
46016
+ const { buffer, cached: cached4, stream, fellBackToMain } = await getSnapshot({
46006
46017
  cameraId: String(req.params.id ?? ""),
46007
46018
  userId: callerId5(req)
46008
46019
  });
@@ -46011,7 +46022,7 @@ function useCameraViewController() {
46011
46022
  "Cache-Control",
46012
46023
  `private, max-age=${CAMERA_SNAPSHOT_CACHE_SECONDS}`
46013
46024
  );
46014
- res.setHeader("X-Camera-Snapshot-Cached", cached3 ? "1" : "0");
46025
+ res.setHeader("X-Camera-Snapshot-Cached", cached4 ? "1" : "0");
46015
46026
  res.setHeader("X-Camera-Stream", stream);
46016
46027
  res.setHeader("X-Camera-Stream-Fallback", fellBackToMain ? "1" : "0");
46017
46028
  res.status(200).end(buffer);
@@ -64248,6 +64259,9 @@ var ROBOT_CLOUD_PATHS = {
64248
64259
  taskList: "/portal/cleaning/get-task-list",
64249
64260
  alertList: "/portal/alert/get-alert-list",
64250
64261
  liftList: "/portal/lift/get-lift-list",
64262
+ workHours: "/portal/workhours/get-work-hours",
64263
+ haltPlans: "/portal/halt-plan/get",
64264
+ stationState: "/portal/detailstate/get-station-detail-state",
64251
64265
  mapList: "/portal/maps/get-map-list",
64252
64266
  fileUrl: "/portal/maps/get-file-url",
64253
64267
  tracking: "/portal/robots/tracking",
@@ -64544,6 +64558,9 @@ var STEP_NAMES = {
64544
64558
  [ROBOT_CLOUD_PATHS.filePreview]: "the map images",
64545
64559
  [ROBOT_CLOUD_PATHS.plansV2]: "the cleaning schedule",
64546
64560
  [ROBOT_CLOUD_PATHS.taskList]: "the cleaning records",
64561
+ [ROBOT_CLOUD_PATHS.workHours]: "the consumable hours",
64562
+ [ROBOT_CLOUD_PATHS.haltPlans]: "the power schedule",
64563
+ [ROBOT_CLOUD_PATHS.stationState]: "the base station state",
64547
64564
  [ROBOT_CLOUD_PATHS.alertList]: "the alert history",
64548
64565
  [ROBOT_CLOUD_PATHS.liftList]: "the lift list"
64549
64566
  };
@@ -64748,6 +64765,23 @@ function useRobotCloudService(credentials, options = {}) {
64748
64765
  async function getLiftList(sceneId) {
64749
64766
  return post(ROBOT_CLOUD_PATHS.liftList, { sceneid: sceneId }, "liftlist");
64750
64767
  }
64768
+ async function getWorkHours(robotId) {
64769
+ return post(ROBOT_CLOUD_PATHS.workHours, { robotId }, "unitlist");
64770
+ }
64771
+ async function getHaltPlans(robotId) {
64772
+ return post(
64773
+ ROBOT_CLOUD_PATHS.haltPlans,
64774
+ { planId: 0, robotId, pageNo: 1, pageSize: 20 },
64775
+ "planList"
64776
+ );
64777
+ }
64778
+ async function getStationState(robotId) {
64779
+ const data = await post(
64780
+ ROBOT_CLOUD_PATHS.stationState,
64781
+ { robotId, options: "state" }
64782
+ );
64783
+ return data.state ?? null;
64784
+ }
64751
64785
  async function getMaps(robotSn) {
64752
64786
  const data = await post(
64753
64787
  ROBOT_CLOUD_PATHS.mapList,
@@ -64829,6 +64863,9 @@ function useRobotCloudService(credentials, options = {}) {
64829
64863
  getPlansV2,
64830
64864
  getTaskList,
64831
64865
  getAlerts,
64866
+ getWorkHours,
64867
+ getHaltPlans,
64868
+ getStationState,
64832
64869
  getLiftList,
64833
64870
  getMaps,
64834
64871
  getFileUrls,
@@ -64842,6 +64879,7 @@ function useRobotCloudService(credentials, options = {}) {
64842
64879
  }
64843
64880
 
64844
64881
  // src/services/ounitech.adapter.ts
64882
+ var import_axios4 = __toESM(require("axios"));
64845
64883
  var OUNITECH_BRAND = "ounitech";
64846
64884
  var OUNITECH_CAPABILITIES = {
64847
64885
  // Pose in the chapter-6 robot list (metres) and the tracking stream.
@@ -65023,12 +65061,326 @@ function ounitechFault(list) {
65023
65061
  return { code: "error", message: String(list[0]).slice(0, 200) };
65024
65062
  return { code: "error", message: "The robot reports an error" };
65025
65063
  }
65064
+ function ounitechMapShare(map, x, y) {
65065
+ const w = map?.width, h = map?.height, r = map?.resolution;
65066
+ const wx = num(x), wy = num(y);
65067
+ if (!finite(w) || !finite(h) || !finite(r) || w <= 0 || h <= 0 || r <= 0 || wx === void 0 || wy === void 0)
65068
+ return null;
65069
+ const sx = (wx - (num(map?.originX) ?? 0)) / r / w * 100;
65070
+ const sy = 100 - (wy - (num(map?.originY) ?? 0)) / r / h * 100;
65071
+ if (sx < 0 || sx > 100 || sy < 0 || sy > 100)
65072
+ return null;
65073
+ return { x: Math.round(sx * 100) / 100, y: Math.round(sy * 100) / 100 };
65074
+ }
65075
+ function ounitechMapView(m, imageUrl, partitionImageUrl, size) {
65076
+ const floorNo2 = Number.isInteger(m.floorNo) ? m.floorNo : null;
65077
+ const width = size?.width ?? null;
65078
+ const height = size?.height ?? null;
65079
+ const frame2 = { width, height, resolution: m.resolution, originX: m.originX, originY: m.originY };
65080
+ const areas = (Array.isArray(m.areaList) ? m.areaList : []).filter((a) => typeof a?.areaName === "string" && a.areaName.trim()).map((a) => {
65081
+ const px = num(a.x), py = num(a.y);
65082
+ const at2 = width && height && px !== void 0 && py !== void 0 && (px > 0 || py > 0) && px <= width && py <= height ? { x: Math.round(px / width * 1e4) / 100, y: Math.round(py / height * 1e4) / 100 } : null;
65083
+ return { ...a.areaId != null ? { areaId: a.areaId } : {}, areaName: a.areaName.trim(), rgba: a.rgba, x: a.x, y: a.y, at: at2 };
65084
+ });
65085
+ return {
65086
+ mapId: String(m.mapId ?? `floor-${floorNo2 ?? 0}`),
65087
+ floor: floorNo2,
65088
+ floorNo: floorNo2,
65089
+ mapDisplayName: String(m.mapName ?? "").trim(),
65090
+ mapName: m.mapName,
65091
+ imageUrl,
65092
+ partitionImageUrl,
65093
+ width,
65094
+ height,
65095
+ resolution: m.resolution,
65096
+ originX: m.originX,
65097
+ originY: m.originY,
65098
+ backgroundFileKey: m.backgroundFileKey,
65099
+ partitionFileKey: m.partitionFileKey,
65100
+ totalArea: m.totalArea,
65101
+ baseX: m.baseX,
65102
+ baseY: m.baseY,
65103
+ baseTheta: m.baseTheta,
65104
+ createTime: m.createTime,
65105
+ dock: ounitechMapShare(frame2, m.baseX ?? 0, m.baseY ?? 0),
65106
+ positionApproximate: true,
65107
+ // The raw areas, kept for older screens.
65108
+ areaList: areas.map(({ at: _at, ...a }) => a),
65109
+ areas: areas.map((a) => ({ name: a.areaName, at: a.at }))
65110
+ };
65111
+ }
65112
+ function ounitechCurrentMap(maps, taskMapId, floorNo2) {
65113
+ const byTask = taskMapId != null ? maps.find((m) => m.mapId === String(taskMapId)) : void 0;
65114
+ if (byTask)
65115
+ return byTask;
65116
+ if (Number.isInteger(floorNo2))
65117
+ return maps.find((m) => m.floorNo === floorNo2) ?? null;
65118
+ return maps.length === 1 ? maps[0] : null;
65119
+ }
65120
+ function pngSize(bytes) {
65121
+ if (!bytes || bytes.length < 24)
65122
+ return null;
65123
+ const ihdr = String.fromCharCode(bytes[12], bytes[13], bytes[14], bytes[15]);
65124
+ if (bytes[1] !== 80 || ihdr !== "IHDR")
65125
+ return null;
65126
+ const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
65127
+ const width = dv.getUint32(16), height = dv.getUint32(20);
65128
+ return width > 0 && height > 0 && width < 2e4 && height < 2e4 ? { width, height } : null;
65129
+ }
65130
+ async function fetchPngSize(url2) {
65131
+ try {
65132
+ const res = await import_axios4.default.get(url2, { responseType: "arraybuffer", headers: { Range: "bytes=0-63" }, timeout: 8e3 });
65133
+ return pngSize(new Uint8Array(res.data));
65134
+ } catch {
65135
+ return null;
65136
+ }
65137
+ }
65138
+ function ounitechTime(v, tzMinutes = 480) {
65139
+ const m = typeof v === "string" ? /^(\d{4}-\d{2}-\d{2})[ T](\d{2}:\d{2}(?::\d{2})?)/.exec(v.trim()) : null;
65140
+ if (!m)
65141
+ return null;
65142
+ const t = Date.parse(`${m[1]}T${m[2].length === 5 ? `${m[2]}:00` : m[2]}Z`) - tzMinutes * 6e4;
65143
+ return Number.isFinite(t) ? new Date(t).toISOString() : null;
65144
+ }
65145
+ var MODE_WORDS = { \u5438\u5C18: "Vacuum", \u6D17\u5730: "Wash floor", \u5C18\u63A8: "Dust mop", \u62D6\u5730: "Mop" };
65146
+ var TYPE_WORDS = {
65147
+ \u51C6\u5907\u6E05\u6D01: "Getting ready",
65148
+ \u8131\u79BB\u57FA\u7AD9\u4E2D: "Leaving the charger",
65149
+ \u5168\u5C40\u6E05\u626B: "Clean all",
65150
+ \u5206\u533A\u6E05\u626B: "Area clean",
65151
+ \u5B9A\u70B9\u6E05\u626B: "Spot clean",
65152
+ \u56DE\u5145: "Returning to charge",
65153
+ \u6CBF\u8FB9\u6E05\u626B: "Edge clean"
65154
+ };
65155
+ var SOURCE_WORDS = { plan: "Schedule", app: "Ounitech app", btn: "Button on the robot" };
65156
+ var round1 = (v) => v !== void 0 ? Math.round(v * 10) / 10 : null;
65157
+ function ounitechTaskRecord(t, maps = [], tz = 480) {
65158
+ const map = maps.find((m) => m.mapId === String(t.mapId));
65159
+ const kind = String(t.typeName ?? "").trim();
65160
+ const mode = String(t.subTypeName ?? "").trim();
65161
+ const src = String(t.source ?? "").split(",")[0].trim();
65162
+ const mileage = num(t.cleanedMileage);
65163
+ return {
65164
+ id: String(t.taskId ?? ""),
65165
+ start: ounitechTime(t.timeFrom, tz),
65166
+ end: ounitechTime(t.timeTo, tz),
65167
+ durationSec: num(t.durationSeconds) ?? num(t.accTime) ?? null,
65168
+ areaM2: round1(num(t.cleanedArea) ?? num(t.accArea)),
65169
+ plannedM2: round1(num(t.countArea)),
65170
+ percent: num(t.accPercent) ?? null,
65171
+ distanceM: mileage !== void 0 ? Math.round(mileage) : null,
65172
+ result: String(t.statusName ?? "").trim() || null,
65173
+ job: TYPE_WORDS[kind] ?? (kind || null),
65174
+ mode: MODE_WORDS[mode] ?? (mode || null),
65175
+ source: SOURCE_WORDS[src] ?? (src || null),
65176
+ map: map ? map.mapDisplayName || (map.floorNo !== null ? `Floor ${map.floorNo}` : null) : null,
65177
+ floorNo: Number.isInteger(t.floorNo) ? t.floorNo : map?.floorNo ?? null
65178
+ };
65179
+ }
65180
+ var ALERT_WORDS = {
65181
+ "205": "Side brush driver offline",
65182
+ "206": "Button panel offline",
65183
+ "540": "Floor check: cliff sensor switched on",
65184
+ "588": "Switched off with the power button",
65185
+ "589": "Switched off by the timed power schedule",
65186
+ "593": "Still finding its position - try again shortly",
65187
+ "601": "Left wheel driver reset",
65188
+ "620": "Right wheel driver offline",
65189
+ "621": "Right wheel driver reset",
65190
+ "734": "IMU zero offset too large",
65191
+ "785": "Localisation ready"
65192
+ };
65193
+ var ALERT_LEVEL_WORDS = { \u63D0\u793A: "Notice", \u8B66\u544A: "Warning", \u6545\u969C: "Fault", \u9519\u8BEF: "Error", \u4E25\u91CD: "Critical" };
65194
+ function ounitechAlertRecord(a, tz = 480) {
65195
+ const raw = String(a.errMsg ?? a.errCode ?? "").trim();
65196
+ const m = /^\s*(\d+)\s*-\s*(.*)$/.exec(raw);
65197
+ const code = m?.[1] ?? "";
65198
+ let rest = (m?.[2] ?? raw).trim();
65199
+ const resolved = /\(Resolved\)\s*$/i.test(rest);
65200
+ rest = rest.replace(/\(Resolved\)\s*$/i, "").replace(/\(\s*\d+\s*\)\s*$/, "").trim();
65201
+ const lv = /^\(([^)]*)\)/.exec(rest);
65202
+ if (lv)
65203
+ rest = rest.slice(lv[0].length).trim();
65204
+ return {
65205
+ code,
65206
+ level: lv ? ALERT_LEVEL_WORDS[lv[1].trim()] ?? lv[1].trim() : null,
65207
+ // An untranslated Chinese text keeps its code up front, so the row is never only Chinese.
65208
+ message: ALERT_WORDS[code] ?? (/[㐀-鿿]/.test(rest || raw) && code ? `Robot alert ${code}: ${rest || raw}` : rest || raw),
65209
+ vendorText: rest || raw,
65210
+ resolved,
65211
+ at: ounitechTime(a.createTime, tz)
65212
+ };
65213
+ }
65214
+ var READINGS = {
65215
+ "battery-percent": { group: "Battery", label: "Battery", unit: "%" },
65216
+ "left-battery-percent": { group: "Battery", label: "Left battery", unit: "%" },
65217
+ "right-battery-percent": { group: "Battery", label: "Right battery", unit: "%" },
65218
+ "bat-vol-left": { group: "Battery", label: "Left battery voltage", unit: "V" },
65219
+ "bat-vol-right": { group: "Battery", label: "Right battery voltage", unit: "V" },
65220
+ BatteryOffline: { group: "Battery", label: "Battery disconnected", bad: "true" },
65221
+ BatteryClosed: { group: "Battery", label: "Battery switched off", bad: "true" },
65222
+ "clean-water": { group: "Water", label: "Clean water", unit: "%" },
65223
+ "dirty-water": { group: "Water", label: "Dirty water", unit: "%" },
65224
+ "clean-water-level": { group: "Water", label: "Clean water level" },
65225
+ "dirty-water-level": { group: "Water", label: "Dirty water level" },
65226
+ "ctank-full": { group: "Water", label: "Clean water tank full" },
65227
+ "cmop-pump-low": { group: "Water", label: "Mop water running low", bad: "true" },
65228
+ "top-cover": { group: "Parts in place", label: "Top cover closed", bad: "false" },
65229
+ "hand-push-rod": { group: "Parts in place", label: "Push handle in place", bad: "false" },
65230
+ "clean-water-tank": { group: "Parts in place", label: "Clean water tank fitted", bad: "false" },
65231
+ "waste-water-tank": { group: "Parts in place", label: "Dirty water tank fitted", bad: "false" },
65232
+ "dust-box": { group: "Parts in place", label: "Dust box fitted", bad: "false" },
65233
+ "collision-left": { group: "Sensors", label: "Left bumper pressed", bad: "true" },
65234
+ "collision-right": { group: "Sensors", label: "Right bumper pressed", bad: "true" },
65235
+ "wfan-brake-flag": { group: "Sensors", label: "Water suction fan blocked", bad: "true" },
65236
+ "sfan-brake-flag": { group: "Sensors", label: "Dust suction fan blocked", bad: "true" },
65237
+ "wfan-brake-percent": { group: "Sensors", label: "Water suction fan blockage", unit: "%" },
65238
+ "sfan-brake-percent": { group: "Sensors", label: "Dust suction fan blockage", unit: "%" },
65239
+ job: { group: "Current job", label: "Job" },
65240
+ status: { group: "Current job", label: "Work status" },
65241
+ "acc-percent": { group: "Current job", label: "Job done", unit: "%" },
65242
+ "acc-area": { group: "Current job", label: "Area cleaned", unit: "m\xB2" },
65243
+ "count-area": { group: "Current job", label: "Area planned", unit: "m\xB2" },
65244
+ "acc-mile": { group: "Current job", label: "Distance driven", unit: "m" },
65245
+ "acc-time": { group: "Current job", label: "Cleaning time" },
65246
+ "acc-task": { group: "Current job", label: "Jobs counted" },
65247
+ "avg-speed": { group: "Current job", label: "Average speed", unit: "m\xB2/s" },
65248
+ x: { group: "Position", label: "Position x", unit: "m" },
65249
+ y: { group: "Position", label: "Position y", unit: "m" },
65250
+ theta: { group: "Position", label: "Heading", unit: "rad" },
65251
+ "mcu-state": { group: "Connection", label: "Main board connected", bad: "false" },
65252
+ bslink: { group: "Connection", label: "Linked to the base station" },
65253
+ RouterSignalStrength: { group: "Connection", label: "Mobile signal" },
65254
+ IsOfflineMode: { group: "Connection", label: "Offline mode", bad: "true" },
65255
+ OfflineVersion: { group: "Software", label: "Offline map version" },
65256
+ McuSW: { group: "Software", label: "Main board software" },
65257
+ FaceH7SW: { group: "Software", label: "Front panel software" },
65258
+ SlamType: { group: "Software", label: "Mapping type" },
65259
+ LockType: { group: "Software", label: "Lock type" }
65260
+ };
65261
+ var STATION_READINGS = {
65262
+ "clean-water": { group: "Base station", label: "Station clean water", unit: "L" },
65263
+ "dirty-water": { group: "Base station", label: "Station dirty water", unit: "L" },
65264
+ "clean-percent": { group: "Base station", label: "Station clean water", unit: "%" },
65265
+ "dirty-percent": { group: "Base station", label: "Station dirty water", unit: "%" },
65266
+ temperature: { group: "Base station", label: "Station temperature", unit: "\xB0C" },
65267
+ "bluetooth-err": { group: "Base station", label: "Bluetooth fault", bad: "true" },
65268
+ "charge-err": { group: "Base station", label: "Charging fault", bad: "true" },
65269
+ "clean-box-err": { group: "Base station", label: "Clean water box fault", bad: "true" },
65270
+ "clean-pump-err": { group: "Base station", label: "Clean water pump fault", bad: "true" },
65271
+ "dirty-box-err": { group: "Base station", label: "Dirty water box fault", bad: "true" },
65272
+ "dirty-pump-err": { group: "Base station", label: "Dirty water pump fault", bad: "true" },
65273
+ "dust-box-err": { group: "Base station", label: "Dust box fault", bad: "true" },
65274
+ "dust-fan-err": { group: "Base station", label: "Dust fan fault", bad: "true" },
65275
+ "ir-err": { group: "Base station", label: "Docking sensor fault", bad: "true" },
65276
+ "solenoid-err": { group: "Base station", label: "Water valve fault", bad: "true" },
65277
+ "temperature-err": { group: "Base station", label: "Temperature fault", bad: "true" },
65278
+ "water-sensor-err": { group: "Base station", label: "Water sensor fault", bad: "true" }
65279
+ };
65280
+ var HIDDEN_READINGS = /* @__PURE__ */ new Set(["RobotIP", "RouterIccid"]);
65281
+ var LEVEL_READING = { \u4F4E: "Low", \u4E2D: "Medium", \u9AD8: "High", \u7A7A: "Empty", \u6EE1: "Full" };
65282
+ function ounitechReadings(props, station = false) {
65283
+ const defs = station ? STATION_READINGS : READINGS;
65284
+ const out = [];
65285
+ for (const p of Array.isArray(props) ? props : []) {
65286
+ const key = String(p?.key ?? "").trim();
65287
+ if (!key || HIDDEN_READINGS.has(key))
65288
+ continue;
65289
+ const raw = p?.value == null ? "" : String(p.value).trim();
65290
+ if (raw === "" || raw === "-")
65291
+ continue;
65292
+ const d = defs[key] ?? { group: station ? "Base station" : "Other readings", label: key };
65293
+ let value;
65294
+ if (raw === "true" || raw === "false")
65295
+ value = raw === "true" ? "Yes" : "No";
65296
+ else if (key === "job")
65297
+ value = JOB_WORDS[raw] ?? raw;
65298
+ else if (key === "status")
65299
+ value = ROBOT_STATUS_NAMES[STATUS_CODE_BY_READING[raw] ?? -1] ?? raw;
65300
+ else if (LEVEL_READING[raw])
65301
+ value = LEVEL_READING[raw];
65302
+ else if (key === "acc-time" && num(raw) !== void 0)
65303
+ value = `${Math.round(num(raw) / 60)} min`;
65304
+ else
65305
+ value = d.unit === "%" ? `${raw}%` : d.unit ? `${raw} ${d.unit}` : raw;
65306
+ out.push({ key, group: d.group, label: d.label, value, attention: !!d.bad && raw === d.bad });
65307
+ }
65308
+ return out;
65309
+ }
65310
+ var PART_WORDS = {
65311
+ left_side_brush_plastic: "Left side brush",
65312
+ right_side_brush_plastic: "Right side brush",
65313
+ dust_bag: "Dust bag",
65314
+ single_suction_mouth_rubber: "Suction rubber",
65315
+ floor_brush_double_roller_structure: "Floor brush rollers",
65316
+ floor_mop_double_roller_structure: "Mop rollers"
65317
+ };
65318
+ var upFirst = (t) => t.charAt(0).toUpperCase() + t.slice(1);
65319
+ function ounitechConsumable(u) {
65320
+ const code = String(u.unitcode ?? "").trim();
65321
+ const minutes = num(u.workminutes);
65322
+ return {
65323
+ part: PART_WORDS[code] ?? upFirst(code.replace(/_/g, " ") || String(u.unitname ?? "").trim() || "Part"),
65324
+ hours: minutes !== void 0 ? Math.round(minutes / 6) / 10 : null,
65325
+ days: num(u.workdays) ?? null
65326
+ };
65327
+ }
65328
+ function ounitechPowerPlan(p) {
65329
+ return {
65330
+ days: (Array.isArray(p.dateList) ? p.dateList : []).map(Number).filter((d) => d >= 1 && d <= 7),
65331
+ time: String(p.actionTime ?? "").trim(),
65332
+ action: Number(p.actionFlag) === 1 ? "on" : "off",
65333
+ enabled: p.enableFlag !== false
65334
+ };
65335
+ }
65336
+ var MAP_TTL_MS = 10 * 6e4;
65337
+ var RECORDS_TTL_MS = 2 * 6e4;
65338
+ var mapCache = /* @__PURE__ */ new Map();
65339
+ var recordsCache = /* @__PURE__ */ new Map();
65340
+ function cached2(cache3, field, key, ttl, load) {
65341
+ const hit = cache3.get(key);
65342
+ if (hit && Date.now() - hit.at < ttl)
65343
+ return hit[field];
65344
+ const p = load();
65345
+ cache3.set(key, { at: Date.now(), [field]: p });
65346
+ p.catch(() => cache3.delete(key));
65347
+ return p;
65348
+ }
65349
+ function clearOunitechCaches() {
65350
+ mapCache.clear();
65351
+ recordsCache.clear();
65352
+ }
65026
65353
  var robotTime = (d) => robotCloudTimestamp(d, "yyyy-MM-dd HH:mm:ss", "Asia/Shanghai");
65027
65354
  function createOunitechAdapter(credentials, options) {
65028
65355
  const cloud = useRobotCloudService(credentials, options);
65029
65356
  async function liveFor(row) {
65030
65357
  return needsLiveState(row) ? cloud.getRobotState(row.robotId).catch(() => null) : null;
65031
65358
  }
65359
+ function floorMaps(sceneId) {
65360
+ return cached2(mapCache, "maps", `${options?.baseUrl ?? ""}|${credentials.appid}|${sceneId}`, MAP_TTL_MS, async () => {
65361
+ const list = (await cloud.getFloorMaps(sceneId)).filter((m) => m.latestFlag !== false);
65362
+ const keys = list.flatMap((m) => [m.backgroundFileKey, m.partitionFileKey]).filter((k) => typeof k === "string" && !!k);
65363
+ const files = keys.length ? await cloud.previewFiles(keys).catch(() => []) : [];
65364
+ const url2 = (k) => files.find((f) => f.fileKey === k)?.url || null;
65365
+ return Promise.all(
65366
+ list.map(async (m) => {
65367
+ const imageUrl = url2(m.backgroundFileKey);
65368
+ return ounitechMapView(m, imageUrl, url2(m.partitionFileKey), imageUrl ? await fetchPngSize(imageUrl) : null);
65369
+ })
65370
+ );
65371
+ });
65372
+ }
65373
+ async function placed(row, robot) {
65374
+ if (!robot.online || !finite(row.sceneId))
65375
+ return robot;
65376
+ const maps = await floorMaps(row.sceneId).catch(() => []);
65377
+ const map = ounitechCurrentMap(maps, row.taskState?.mapId, robot.floorNo);
65378
+ if (!map)
65379
+ return robot;
65380
+ robot.mapId = map.mapId;
65381
+ robot.planPosition = robot.position ? ounitechMapShare(map, robot.position.x, robot.position.y) : null;
65382
+ return robot;
65383
+ }
65032
65384
  async function rowFor(robotSn) {
65033
65385
  return (await cloud.getHomeRobots()).find((r) => r.robotSn === robotSn) ?? null;
65034
65386
  }
@@ -65037,7 +65389,9 @@ function createOunitechAdapter(credentials, options) {
65037
65389
  displayName: "Ounitech (Q3-G / Q3-W)",
65038
65390
  capabilities: OUNITECH_CAPABILITIES,
65039
65391
  async listRobots() {
65040
- return Promise.all((await cloud.getHomeRobots()).map(async (row) => ounitechRobotFromHomeRow(row, await liveFor(row))));
65392
+ return Promise.all(
65393
+ (await cloud.getHomeRobots()).map(async (row) => placed(row, ounitechRobotFromHomeRow(row, await liveFor(row))))
65394
+ );
65041
65395
  },
65042
65396
  async getRobot(robotSn) {
65043
65397
  const row = await rowFor(robotSn);
@@ -65053,7 +65407,7 @@ function createOunitechAdapter(credentials, options) {
65053
65407
  position: null
65054
65408
  };
65055
65409
  }
65056
- return ounitechRobotFromHomeRow(row, await liveFor(row));
65410
+ return placed(row, ounitechRobotFromHomeRow(row, await liveFor(row)));
65057
65411
  },
65058
65412
  async sendCommand(robotSn, command) {
65059
65413
  const options2 = {
@@ -65081,31 +65435,16 @@ function createOunitechAdapter(credentials, options) {
65081
65435
  );
65082
65436
  }
65083
65437
  },
65084
- /** Chapter 6 floor maps, in the chapter-2 shape the screens read (walls left out - they are large). */
65438
+ /**
65439
+ * Chapter 6 floor maps (walls left out - they are large): the chapter-2
65440
+ * fields plus `mapId`, `imageUrl`, `width` / `height` (from the PNG) and
65441
+ * the areas' centres, so robot detail draws the real map with the robot on it.
65442
+ */
65085
65443
  async getMaps(robotSn) {
65086
65444
  const row = await rowFor(robotSn);
65087
65445
  if (!row || !finite(row.sceneId))
65088
65446
  return [];
65089
- return (await cloud.getFloorMaps(row.sceneId)).filter((m) => m.latestFlag !== false).map((m) => ({
65090
- floorNo: m.floorNo,
65091
- mapName: m.mapName,
65092
- backgroundFileKey: m.backgroundFileKey,
65093
- partitionFileKey: m.partitionFileKey,
65094
- originX: m.originX,
65095
- originY: m.originY,
65096
- resolution: m.resolution,
65097
- totalArea: m.totalArea,
65098
- baseX: m.baseX,
65099
- baseY: m.baseY,
65100
- baseTheta: m.baseTheta,
65101
- createTime: m.createTime,
65102
- areaList: (Array.isArray(m.areaList) ? m.areaList : []).map((a) => ({
65103
- areaName: a.areaName,
65104
- rgba: a.rgba,
65105
- x: a.x,
65106
- y: a.y
65107
- }))
65108
- }));
65447
+ return floorMaps(row.sceneId);
65109
65448
  },
65110
65449
  async getMapImages(_robotSn, fileKeys) {
65111
65450
  return cloud.previewFiles(fileKeys);
@@ -65124,6 +65463,57 @@ function createOunitechAdapter(credentials, options) {
65124
65463
  jobList: p.cleanList ?? p.jobList ?? []
65125
65464
  }));
65126
65465
  },
65466
+ /**
65467
+ * Robot detail's records (read-only, cached 2 min - the vendor rate-limits):
65468
+ * cleaning jobs (14 days), alert history (30 days), consumable hours, power
65469
+ * schedule, lifts, every live reading and the base station. Reads run one
65470
+ * after another (gentler on the rate limit); each part carries its own error.
65471
+ */
65472
+ async getRecords(robotSn) {
65473
+ return cached2(recordsCache, "value", `${options?.baseUrl ?? ""}|${credentials.appid}|${robotSn}`, RECORDS_TTL_MS, async () => {
65474
+ const row = await rowFor(robotSn);
65475
+ if (!row || !finite(row.robotId))
65476
+ return { supported: true, error: `Serial ${robotSn} is not on this Ounitech account.` };
65477
+ const robotId = row.robotId;
65478
+ const tz = finite(row.timezone) ? row.timezone : 480;
65479
+ const now = /* @__PURE__ */ new Date();
65480
+ const since = (days) => robotTime(new Date(now.getTime() - days * 864e5));
65481
+ const part = async (read2) => {
65482
+ try {
65483
+ return { items: await read2() };
65484
+ } catch (e) {
65485
+ return { items: [], error: String(e?.message ?? e).slice(0, 300) };
65486
+ }
65487
+ };
65488
+ const maps = finite(row.sceneId) ? await floorMaps(row.sceneId).catch(() => []) : [];
65489
+ const tasks = await part(
65490
+ async () => ((await cloud.getTaskList(robotId, since(14), robotTime(now))).taskList ?? []).map((t) => ounitechTaskRecord(t, maps, tz)).sort((a, b) => String(b.start ?? "").localeCompare(String(a.start ?? ""))).slice(0, 50)
65491
+ );
65492
+ const alerts = await part(
65493
+ async () => ((await cloud.getAlerts(robotId, since(30), robotTime(now))).alertList ?? []).map((a) => ounitechAlertRecord(a, tz))
65494
+ );
65495
+ const consumables = await part(async () => ((await cloud.getWorkHours(robotId)).unitlist ?? []).map(ounitechConsumable));
65496
+ const power = await part(async () => ((await cloud.getHaltPlans(robotId)).planList ?? []).map(ounitechPowerPlan));
65497
+ const lifts = finite(row.sceneId) ? await part(
65498
+ async () => ((await cloud.getLiftList(row.sceneId)).liftlist ?? []).map((l) => ({
65499
+ name: String(l.liftname ?? "").trim() || `Lift ${l.liftno ?? ""}`.trim(),
65500
+ floorNo: Number.isInteger(l.floorno) ? l.floorno : null,
65501
+ online: Number(l.onlineflag) === 1,
65502
+ enabled: l.enableflag !== false
65503
+ }))
65504
+ ) : { items: [] };
65505
+ const readings = await part(async () => ounitechReadings((await cloud.getRobotState(robotId)).properties));
65506
+ const station = await part(async () => {
65507
+ const st = await cloud.getStationState(robotId).catch((e) => {
65508
+ if (/no station bound|e=59/i.test(String(e?.message ?? "")))
65509
+ return null;
65510
+ throw e;
65511
+ });
65512
+ return st ? [{ status: String(st.statusName ?? "").trim() || null, readings: ounitechReadings(st.properties, true) }] : [];
65513
+ });
65514
+ return { supported: true, readAt: now.toISOString(), tasks, alerts, consumables, power, lifts, readings, station };
65515
+ });
65516
+ },
65127
65517
  /**
65128
65518
  * Staff Diagnose: every other read-only chapter-6 call, with the vendor's
65129
65519
  * answer (lists cut to 3). Never a command, never the signed envelope.
@@ -65197,6 +65587,9 @@ function createOunitechAdapter(credentials, options) {
65197
65587
  const r = await cloud.getAlerts(robotId, window.timeFrom, window.timeTo);
65198
65588
  return { total: r.total ?? r.alertList?.length ?? 0, latest: cut(r.alertList ?? []) };
65199
65589
  });
65590
+ await run("consumable hours (get-work-hours)", ROBOT_CLOUD_PATHS.workHours, { robotId }, async () => cut((await cloud.getWorkHours(robotId)).unitlist ?? []));
65591
+ await run("power schedule (halt-plan/get)", ROBOT_CLOUD_PATHS.haltPlans, { robotId }, async () => cut((await cloud.getHaltPlans(robotId)).planList ?? []));
65592
+ await run("base station (get-station-detail-state)", ROBOT_CLOUD_PATHS.stationState, { robotId, options: "state" }, async () => cloud.getStationState(robotId));
65200
65593
  if (finite(row.sceneId)) {
65201
65594
  const sceneId = row.sceneId;
65202
65595
  await run("lifts (get-lift-list)", ROBOT_CLOUD_PATHS.liftList, { sceneid: sceneId }, async () => {
@@ -65230,7 +65623,7 @@ var OUNITECH_BRAND_DEFINITION = {
65230
65623
  { name: "Q3-G", codes: ["Q3G", "Q3-G"] },
65231
65624
  { name: "Q3-W", codes: ["Q3W", "Q3-W"] }
65232
65625
  ],
65233
- info: { makerApp: "the Ounitech app", makerAppOnly: ["pausing or stopping a job", "cleaning across floors"] },
65626
+ info: { makerApp: "the Ounitech app", makerAppOnly: ["pausing or stopping a job", "cleaning across floors", "changing maps, areas and schedules"] },
65234
65627
  create: (credentials) => createOunitechAdapter(credentials)
65235
65628
  };
65236
65629
  function registerOunitechBrand() {
@@ -66029,7 +66422,7 @@ function createOpenRmfClient(config2, deps) {
66029
66422
  throw new OpenRmfError("The fleet server sent a reply that is not JSON.");
66030
66423
  }
66031
66424
  }
66032
- function cached3(key, ttlMs, load) {
66425
+ function cached4(key, ttlMs, load) {
66033
66426
  const k = `${config2?.baseUrl}|${key}`;
66034
66427
  const hit = cache.get(k);
66035
66428
  if (hit && now() - hit.at < ttlMs)
@@ -66041,8 +66434,8 @@ function createOpenRmfClient(config2, deps) {
66041
66434
  }
66042
66435
  const enc2 = encodeURIComponent;
66043
66436
  return {
66044
- fleets: () => cached3("fleets", 1500, () => call("GET", "/fleets")),
66045
- buildingMap: () => cached3("building_map", 6e4, () => call("GET", "/building_map")),
66437
+ fleets: () => cached4("fleets", 1500, () => call("GET", "/fleets")),
66438
+ buildingMap: () => cached4("building_map", 6e4, () => call("GET", "/building_map")),
66046
66439
  doors: () => call("GET", "/doors"),
66047
66440
  doorState: (name) => call("GET", `/doors/${enc2(name)}/state`),
66048
66441
  doorRequest: (name, mode) => call("POST", `/doors/${enc2(name)}/request`, { mode }),
@@ -67486,7 +67879,7 @@ function mapSummary(m) {
67486
67879
  }
67487
67880
  var CACHE_TTL_MS = 5 * 6e4;
67488
67881
  var cache2 = /* @__PURE__ */ new Map();
67489
- function cached2(key, load) {
67882
+ function cached3(key, load) {
67490
67883
  const hit = cache2.get(key);
67491
67884
  if (hit && Date.now() - hit.at < CACHE_TTL_MS)
67492
67885
  return hit.value;
@@ -67572,8 +67965,8 @@ function createPadbotAdapter(credentials, options = {}) {
67572
67965
  const ns = `${credentials.appid}@${options.baseUrl ?? padbotBaseUrl()}`;
67573
67966
  const account = padbotAccountKey(credentials);
67574
67967
  const callRaw = call;
67575
- const roster = () => cached2(`${ns}:robots`, () => call(PADBOT_PATHS.robots, { robotTypes: ["PATROL"] }));
67576
- const maps = (sn) => cached2(`${ns}:maps:${sn}`, () => call(PADBOT_PATHS.maps, { serialNumber: sn }).then(asList));
67968
+ const roster = () => cached3(`${ns}:robots`, () => call(PADBOT_PATHS.robots, { robotTypes: ["PATROL"] }));
67969
+ const maps = (sn) => cached3(`${ns}:maps:${sn}`, () => call(PADBOT_PATHS.maps, { serialNumber: sn }).then(asList));
67577
67970
  const states = async (sn) => {
67578
67971
  const list = await call(PADBOT_PATHS.states, { serialNumbers: [sn] });
67579
67972
  const entry = (list ?? []).find((e) => e?.serialNumber === sn);
@@ -68141,6 +68534,12 @@ function useRobotFleetService(deps) {
68141
68534
  return [];
68142
68535
  return adapter.getMapImages(await resolveRobotSn(robot), fileKeys);
68143
68536
  }
68537
+ async function getRecords(robot) {
68538
+ const adapter = adapterFor(robot);
68539
+ if (!adapter.getRecords)
68540
+ return null;
68541
+ return adapter.getRecords(await resolveRobotSn(robot));
68542
+ }
68144
68543
  async function getPlans(robot) {
68145
68544
  const adapter = adapterFor(robot);
68146
68545
  if (!adapter.getPlans)
@@ -68510,6 +68909,7 @@ function useRobotFleetService(deps) {
68510
68909
  getMaps,
68511
68910
  getMapImages,
68512
68911
  getPlans,
68912
+ getRecords,
68513
68913
  getPatrolRoutes,
68514
68914
  dispatch: dispatch2
68515
68915
  };
@@ -71103,9 +71503,9 @@ function rmfSummary(rmf) {
71103
71503
  }
71104
71504
 
71105
71505
  // src/services/robot-tracking.service.ts
71106
- var import_axios4 = __toESM(require("axios"));
71506
+ var import_axios5 = __toESM(require("axios"));
71107
71507
  async function openWithAxios(url2, body) {
71108
- const response = await import_axios4.default.post(url2, body, {
71508
+ const response = await import_axios5.default.post(url2, body, {
71109
71509
  responseType: "stream",
71110
71510
  // No read timeout: this connection is SUPPOSED to stay open and mostly
71111
71511
  // silent. A request timeout here would sever a healthy stream on a quiet
@@ -71318,6 +71718,14 @@ function useRobotFleetController(deps) {
71318
71718
  fail(next, error);
71319
71719
  }
71320
71720
  }
71721
+ async function getRecords(req, res, next) {
71722
+ try {
71723
+ const robot = await entitleRobot(req, req.params.id);
71724
+ res.json(await getFleet2().getRecords(robot) ?? { supported: false });
71725
+ } catch (error) {
71726
+ fail(next, error);
71727
+ }
71728
+ }
71321
71729
  async function getPatrolRoutes(req, res, next) {
71322
71730
  try {
71323
71731
  const robot = await entitleRobot(req, req.params.id);
@@ -71611,6 +72019,7 @@ function useRobotFleetController(deps) {
71611
72019
  getMaps,
71612
72020
  getMapImages,
71613
72021
  getPlans,
72022
+ getRecords,
71614
72023
  getPatrolRoutes,
71615
72024
  sendCommand: sendCommand2,
71616
72025
  trackRobot,
@@ -80249,13 +80658,13 @@ function useSiteBillingItemRepo() {
80249
80658
  }
80250
80659
  const cacheKey = (0, import_node_server_utils209.makeCacheKey)(namespace_collection3, { _id: String(_id) });
80251
80660
  try {
80252
- const cached3 = await getCache(cacheKey);
80253
- if (cached3) {
80661
+ const cached4 = await getCache(cacheKey);
80662
+ if (cached4) {
80254
80663
  import_node_server_utils209.logger.log({
80255
80664
  level: "info",
80256
80665
  message: `Cache hit for getById site billing items: ${cacheKey}`
80257
80666
  });
80258
- return cached3;
80667
+ return cached4;
80259
80668
  }
80260
80669
  const result = await collection.findOne({
80261
80670
  _id
@@ -80609,13 +81018,13 @@ function useSiteBillingConfigurationRepo() {
80609
81018
  }
80610
81019
  const cacheKey = (0, import_node_server_utils211.makeCacheKey)(namespace_collection3, { _id: String(_id) });
80611
81020
  try {
80612
- const cached3 = await getCache(cacheKey);
80613
- if (cached3) {
81021
+ const cached4 = await getCache(cacheKey);
81022
+ if (cached4) {
80614
81023
  import_node_server_utils211.logger.log({
80615
81024
  level: "info",
80616
81025
  message: `Cache hit for getById site billing configuration: ${cacheKey}`
80617
81026
  });
80618
- return cached3;
81027
+ return cached4;
80619
81028
  }
80620
81029
  const result = await collection.findOne({
80621
81030
  _id
@@ -82260,13 +82669,13 @@ function useSiteUnitBillingRepo() {
82260
82669
  }
82261
82670
  const cacheKey = (0, import_node_server_utils220.makeCacheKey)(namespace_collection3, { _id: String(_id) });
82262
82671
  try {
82263
- const cached3 = await getCache(cacheKey);
82264
- if (cached3) {
82672
+ const cached4 = await getCache(cacheKey);
82673
+ if (cached4) {
82265
82674
  import_node_server_utils220.logger.log({
82266
82675
  level: "info",
82267
82676
  message: `Cache hit for getById site unit billing: ${cacheKey}`
82268
82677
  });
82269
- return cached3;
82678
+ return cached4;
82270
82679
  }
82271
82680
  const result = await collection.findOne({
82272
82681
  _id
@@ -85069,13 +85478,13 @@ function useNfcPatrolRouteRepo() {
85069
85478
  }
85070
85479
  const cacheKey = (0, import_node_server_utils227.makeCacheKey)(namespace_collection3, cacheParams);
85071
85480
  try {
85072
- const cached3 = await getCache(cacheKey);
85073
- if (cached3) {
85481
+ const cached4 = await getCache(cacheKey);
85482
+ if (cached4) {
85074
85483
  import_node_server_utils227.logger.log({
85075
85484
  level: "info",
85076
85485
  message: `Cache hit for getById ${namespace_collection3}: ${cacheKey}`
85077
85486
  });
85078
- return cached3;
85487
+ return cached4;
85079
85488
  }
85080
85489
  let result;
85081
85490
  if (isStart === true) {
@@ -86523,13 +86932,13 @@ function useStatementOfAccountRepo() {
86523
86932
  }
86524
86933
  const cacheKey = (0, import_node_server_utils235.makeCacheKey)(namespace_collection3, { _id: String(_id) });
86525
86934
  try {
86526
- const cached3 = await getCache(cacheKey);
86527
- if (cached3) {
86935
+ const cached4 = await getCache(cacheKey);
86936
+ if (cached4) {
86528
86937
  import_node_server_utils235.logger.log({
86529
86938
  level: "info",
86530
86939
  message: `Cache hit for getById soa: ${cacheKey}`
86531
86940
  });
86532
- return cached3;
86941
+ return cached4;
86533
86942
  }
86534
86943
  const result = await collection.findOne({
86535
86944
  _id
@@ -93601,7 +94010,7 @@ var MManpowerMonitoring = class {
93601
94010
  var import_node_server_utils265 = require("@7365admin1/node-server-utils");
93602
94011
 
93603
94012
  // src/utils/hrmlabs-attendance.util.ts
93604
- var import_axios5 = __toESM(require("axios"));
94013
+ var import_axios6 = __toESM(require("axios"));
93605
94014
  var import_moment_timezone7 = __toESM(require("moment-timezone"));
93606
94015
  var default_early_checkIn = 4;
93607
94016
  async function hrmLabsAuthentication({
@@ -93610,7 +94019,7 @@ async function hrmLabsAuthentication({
93610
94019
  password,
93611
94020
  domain
93612
94021
  }) {
93613
- const res = await import_axios5.default.post(
94022
+ const res = await import_axios6.default.post(
93614
94023
  authUrl,
93615
94024
  {
93616
94025
  grant_type: "password",
@@ -93640,7 +94049,7 @@ async function fetchAttendanceData({
93640
94049
  search
93641
94050
  }) {
93642
94051
  try {
93643
- const res = await import_axios5.default.post(
94052
+ const res = await import_axios6.default.post(
93644
94053
  attendanceUrl,
93645
94054
  {
93646
94055
  start: startDate,
@@ -93840,7 +94249,7 @@ async function fetchSites({ siteUrl, token }) {
93840
94249
  do {
93841
94250
  try {
93842
94251
  attempt++;
93843
- const res = await import_axios5.default.get(siteUrl, {
94252
+ const res = await import_axios6.default.get(siteUrl, {
93844
94253
  headers: { Authorization: `Bearer ${token}` },
93845
94254
  timeout: 15e3
93846
94255
  });
@@ -97391,7 +97800,7 @@ async function manpowerEvents(io) {
97391
97800
  }
97392
97801
 
97393
97802
  // src/services/reddot-payment.service.ts
97394
- var import_axios6 = __toESM(require("axios"));
97803
+ var import_axios7 = __toESM(require("axios"));
97395
97804
 
97396
97805
  // src/utils/payment-signature.util.ts
97397
97806
  var crypto11 = __toESM(require("crypto"));
@@ -98025,7 +98434,7 @@ var useRedDotPaymentSvc = () => {
98025
98434
  );
98026
98435
  }
98027
98436
  const url2 = process.env.MERCHANT_PAYMENT;
98028
- const response = await import_axios6.default.post(url2, dataString, { headers });
98437
+ const response = await import_axios7.default.post(url2, dataString, { headers });
98029
98438
  const result = response.data;
98030
98439
  return result;
98031
98440
  } catch (error) {
@@ -98059,7 +98468,7 @@ var useRedDotPaymentSvc = () => {
98059
98468
  );
98060
98469
  }
98061
98470
  const url2 = process.env.MERCHANT_ENQUIRY;
98062
- const response = await import_axios6.default.post(url2, dataString, { headers });
98471
+ const response = await import_axios7.default.post(url2, dataString, { headers });
98063
98472
  const result = response.data;
98064
98473
  const transactionId = result.transaction_id;
98065
98474
  const amount = result.request_amount || 0;
@@ -107224,6 +107633,7 @@ function usePersonalEmergencyChainController() {
107224
107633
  claimReadsAsStale,
107225
107634
  clampChassis,
107226
107635
  clampPtzSpeed,
107636
+ clearOunitechCaches,
107227
107637
  clearPadbotCache,
107228
107638
  clearRobotBrands,
107229
107639
  clockDriftSeconds,
@@ -107417,10 +107827,19 @@ function usePersonalEmergencyChainController() {
107417
107827
  orgQualifiesForOwnerRepair,
107418
107828
  orgRoleSets,
107419
107829
  orgSchema,
107830
+ ounitechAlertRecord,
107420
107831
  ounitechCleaning,
107832
+ ounitechConsumable,
107833
+ ounitechCurrentMap,
107421
107834
  ounitechFault,
107422
107835
  ounitechJobWords,
107836
+ ounitechMapShare,
107837
+ ounitechMapView,
107838
+ ounitechPowerPlan,
107839
+ ounitechReadings,
107423
107840
  ounitechRobotFromHomeRow,
107841
+ ounitechTaskRecord,
107842
+ ounitechTime,
107424
107843
  overnight_parking_requests_namespace_collection,
107425
107844
  padbotAccountKey,
107426
107845
  padbotAlarmFault,
@@ -107473,6 +107892,7 @@ function usePersonalEmergencyChainController() {
107473
107892
  platform_terms_namespace_collection,
107474
107893
  playbackRelays,
107475
107894
  playbackWindowRefusal,
107895
+ pngSize,
107476
107896
  promoCodeRefusal,
107477
107897
  promoCodeSchema,
107478
107898
  promoCodeStatusSchema,