@ray-js/robot-data-stream 0.0.15-beta.8 → 0.0.16-beta.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.
Files changed (36) hide show
  1. package/lib/constant.d.ts +1 -0
  2. package/lib/constant.js +11 -0
  3. package/lib/mqtt/hooks/useStructuredMessage.d.ts +0 -3
  4. package/lib/mqtt/hooks/useStructuredMessage.js +150 -75
  5. package/lib/mqtt/mqttProvider.d.ts +10 -1
  6. package/lib/mqtt/mqttProvider.js +5 -3
  7. package/lib/mqtt/type/fun.d.ts +24 -9
  8. package/lib/mqtt/type/fun.js +2 -1
  9. package/lib/mqtt/type/index.d.ts +4 -1
  10. package/lib/mqtt/type/protocols/base.d.ts +4 -1
  11. package/lib/mqtt/type/protocols/base.js +9 -3
  12. package/lib/mqtt/type/protocols/carpetCleanProtocol.d.ts +2 -2
  13. package/lib/mqtt/type/protocols/carpetCleanProtocol.js +2 -2
  14. package/lib/mqtt/type/protocols/carpetProtocol.d.ts +5 -5
  15. package/lib/mqtt/type/protocols/carpetProtocol.js +7 -7
  16. package/lib/mqtt/type/protocols/roomPropertyProtocol.d.ts +8 -2
  17. package/lib/mqtt/type/protocols/roomPropertyProtocol.js +26 -5
  18. package/lib/mqtt/type/protocols/scheduleProtocol.d.ts +12 -3
  19. package/lib/mqtt/type/protocols/scheduleProtocol.js +17 -0
  20. package/lib/mqtt/type/protocols/selectRoomCleanProtocol.d.ts +6 -2
  21. package/lib/mqtt/type/protocols/selectRoomCleanProtocol.js +12 -4
  22. package/lib/mqtt/type/protocols/spotCleanProtocol.d.ts +8 -2
  23. package/lib/mqtt/type/protocols/spotCleanProtocol.js +24 -2
  24. package/lib/mqtt/type/protocols/wifiMapProtocol.d.ts +1 -0
  25. package/lib/mqtt/type/protocols/wifiMapProtocol.js +2 -1
  26. package/lib/mqtt/type/protocols/zoneCleanProtocol.d.ts +7 -2
  27. package/lib/mqtt/type/protocols/zoneCleanProtocol.js +31 -4
  28. package/lib/mqtt/useRoomProperty.js +8 -5
  29. package/lib/mqtt/useSchedule.js +20 -7
  30. package/lib/mqtt/useSelectRoomClean.js +37 -14
  31. package/lib/mqtt/useSpotClean.js +22 -12
  32. package/lib/mqtt/useWifiMap.js +4 -2
  33. package/lib/mqtt/useZoneClean.js +38 -46
  34. package/lib/mqtt/waterPreference.d.ts +20 -0
  35. package/lib/mqtt/waterPreference.js +70 -0
  36. package/package.json +7 -4
@@ -1,5 +1,7 @@
1
1
  import * as z from '../../../myLib/zod/mini';
2
+ import { MqttError } from '../../promise';
2
3
  import { BaseResponseSchema, Point } from './base';
4
+ const VALIDATION_ERROR_CODE = -2;
3
5
  const zoneSchema = z.object({
4
6
  // 区域点集
5
7
  points: z.array(Point),
@@ -20,10 +22,12 @@ export const setZoneCleanSchema = z.object({
20
22
  zones: z.array(zoneSchema),
21
23
  origin: Point,
22
24
  suctions: z.optional(z.array(z.string())),
23
- cisterns: z.optional(z.array(z.string())),
25
+ cisterns: z.optional(z.array(z.union([z.string(), z.number()]))),
26
+ waterValues: z.optional(z.array(z.union([z.string(), z.number()]))),
24
27
  cleanCounts: z.optional(z.array(z.int())),
25
28
  yMops: z.optional(z.array(z.int())),
26
- sweepMopModes: z.optional(z.array(z.string()))
29
+ sweepMopModes: z.optional(z.array(z.string())),
30
+ routePreferences: z.optional(z.array(z.string()))
27
31
  });
28
32
 
29
33
  // 划区清扫响应 Schema
@@ -35,15 +39,38 @@ const setZoneCleanResponseSchema = z.extend(BaseResponseSchema, {
35
39
  // 吸力, closed - 关闭 gentle - 安静 normal - 正常 strong - 强劲 max - 超强 ,默认值为''
36
40
  suctions: z.optional(z.array(z.string())),
37
41
  // 拖地水量 "closed"- 关闭,"low"-低,"middle"-中,"high"-高,默认值为''
38
- cisterns: z.optional(z.array(z.string())),
42
+ cisterns: z.optional(z.array(z.union([z.string(), z.number()]))),
43
+ // 自定义拖地水量
44
+ waterValues: z.optional(z.array(z.union([z.string(), z.number()]))),
39
45
  // 清扫次数 默认值1
40
46
  cleanCounts: z.optional(z.array(z.int())),
41
47
  // 拖地模式 1:开启Y型拖地 0:关闭Y型拖地 -1 未设置 默认值-1
42
48
  yMops: z.optional(z.array(z.int())),
43
49
  // 扫拖模式 "only_sweep":仅扫,"only_mop":仅拖,"both_work":扫拖同时,"clean_before_mop":先扫后拖,默认值为'only_sweep'
44
- sweepMopModes: z.optional(z.array(z.string()))
50
+ sweepMopModes: z.optional(z.array(z.string())),
51
+ // 路线偏好
52
+ routePreferences: z.optional(z.array(z.string()))
45
53
  });
46
54
 
47
55
  // 类型导出
48
56
 
57
+ export function validateSetZoneClean(data) {
58
+ const num = data.zones.length;
59
+ const validateLength = (name, value) => {
60
+ if (value && value.length !== num) {
61
+ throw new MqttError(`${name} length must be ${num}, actual is ${value.length}`, {
62
+ errCode: VALIDATION_ERROR_CODE,
63
+ reqType: 'set_zone_clean'
64
+ });
65
+ }
66
+ };
67
+ validateLength('suctions', data.suctions);
68
+ validateLength('cisterns', data.cisterns);
69
+ validateLength('waterValues', data.waterValues);
70
+ validateLength('cleanCounts', data.cleanCounts);
71
+ validateLength('yMops', data.yMops);
72
+ validateLength('sweepMopModes', data.sweepMopModes);
73
+ validateLength('routePreferences', data.routePreferences);
74
+ }
75
+
49
76
  // 函数类型定义
@@ -1,8 +1,10 @@
1
+ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
1
2
  import { useContext } from 'react';
2
3
  import { handleMqttError, useStructuredMessage } from './hooks/useStructuredMessage';
3
4
  import { SingletonContext } from './mqttProvider';
4
5
  import { RoomPropertyEnum } from './type';
5
6
  import { validator } from './type/fun';
7
+ import { normalizeWaterPreferencePayload } from './waterPreference';
6
8
  /**
7
9
  * 自定义 Hook,用于房间属性管理
8
10
  * @param devId 设备ID(可选,如果不提供则从 MqttProvider Context 获取)
@@ -45,7 +47,7 @@ export const useRoomProperty = () => {
45
47
  setRoomProperty: data => {
46
48
  return new Promise((resolve, reject) => {
47
49
  try {
48
- var _data$num, _data$suctions, _data$cisterns, _data$cleanCounts, _data$yMops, _data$sweepMopModes, _data$names;
50
+ var _data$num, _data$suctions, _data$cleanCounts, _data$yMops, _data$sweepMopModes, _data$names, _data$routePreference;
49
51
  if (!useMqtt) {
50
52
  reject(new Error('useMqtt is not used'));
51
53
  return;
@@ -56,18 +58,19 @@ export const useRoomProperty = () => {
56
58
  ids
57
59
  } = data;
58
60
  const len = ids.length;
59
- const sendData = {
61
+ const sendData = _objectSpread({
60
62
  num: (_data$num = data.num) !== null && _data$num !== void 0 ? _data$num : len,
61
63
  ids,
62
64
  suctions: (_data$suctions = data.suctions) !== null && _data$suctions !== void 0 ? _data$suctions : new Array(len).fill('closed'),
63
- cisterns: (_data$cisterns = data.cisterns) !== null && _data$cisterns !== void 0 ? _data$cisterns : new Array(len).fill('closed'),
64
65
  cleanCounts: (_data$cleanCounts = data.cleanCounts) !== null && _data$cleanCounts !== void 0 ? _data$cleanCounts : new Array(len).fill(1),
65
66
  yMops: (_data$yMops = data.yMops) !== null && _data$yMops !== void 0 ? _data$yMops : new Array(len).fill(-1),
66
67
  sweepMopModes: (_data$sweepMopModes = data.sweepMopModes) !== null && _data$sweepMopModes !== void 0 ? _data$sweepMopModes : new Array(len).fill('only_sweep'),
67
68
  names: (_data$names = data.names) !== null && _data$names !== void 0 ? _data$names : new Array(len).fill(''),
69
+ nameLabels: data.nameLabels,
68
70
  floorTypes: data.floorTypes,
69
- orders: data.orders
70
- };
71
+ orders: data.orders,
72
+ routePreferences: (_data$routePreference = data.routePreferences) !== null && _data$routePreference !== void 0 ? _data$routePreference : new Array(len).fill('standard')
73
+ }, normalizeWaterPreferencePayload(data.cisterns, data.waterValues));
71
74
 
72
75
  // 使用 TypeBox Schema 进行参数验证(包含自定义验证逻辑)
73
76
  const validatedData = validator.validate('set_room_property', sendData);
@@ -1,8 +1,10 @@
1
+ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
1
2
  import "core-js/modules/esnext.iterator.map.js";
2
3
  // 定时
3
4
  import { encodeDeviceTimer0x30 } from '@ray-js/robot-protocol';
4
5
  import { useContext } from 'react';
5
- import { CISTERN_MAP, CLEAN_MODE_MAP, SUCTION_MAP } from '../constant';
6
+ import { CLEAN_MODE_MAP, SUCTION_MAP, ROUTE_PREFERENCE_MAP } from '../constant';
7
+ import { normalizeWaterPreferencePayload, resolveWaterLevel } from './waterPreference';
6
8
  import { handleMqttError, useStructuredMessage } from './hooks/useStructuredMessage';
7
9
  import { SingletonContext } from './mqttProvider';
8
10
  import { ScheduleEnum } from './type';
@@ -53,8 +55,16 @@ export const useSchedule = () => {
53
55
  try {
54
56
  // 使用 TypeBox Schema 进行参数验证
55
57
  const validatedData = validator.validate('set_schedule', message);
58
+ const list = validatedData.list.map(item => {
59
+ var _item$routePreference, _item$ids;
60
+ return _objectSpread(_objectSpread(_objectSpread({}, item), normalizeWaterPreferencePayload(item.cisterns, item.waterValues)), {}, {
61
+ routePreferences: (_item$routePreference = item.routePreferences) !== null && _item$routePreference !== void 0 ? _item$routePreference : new Array(((_item$ids = item.ids) === null || _item$ids === void 0 ? void 0 : _item$ids.length) || 1).fill('standard')
62
+ });
63
+ });
56
64
  if (useMqtt) {
57
- sendStructuredMessage(ScheduleEnum.set, validatedData, resolve, error => reject(handleMqttError(error, 'Failed to set schedule')), ScheduleEnum.query // 响应类型是 query,不是 set
65
+ sendStructuredMessage(ScheduleEnum.set, _objectSpread(_objectSpread({}, validatedData), {}, {
66
+ list
67
+ }), resolve, error => reject(handleMqttError(error, 'Failed to set schedule')), ScheduleEnum.query // 响应类型是 query,不是 set
58
68
  );
59
69
  return;
60
70
  }
@@ -63,7 +73,7 @@ export const useSchedule = () => {
63
73
  const command = encodeDeviceTimer0x30({
64
74
  version: commandVersion,
65
75
  number: validatedData.num,
66
- list: validatedData.list.map(_ref => {
76
+ list: list.map(_ref => {
67
77
  let {
68
78
  active,
69
79
  suctions,
@@ -72,13 +82,15 @@ export const useSchedule = () => {
72
82
  cleanCounts,
73
83
  cycle,
74
84
  cisterns,
75
- time
85
+ waterValues,
86
+ time,
87
+ routePreferences
76
88
  } = _ref;
77
89
  return {
78
90
  effectiveness: active,
79
91
  cleanMode: CLEAN_MODE_MAP[(sweepMopModes === null || sweepMopModes === void 0 ? void 0 : sweepMopModes[0]) || ''],
80
92
  fanLevel: SUCTION_MAP[(suctions === null || suctions === void 0 ? void 0 : suctions[0]) || ''],
81
- waterLevel: CISTERN_MAP[(cisterns === null || cisterns === void 0 ? void 0 : cisterns[0]) || ''],
93
+ waterLevel: resolveWaterLevel(waterValues === null || waterValues === void 0 ? void 0 : waterValues[0], cisterns === null || cisterns === void 0 ? void 0 : cisterns[0]),
82
94
  time: {
83
95
  hour: time[0],
84
96
  minute: time[1]
@@ -86,7 +98,8 @@ export const useSchedule = () => {
86
98
  week: cycle,
87
99
  sweepCount: (cleanCounts === null || cleanCounts === void 0 ? void 0 : cleanCounts[0]) || 1,
88
100
  roomIds: ids || [],
89
- roomNum: (ids === null || ids === void 0 ? void 0 : ids.length) || 0
101
+ roomNum: (ids === null || ids === void 0 ? void 0 : ids.length) || 0,
102
+ routePreference: ROUTE_PREFERENCE_MAP[(routePreferences === null || routePreferences === void 0 ? void 0 : routePreferences[0]) || 'standard']
90
103
  };
91
104
  })
92
105
  });
@@ -97,7 +110,7 @@ export const useSchedule = () => {
97
110
  reqType: ScheduleEnum.query,
98
111
  version: commandVersion,
99
112
  taskId: `${Date.now()}`,
100
- list: validatedData.list,
113
+ list,
101
114
  num: validatedData.num
102
115
  });
103
116
  } catch (error) {
@@ -1,3 +1,4 @@
1
+ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
1
2
  import "core-js/modules/esnext.iterator.constructor.js";
2
3
  import "core-js/modules/esnext.iterator.for-each.js";
3
4
  import "core-js/modules/esnext.iterator.map.js";
@@ -8,6 +9,7 @@ import { handleMqttError, useStructuredMessage } from './hooks/useStructuredMess
8
9
  import { SingletonContext } from './mqttProvider';
9
10
  import { RoomCleanSetEnum } from './type';
10
11
  import { validator } from './type/fun';
12
+ import { normalizeWaterPreferencePayload } from './waterPreference';
11
13
  /**
12
14
  * 自定义 Hook,用于选区清扫
13
15
  * @returns 包含 requestSelectRoomClean 和 setRoomClean 函数的对象
@@ -59,9 +61,11 @@ export const useSelectRoomClean = () => {
59
61
  ids: [],
60
62
  suctions: [],
61
63
  cisterns: [],
64
+ waterValues: [],
62
65
  cleanCounts: [],
63
66
  yMops: [],
64
- sweepMopModes: []
67
+ sweepMopModes: [],
68
+ routePreferences: []
65
69
  });
66
70
  } catch (error) {
67
71
  reject(handleMqttError(error, 'Failed to request select room clean'));
@@ -77,28 +81,36 @@ export const useSelectRoomClean = () => {
77
81
  if (useMqtt) {
78
82
  const ids = [];
79
83
  const suctions = [];
80
- const cisterns = [];
81
84
  const cleanCounts = [];
82
85
  const yMops = [];
83
86
  const sweepMopModes = [];
87
+ const routePreferences = [];
84
88
  rooms.forEach(room => {
85
- var _room$suction, _room$cleanTimes, _room$yMop, _room$sweepMopMode;
89
+ var _room$suction, _room$cleanTimes, _room$yMop, _room$sweepMopMode, _room$routePreference;
86
90
  ids.push(room.roomId);
87
91
  suctions.push((_room$suction = room.suction) !== null && _room$suction !== void 0 ? _room$suction : '');
88
- cisterns.push(room.cistern);
89
92
  cleanCounts.push((_room$cleanTimes = room.cleanTimes) !== null && _room$cleanTimes !== void 0 ? _room$cleanTimes : 1);
90
93
  yMops.push((_room$yMop = room.yMop) !== null && _room$yMop !== void 0 ? _room$yMop : -1);
91
94
  sweepMopModes.push((_room$sweepMopMode = room.sweepMopMode) !== null && _room$sweepMopMode !== void 0 ? _room$sweepMopMode : 'only_sweep');
95
+ routePreferences.push((_room$routePreference = room.routePreference) !== null && _room$routePreference !== void 0 ? _room$routePreference : 'standard');
92
96
  });
93
- sendStructuredMessage(RoomCleanSetEnum.set, {
97
+ const waterPayload = normalizeWaterPreferencePayload(rooms.map(room => {
98
+ var _room$cistern;
99
+ return (_room$cistern = room.cistern) !== null && _room$cistern !== void 0 ? _room$cistern : '';
100
+ }), rooms.map(room => {
101
+ var _room$waterValue;
102
+ return (_room$waterValue = room.waterValue) !== null && _room$waterValue !== void 0 ? _room$waterValue : '';
103
+ }));
104
+ sendStructuredMessage(RoomCleanSetEnum.set, _objectSpread(_objectSpread({
94
105
  ids,
95
- suctions,
96
- cisterns,
106
+ suctions
107
+ }, waterPayload), {}, {
97
108
  cleanCounts,
98
109
  yMops,
99
110
  sweepMopModes,
111
+ routePreferences,
100
112
  num: rooms.length
101
- }, resolve, error => reject(handleMqttError(error, 'Failed to set room clean')), RoomCleanSetEnum.query // 响应类型是 query,不是 set
113
+ }), resolve, error => reject(handleMqttError(error, 'Failed to set room clean')), RoomCleanSetEnum.query // 响应类型是 query,不是 set
102
114
  );
103
115
  return;
104
116
  }
@@ -115,7 +127,13 @@ export const useSelectRoomClean = () => {
115
127
  var _room$suction2;
116
128
  return (_room$suction2 = room.suction) !== null && _room$suction2 !== void 0 ? _room$suction2 : '';
117
129
  });
118
- const cisterns = rooms.map(room => room.cistern);
130
+ const waterPayload = normalizeWaterPreferencePayload(rooms.map(room => {
131
+ var _room$cistern2;
132
+ return (_room$cistern2 = room.cistern) !== null && _room$cistern2 !== void 0 ? _room$cistern2 : '';
133
+ }), rooms.map(room => {
134
+ var _room$waterValue2;
135
+ return (_room$waterValue2 = room.waterValue) !== null && _room$waterValue2 !== void 0 ? _room$waterValue2 : '';
136
+ }));
119
137
  const cleanCounts = rooms.map(room => {
120
138
  var _room$cleanTimes2;
121
139
  return (_room$cleanTimes2 = room.cleanTimes) !== null && _room$cleanTimes2 !== void 0 ? _room$cleanTimes2 : 1;
@@ -128,19 +146,24 @@ export const useSelectRoomClean = () => {
128
146
  var _room$sweepMopMode2;
129
147
  return (_room$sweepMopMode2 = room.sweepMopMode) !== null && _room$sweepMopMode2 !== void 0 ? _room$sweepMopMode2 : 'only_sweep';
130
148
  });
131
- resolve({
149
+ const routePreferences = rooms.map(room => {
150
+ var _room$routePreference2;
151
+ return (_room$routePreference2 = room.routePreference) !== null && _room$routePreference2 !== void 0 ? _room$routePreference2 : 'standard';
152
+ });
153
+ resolve(_objectSpread(_objectSpread({
132
154
  success: true,
133
155
  errCode: 0,
134
156
  reqType: RoomCleanSetEnum.query,
135
157
  version: commandVersion,
136
158
  taskId: `${Date.now()}`,
137
159
  ids,
138
- suctions,
139
- cisterns,
160
+ suctions
161
+ }, waterPayload), {}, {
140
162
  cleanCounts,
141
163
  yMops,
142
- sweepMopModes
143
- });
164
+ sweepMopModes,
165
+ routePreferences
166
+ }));
144
167
  } catch (error) {
145
168
  reject(handleMqttError(error, 'Failed to set room clean'));
146
169
  }
@@ -1,3 +1,4 @@
1
+ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
1
2
  import "core-js/modules/esnext.iterator.map.js";
2
3
  // 定点清扫
3
4
 
@@ -8,6 +9,7 @@ import { encodeSpotClean0x16 } from '@ray-js/robot-protocol';
8
9
  import { pointsToString } from '../utils';
9
10
  import { useStructuredMessage, handleMqttError } from './hooks/useStructuredMessage';
10
11
  import { validator } from './type/fun';
12
+ import { normalizeWaterPreferencePayload } from './waterPreference';
11
13
  /**
12
14
  * 自定义 Hook,用于定点清扫
13
15
  * @returns 包含 requestSpotClean 和 setSpotClean 函数的对象
@@ -57,25 +59,30 @@ export const useSpotClean = () => {
57
59
  origin
58
60
  } = validatedData;
59
61
  const num = spots.length;
62
+ const waterPayload = normalizeWaterPreferencePayload(validatedData.cisterns, validatedData.waterValues);
60
63
 
61
64
  // 为可选字段设置默认值
62
65
  const {
63
66
  suctions = new Array(num).fill(''),
64
- cisterns = new Array(num).fill(''),
65
67
  cleanCounts = new Array(num).fill(1),
66
68
  yMops = new Array(num).fill(-1),
67
- sweepMopModes = new Array(num).fill('only_sweep')
69
+ sweepMopModes = new Array(num).fill('only_sweep'),
70
+ routePreferences = new Array(num).fill('standard'),
71
+ names
68
72
  } = validatedData;
69
73
  if (useMqtt) {
70
- sendStructuredMessage(SpotCleanEnum.set, {
74
+ sendStructuredMessage(SpotCleanEnum.set, _objectSpread(_objectSpread({
71
75
  num,
72
76
  polygons: spots.map(spot => pointsToString([spot], origin)),
73
- suctions,
74
- cisterns,
77
+ suctions
78
+ }, waterPayload), {}, {
75
79
  cleanCounts,
76
80
  yMops,
77
- sweepMopModes
78
- }, resolve, error => reject(handleMqttError(error, 'Failed to set spot clean')), SpotCleanEnum.query // 响应类型是 query,不是 set
81
+ sweepMopModes,
82
+ routePreferences
83
+ }, names && {
84
+ names
85
+ }), resolve, error => reject(handleMqttError(error, 'Failed to set spot clean')), SpotCleanEnum.query // 响应类型是 query,不是 set
79
86
  );
80
87
  return;
81
88
  }
@@ -87,19 +94,22 @@ export const useSpotClean = () => {
87
94
  point: spots[0]
88
95
  });
89
96
  devices.common.model.actions.command_trans.set(command);
90
- resolve({
97
+ resolve(_objectSpread(_objectSpread({
91
98
  success: true,
92
99
  errCode: 0,
93
100
  reqType: SpotCleanEnum.query,
94
101
  version: commandVersion,
95
102
  taskId: `${Date.now()}`,
96
103
  polygons: spots.map(spot => pointsToString([spot], origin)),
97
- suctions,
98
- cisterns,
104
+ suctions
105
+ }, waterPayload), {}, {
99
106
  cleanCounts,
100
107
  yMops,
101
- sweepMopModes
102
- });
108
+ sweepMopModes,
109
+ routePreferences
110
+ }, names && {
111
+ names
112
+ }));
103
113
  } catch (error) {
104
114
  reject(handleMqttError(error, 'Failed to set spot clean'));
105
115
  }
@@ -18,7 +18,7 @@ export const useWifiMap = () => {
18
18
 
19
19
  /**
20
20
  * 设置 WiFi 地图
21
- * @param data 包含 taskId 的参数对象(taskId 可选,不提供时自动生成)
21
+ * @param data 包含 taskId 的参数对象(taskId 可选,不提供时自动生成,switch 可选,默认)
22
22
  * @returns Promise<WifiMapResponse> 响应结果
23
23
  */
24
24
 
@@ -36,9 +36,11 @@ export const useWifiMap = () => {
36
36
  let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
37
37
  return new Promise((resolve, reject) => {
38
38
  try {
39
+ var _data$switch;
39
40
  // 如果没有提供 taskId,自动生成
40
41
  const wifiMapData = {
41
- taskId: data.taskId || String(Date.now())
42
+ taskId: data.taskId || String(Date.now()),
43
+ switch: (_data$switch = data.switch) !== null && _data$switch !== void 0 ? _data$switch : true
42
44
  };
43
45
 
44
46
  // 使用 TypeBox Schema 进行参数验证
@@ -1,3 +1,4 @@
1
+ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
1
2
  import "core-js/modules/esnext.iterator.map.js";
2
3
  // 划区清扫
3
4
  import { encodeZoneClean0x3a, requestZoneClean0x3b } from '@ray-js/robot-protocol';
@@ -7,6 +8,7 @@ import { handleMqttError, useStructuredMessage } from './hooks/useStructuredMess
7
8
  import { SingletonContext } from './mqttProvider';
8
9
  import { ZoneCleanEnum } from './type';
9
10
  import { validator } from './type/fun';
11
+ import { normalizeWaterPreferencePayload } from './waterPreference';
10
12
  /**
11
13
  * 自定义 Hook,用于划区清扫
12
14
  * @returns 包含 requestZoneClean 和 setZoneClean 函数的对象
@@ -73,16 +75,15 @@ export const useZoneClean = () => {
73
75
 
74
76
  // 将业务参数转换为协议数据格式
75
77
  const num = zones.length;
78
+ const waterPayload = normalizeWaterPreferencePayload(params.cisterns, params.waterValues);
76
79
  const {
77
80
  suctions = new Array(num).fill(''),
78
- cisterns = new Array(num).fill(''),
79
81
  cleanCounts = new Array(num).fill(1),
80
82
  yMops = new Array(num).fill(-1),
81
- sweepMopModes = new Array(num).fill('only_sweep')
83
+ sweepMopModes = new Array(num).fill('only_sweep'),
84
+ routePreferences = new Array(num).fill('standard')
82
85
  } = params;
83
-
84
- // 构建符合 SetZoneCleanData 格式的数据
85
- const zoneCleanData = {
86
+ const zoneCleanData = _objectSpread(_objectSpread({
86
87
  zones: zones.map(_ref => {
87
88
  let {
88
89
  points,
@@ -96,41 +97,44 @@ export const useZoneClean = () => {
96
97
  };
97
98
  }),
98
99
  origin,
99
- suctions,
100
- cisterns,
100
+ suctions
101
+ }, waterPayload), {}, {
101
102
  cleanCounts,
102
103
  yMops,
103
- sweepMopModes
104
- };
104
+ sweepMopModes,
105
+ routePreferences
106
+ });
105
107
 
106
108
  // 使用 TypeBox Schema 进行参数验证
107
109
  const validatedData = validator.validate('set_zone_clean', zoneCleanData);
110
+ const polygons = zones.map(_ref2 => {
111
+ let {
112
+ points
113
+ } = _ref2;
114
+ return pointsToString(points, origin);
115
+ });
116
+ const names = zones.map(_ref3 => {
117
+ let {
118
+ name
119
+ } = _ref3;
120
+ return name || '';
121
+ });
122
+ const commonFields = _objectSpread(_objectSpread({
123
+ suctions: validatedData.suctions
124
+ }, waterPayload), {}, {
125
+ cleanCounts: validatedData.cleanCounts,
126
+ yMops: validatedData.yMops,
127
+ sweepMopModes: validatedData.sweepMopModes,
128
+ routePreferences: validatedData.routePreferences
129
+ });
108
130
  if (useMqtt) {
109
- // 将 zones 转换为 polygons 字符串格式(用于 MQTT 消息)
110
- const polygons = zones.map(_ref2 => {
111
- let {
112
- points
113
- } = _ref2;
114
- return pointsToString(points, origin);
115
- });
116
- const names = zones.map(_ref3 => {
117
- let {
118
- name
119
- } = _ref3;
120
- return name || '';
121
- });
122
- sendStructuredMessage(ZoneCleanEnum.set, {
123
- num: zones.length,
131
+ sendStructuredMessage(ZoneCleanEnum.set, _objectSpread(_objectSpread({
132
+ num,
124
133
  switchGo: true,
125
- polygons,
126
- suctions: validatedData.suctions,
127
- cisterns: validatedData.cisterns,
128
- cleanCounts: validatedData.cleanCounts,
129
- yMops: validatedData.yMops,
130
- sweepMopModes: validatedData.sweepMopModes,
134
+ polygons
135
+ }, commonFields), {}, {
131
136
  names
132
- }, resolve, error => reject(handleMqttError(error, 'Failed to set zone clean')), ZoneCleanEnum.query // 响应类型是 query,不是 set
133
- );
137
+ }), resolve, error => reject(handleMqttError(error, 'Failed to set zone clean')), ZoneCleanEnum.query);
134
138
  return;
135
139
  }
136
140
 
@@ -146,19 +150,7 @@ export const useZoneClean = () => {
146
150
  }))
147
151
  });
148
152
  devices.common.model.actions.command_trans.set(command);
149
- const polygons = zones.map(_ref4 => {
150
- let {
151
- points
152
- } = _ref4;
153
- return pointsToString(points, origin);
154
- });
155
- const names = zones.map(_ref5 => {
156
- let {
157
- name
158
- } = _ref5;
159
- return name || '';
160
- });
161
- resolve({
153
+ resolve(_objectSpread({
162
154
  success: true,
163
155
  errCode: 0,
164
156
  reqType: ZoneCleanEnum.query,
@@ -166,7 +158,7 @@ export const useZoneClean = () => {
166
158
  taskId: `${Date.now()}`,
167
159
  polygons,
168
160
  names
169
- });
161
+ }, commonFields));
170
162
  } catch (error) {
171
163
  reject(handleMqttError(error, 'Failed to set zone clean'));
172
164
  }
@@ -0,0 +1,20 @@
1
+ export type WaterPreferenceValue = string | number;
2
+ /**
3
+ * 将自定义水量 / 标准水量统一归一化为设备命令需要的数值。
4
+ * 优先使用 waterValue,其次回退到 cistern。
5
+ */
6
+ export declare const resolveWaterLevel: (waterValue?: WaterPreferenceValue, cistern?: WaterPreferenceValue, fallback?: number) => number;
7
+ export declare const hasPreferenceValue: (value?: WaterPreferenceValue | null) => boolean;
8
+ /**
9
+ * MQTT 水量相关字段是可选的。
10
+ * 当数组里全是空字符串时,认为该字段未设置,避免把空 cisterns/waterValues 发给设备。
11
+ */
12
+ export declare const normalizeOptionalPreferenceArray: <T extends WaterPreferenceValue>(values?: T[] | undefined) => T[] | undefined;
13
+ /**
14
+ * 自定义水量优先于旧 cistern 水量。
15
+ * 当某一项存在自定义水量时,同位置的 cistern 会被清空;最终空数组字段会被省略。
16
+ */
17
+ export declare const normalizeWaterPreferencePayload: (cisterns?: WaterPreferenceValue[], waterValues?: WaterPreferenceValue[]) => {
18
+ cisterns?: WaterPreferenceValue[] | undefined;
19
+ waterValues?: WaterPreferenceValue[] | undefined;
20
+ };
@@ -0,0 +1,70 @@
1
+ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
+ import "core-js/modules/esnext.iterator.constructor.js";
3
+ import "core-js/modules/esnext.iterator.some.js";
4
+ import { CISTERN_MAP } from '../constant';
5
+ /**
6
+ * 将自定义水量 / 标准水量统一归一化为设备命令需要的数值。
7
+ * 优先使用 waterValue,其次回退到 cistern。
8
+ */
9
+ export const resolveWaterLevel = function (waterValue, cistern) {
10
+ var _ref, _resolveValue;
11
+ let fallback = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : CISTERN_MAP.closed;
12
+ const resolveValue = value => {
13
+ if (typeof value === 'number' && Number.isFinite(value)) {
14
+ return value;
15
+ }
16
+ if (typeof value !== 'string') {
17
+ return undefined;
18
+ }
19
+ if (value in CISTERN_MAP) {
20
+ return CISTERN_MAP[value];
21
+ }
22
+ const parsed = Number(value);
23
+ return Number.isFinite(parsed) ? parsed : undefined;
24
+ };
25
+ return (_ref = (_resolveValue = resolveValue(waterValue)) !== null && _resolveValue !== void 0 ? _resolveValue : resolveValue(cistern)) !== null && _ref !== void 0 ? _ref : fallback;
26
+ };
27
+ export const hasPreferenceValue = value => value !== '' && value !== null && value !== undefined;
28
+
29
+ /**
30
+ * MQTT 水量相关字段是可选的。
31
+ * 当数组里全是空字符串时,认为该字段未设置,避免把空 cisterns/waterValues 发给设备。
32
+ */
33
+ export const normalizeOptionalPreferenceArray = values => {
34
+ if (!values) {
35
+ return undefined;
36
+ }
37
+ return values.some(hasPreferenceValue) ? values : undefined;
38
+ };
39
+
40
+ /**
41
+ * 自定义水量优先于旧 cistern 水量。
42
+ * 当某一项存在自定义水量时,同位置的 cistern 会被清空;最终空数组字段会被省略。
43
+ */
44
+ export const normalizeWaterPreferencePayload = (cisterns, waterValues) => {
45
+ var _cisterns$length, _waterValues$length;
46
+ const maxLength = Math.max((_cisterns$length = cisterns === null || cisterns === void 0 ? void 0 : cisterns.length) !== null && _cisterns$length !== void 0 ? _cisterns$length : 0, (_waterValues$length = waterValues === null || waterValues === void 0 ? void 0 : waterValues.length) !== null && _waterValues$length !== void 0 ? _waterValues$length : 0);
47
+ if (maxLength === 0) {
48
+ return {};
49
+ }
50
+ const normalizedCisterns = normalizeOptionalPreferenceArray(Array.from({
51
+ length: maxLength
52
+ }, (_, index) => {
53
+ var _cisterns$index;
54
+ if (hasPreferenceValue(waterValues === null || waterValues === void 0 ? void 0 : waterValues[index])) {
55
+ return '';
56
+ }
57
+ return (_cisterns$index = cisterns === null || cisterns === void 0 ? void 0 : cisterns[index]) !== null && _cisterns$index !== void 0 ? _cisterns$index : '';
58
+ }));
59
+ const normalizedWaterValues = normalizeOptionalPreferenceArray(Array.from({
60
+ length: maxLength
61
+ }, (_, index) => {
62
+ var _waterValues$index;
63
+ return (_waterValues$index = waterValues === null || waterValues === void 0 ? void 0 : waterValues[index]) !== null && _waterValues$index !== void 0 ? _waterValues$index : '';
64
+ }));
65
+ return _objectSpread(_objectSpread({}, normalizedCisterns ? {
66
+ cisterns: normalizedCisterns
67
+ } : {}), normalizedWaterValues ? {
68
+ waterValues: normalizedWaterValues
69
+ } : {});
70
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ray-js/robot-data-stream",
3
- "version": "0.0.15-beta.8",
3
+ "version": "0.0.16-beta.1",
4
4
  "description": "扫地机P2P数据流标准化组件",
5
5
  "main": "lib/index",
6
6
  "files": [
@@ -28,7 +28,9 @@
28
28
  "start:wechat": "ray start ./example -t wechat --verbose",
29
29
  "start:web": "ray start ./example -t web",
30
30
  "prepublishOnly": "yarn build",
31
- "release-it": "standard-version"
31
+ "release-it": "standard-version",
32
+ "docs:dev": "vitepress dev docs",
33
+ "docs:build": "vitepress build docs"
32
34
  },
33
35
  "peerDependencies": {
34
36
  "@ray-js/log4js": "^0.0.4",
@@ -53,14 +55,15 @@
53
55
  "@ray-js/log4js": "^0.0.4",
54
56
  "@ray-js/ray": "1.8.0-beta.14",
55
57
  "@ray-js/robot-protocol": "^1.0.1",
58
+ "@types/lodash-es": "^4.17.12",
56
59
  "core-js": "^3.19.1",
57
60
  "eslint-config-tuya-panel": "^0.4.2",
58
61
  "husky": "^1.2.0",
59
62
  "lint-staged": "^10.2.11",
60
63
  "patch-package": "^8.0.0",
61
- "@types/lodash-es": "^4.17.12",
62
64
  "prettier": "^3.8.0",
63
- "standard-version": "9.3.2"
65
+ "standard-version": "9.3.2",
66
+ "vitepress": "^1.6.4"
64
67
  },
65
68
  "husky": {
66
69
  "hooks": {