@ray-js/robot-data-stream 0.0.15-beta.9 → 0.0.16-beta.2
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/lib/constant.d.ts +1 -0
- package/lib/constant.js +11 -0
- package/lib/mqtt/hooks/useStructuredMessage.d.ts +0 -3
- package/lib/mqtt/hooks/useStructuredMessage.js +148 -116
- package/lib/mqtt/type/fun.d.ts +24 -9
- package/lib/mqtt/type/fun.js +2 -1
- package/lib/mqtt/type/index.d.ts +4 -1
- package/lib/mqtt/type/protocols/base.d.ts +4 -1
- package/lib/mqtt/type/protocols/base.js +9 -3
- package/lib/mqtt/type/protocols/carpetCleanProtocol.d.ts +2 -2
- package/lib/mqtt/type/protocols/carpetCleanProtocol.js +2 -2
- package/lib/mqtt/type/protocols/carpetProtocol.d.ts +5 -5
- package/lib/mqtt/type/protocols/carpetProtocol.js +7 -7
- package/lib/mqtt/type/protocols/roomPropertyProtocol.d.ts +8 -2
- package/lib/mqtt/type/protocols/roomPropertyProtocol.js +26 -5
- package/lib/mqtt/type/protocols/scheduleProtocol.d.ts +12 -3
- package/lib/mqtt/type/protocols/scheduleProtocol.js +17 -0
- package/lib/mqtt/type/protocols/selectRoomCleanProtocol.d.ts +6 -2
- package/lib/mqtt/type/protocols/selectRoomCleanProtocol.js +12 -4
- package/lib/mqtt/type/protocols/spotCleanProtocol.d.ts +8 -2
- package/lib/mqtt/type/protocols/spotCleanProtocol.js +24 -2
- package/lib/mqtt/type/protocols/wifiMapProtocol.d.ts +1 -0
- package/lib/mqtt/type/protocols/wifiMapProtocol.js +2 -1
- package/lib/mqtt/type/protocols/zoneCleanProtocol.d.ts +7 -2
- package/lib/mqtt/type/protocols/zoneCleanProtocol.js +31 -4
- package/lib/mqtt/useRoomProperty.js +8 -4
- package/lib/mqtt/useSchedule.js +25 -7
- package/lib/mqtt/useSelectRoomClean.js +36 -13
- package/lib/mqtt/useSpotClean.js +22 -10
- package/lib/mqtt/useWifiMap.js +4 -2
- package/lib/mqtt/useZoneClean.js +39 -45
- package/lib/mqtt/waterPreference.d.ts +20 -0
- package/lib/mqtt/waterPreference.js +70 -0
- 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$
|
|
50
|
+
var _data$num, _data$suctions, _data$cleanCounts, _data$yMops, _data$sweepMopModes, _data$names;
|
|
49
51
|
if (!useMqtt) {
|
|
50
52
|
reject(new Error('useMqtt is not used'));
|
|
51
53
|
return;
|
|
@@ -56,18 +58,20 @@ export const useRoomProperty = () => {
|
|
|
56
58
|
ids
|
|
57
59
|
} = data;
|
|
58
60
|
const len = ids.length;
|
|
59
|
-
const sendData = {
|
|
61
|
+
const sendData = _objectSpread(_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
71
|
orders: data.orders
|
|
70
|
-
}
|
|
72
|
+
}, data.routePreferences && {
|
|
73
|
+
routePreferences: data.routePreferences
|
|
74
|
+
}), normalizeWaterPreferencePayload(data.cisterns, data.waterValues));
|
|
71
75
|
|
|
72
76
|
// 使用 TypeBox Schema 进行参数验证(包含自定义验证逻辑)
|
|
73
77
|
const validatedData = validator.validate('set_room_property', sendData);
|
package/lib/mqtt/useSchedule.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
2
|
+
import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
|
|
3
|
+
const _excluded = ["routePreferences"];
|
|
1
4
|
import "core-js/modules/esnext.iterator.map.js";
|
|
2
5
|
// 定时
|
|
3
6
|
import { encodeDeviceTimer0x30 } from '@ray-js/robot-protocol';
|
|
4
7
|
import { useContext } from 'react';
|
|
5
|
-
import {
|
|
8
|
+
import { CLEAN_MODE_MAP, SUCTION_MAP, ROUTE_PREFERENCE_MAP } from '../constant';
|
|
9
|
+
import { normalizeWaterPreferencePayload, resolveWaterLevel } from './waterPreference';
|
|
6
10
|
import { handleMqttError, useStructuredMessage } from './hooks/useStructuredMessage';
|
|
7
11
|
import { SingletonContext } from './mqttProvider';
|
|
8
12
|
import { ScheduleEnum } from './type';
|
|
@@ -53,8 +57,19 @@ export const useSchedule = () => {
|
|
|
53
57
|
try {
|
|
54
58
|
// 使用 TypeBox Schema 进行参数验证
|
|
55
59
|
const validatedData = validator.validate('set_schedule', message);
|
|
60
|
+
const list = validatedData.list.map(item => {
|
|
61
|
+
const {
|
|
62
|
+
routePreferences
|
|
63
|
+
} = item,
|
|
64
|
+
rest = _objectWithoutProperties(item, _excluded);
|
|
65
|
+
return _objectSpread(_objectSpread(_objectSpread({}, rest), normalizeWaterPreferencePayload(item.cisterns, item.waterValues)), routePreferences && {
|
|
66
|
+
routePreferences
|
|
67
|
+
});
|
|
68
|
+
});
|
|
56
69
|
if (useMqtt) {
|
|
57
|
-
sendStructuredMessage(ScheduleEnum.set,
|
|
70
|
+
sendStructuredMessage(ScheduleEnum.set, _objectSpread(_objectSpread({}, validatedData), {}, {
|
|
71
|
+
list
|
|
72
|
+
}), resolve, error => reject(handleMqttError(error, 'Failed to set schedule')), ScheduleEnum.query // 响应类型是 query,不是 set
|
|
58
73
|
);
|
|
59
74
|
return;
|
|
60
75
|
}
|
|
@@ -63,7 +78,7 @@ export const useSchedule = () => {
|
|
|
63
78
|
const command = encodeDeviceTimer0x30({
|
|
64
79
|
version: commandVersion,
|
|
65
80
|
number: validatedData.num,
|
|
66
|
-
list:
|
|
81
|
+
list: list.map(_ref => {
|
|
67
82
|
let {
|
|
68
83
|
active,
|
|
69
84
|
suctions,
|
|
@@ -72,13 +87,15 @@ export const useSchedule = () => {
|
|
|
72
87
|
cleanCounts,
|
|
73
88
|
cycle,
|
|
74
89
|
cisterns,
|
|
75
|
-
|
|
90
|
+
waterValues,
|
|
91
|
+
time,
|
|
92
|
+
routePreferences
|
|
76
93
|
} = _ref;
|
|
77
94
|
return {
|
|
78
95
|
effectiveness: active,
|
|
79
96
|
cleanMode: CLEAN_MODE_MAP[(sweepMopModes === null || sweepMopModes === void 0 ? void 0 : sweepMopModes[0]) || ''],
|
|
80
97
|
fanLevel: SUCTION_MAP[(suctions === null || suctions === void 0 ? void 0 : suctions[0]) || ''],
|
|
81
|
-
waterLevel:
|
|
98
|
+
waterLevel: resolveWaterLevel(waterValues === null || waterValues === void 0 ? void 0 : waterValues[0], cisterns === null || cisterns === void 0 ? void 0 : cisterns[0]),
|
|
82
99
|
time: {
|
|
83
100
|
hour: time[0],
|
|
84
101
|
minute: time[1]
|
|
@@ -86,7 +103,8 @@ export const useSchedule = () => {
|
|
|
86
103
|
week: cycle,
|
|
87
104
|
sweepCount: (cleanCounts === null || cleanCounts === void 0 ? void 0 : cleanCounts[0]) || 1,
|
|
88
105
|
roomIds: ids || [],
|
|
89
|
-
roomNum: (ids === null || ids === void 0 ? void 0 : ids.length) || 0
|
|
106
|
+
roomNum: (ids === null || ids === void 0 ? void 0 : ids.length) || 0,
|
|
107
|
+
routePreference: ROUTE_PREFERENCE_MAP[(routePreferences === null || routePreferences === void 0 ? void 0 : routePreferences[0]) || 'standard']
|
|
90
108
|
};
|
|
91
109
|
})
|
|
92
110
|
});
|
|
@@ -97,7 +115,7 @@ export const useSchedule = () => {
|
|
|
97
115
|
reqType: ScheduleEnum.query,
|
|
98
116
|
version: commandVersion,
|
|
99
117
|
taskId: `${Date.now()}`,
|
|
100
|
-
list
|
|
118
|
+
list,
|
|
101
119
|
num: validatedData.num
|
|
102
120
|
});
|
|
103
121
|
} catch (error) {
|
|
@@ -1,6 +1,8 @@
|
|
|
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";
|
|
5
|
+
import "core-js/modules/esnext.iterator.some.js";
|
|
4
6
|
// 选区清扫
|
|
5
7
|
import { encodeRoomClean0x14, requestRoomClean0x15 } from '@ray-js/robot-protocol';
|
|
6
8
|
import { useContext } from 'react';
|
|
@@ -8,6 +10,7 @@ import { handleMqttError, useStructuredMessage } from './hooks/useStructuredMess
|
|
|
8
10
|
import { SingletonContext } from './mqttProvider';
|
|
9
11
|
import { RoomCleanSetEnum } from './type';
|
|
10
12
|
import { validator } from './type/fun';
|
|
13
|
+
import { normalizeWaterPreferencePayload } from './waterPreference';
|
|
11
14
|
/**
|
|
12
15
|
* 自定义 Hook,用于选区清扫
|
|
13
16
|
* @returns 包含 requestSelectRoomClean 和 setRoomClean 函数的对象
|
|
@@ -59,9 +62,11 @@ export const useSelectRoomClean = () => {
|
|
|
59
62
|
ids: [],
|
|
60
63
|
suctions: [],
|
|
61
64
|
cisterns: [],
|
|
65
|
+
waterValues: [],
|
|
62
66
|
cleanCounts: [],
|
|
63
67
|
yMops: [],
|
|
64
|
-
sweepMopModes: []
|
|
68
|
+
sweepMopModes: [],
|
|
69
|
+
routePreferences: []
|
|
65
70
|
});
|
|
66
71
|
} catch (error) {
|
|
67
72
|
reject(handleMqttError(error, 'Failed to request select room clean'));
|
|
@@ -77,28 +82,37 @@ export const useSelectRoomClean = () => {
|
|
|
77
82
|
if (useMqtt) {
|
|
78
83
|
const ids = [];
|
|
79
84
|
const suctions = [];
|
|
80
|
-
const cisterns = [];
|
|
81
85
|
const cleanCounts = [];
|
|
82
86
|
const yMops = [];
|
|
83
87
|
const sweepMopModes = [];
|
|
88
|
+
const prefs = rooms.map(room => room.routePreference);
|
|
84
89
|
rooms.forEach(room => {
|
|
85
90
|
var _room$suction, _room$cleanTimes, _room$yMop, _room$sweepMopMode;
|
|
86
91
|
ids.push(room.roomId);
|
|
87
92
|
suctions.push((_room$suction = room.suction) !== null && _room$suction !== void 0 ? _room$suction : '');
|
|
88
|
-
cisterns.push(room.cistern);
|
|
89
93
|
cleanCounts.push((_room$cleanTimes = room.cleanTimes) !== null && _room$cleanTimes !== void 0 ? _room$cleanTimes : 1);
|
|
90
94
|
yMops.push((_room$yMop = room.yMop) !== null && _room$yMop !== void 0 ? _room$yMop : -1);
|
|
91
95
|
sweepMopModes.push((_room$sweepMopMode = room.sweepMopMode) !== null && _room$sweepMopMode !== void 0 ? _room$sweepMopMode : 'only_sweep');
|
|
92
96
|
});
|
|
93
|
-
|
|
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(_objectSpread({
|
|
94
105
|
ids,
|
|
95
|
-
suctions
|
|
96
|
-
|
|
106
|
+
suctions
|
|
107
|
+
}, waterPayload), {}, {
|
|
97
108
|
cleanCounts,
|
|
98
109
|
yMops,
|
|
99
|
-
sweepMopModes
|
|
110
|
+
sweepMopModes
|
|
111
|
+
}, prefs.some(Boolean) && {
|
|
112
|
+
routePreferences: prefs.map(p => p !== null && p !== void 0 ? p : 'standard')
|
|
113
|
+
}), {}, {
|
|
100
114
|
num: rooms.length
|
|
101
|
-
}, resolve, error => reject(handleMqttError(error, 'Failed to set room clean')), RoomCleanSetEnum.query // 响应类型是 query,不是 set
|
|
115
|
+
}), resolve, error => reject(handleMqttError(error, 'Failed to set room clean')), RoomCleanSetEnum.query // 响应类型是 query,不是 set
|
|
102
116
|
);
|
|
103
117
|
return;
|
|
104
118
|
}
|
|
@@ -115,7 +129,13 @@ export const useSelectRoomClean = () => {
|
|
|
115
129
|
var _room$suction2;
|
|
116
130
|
return (_room$suction2 = room.suction) !== null && _room$suction2 !== void 0 ? _room$suction2 : '';
|
|
117
131
|
});
|
|
118
|
-
const
|
|
132
|
+
const waterPayload = normalizeWaterPreferencePayload(rooms.map(room => {
|
|
133
|
+
var _room$cistern2;
|
|
134
|
+
return (_room$cistern2 = room.cistern) !== null && _room$cistern2 !== void 0 ? _room$cistern2 : '';
|
|
135
|
+
}), rooms.map(room => {
|
|
136
|
+
var _room$waterValue2;
|
|
137
|
+
return (_room$waterValue2 = room.waterValue) !== null && _room$waterValue2 !== void 0 ? _room$waterValue2 : '';
|
|
138
|
+
}));
|
|
119
139
|
const cleanCounts = rooms.map(room => {
|
|
120
140
|
var _room$cleanTimes2;
|
|
121
141
|
return (_room$cleanTimes2 = room.cleanTimes) !== null && _room$cleanTimes2 !== void 0 ? _room$cleanTimes2 : 1;
|
|
@@ -128,19 +148,22 @@ export const useSelectRoomClean = () => {
|
|
|
128
148
|
var _room$sweepMopMode2;
|
|
129
149
|
return (_room$sweepMopMode2 = room.sweepMopMode) !== null && _room$sweepMopMode2 !== void 0 ? _room$sweepMopMode2 : 'only_sweep';
|
|
130
150
|
});
|
|
131
|
-
|
|
151
|
+
const prefs = rooms.map(room => room.routePreference);
|
|
152
|
+
resolve(_objectSpread(_objectSpread({
|
|
132
153
|
success: true,
|
|
133
154
|
errCode: 0,
|
|
134
155
|
reqType: RoomCleanSetEnum.query,
|
|
135
156
|
version: commandVersion,
|
|
136
157
|
taskId: `${Date.now()}`,
|
|
137
158
|
ids,
|
|
138
|
-
suctions
|
|
139
|
-
|
|
159
|
+
suctions
|
|
160
|
+
}, waterPayload), {}, {
|
|
140
161
|
cleanCounts,
|
|
141
162
|
yMops,
|
|
142
163
|
sweepMopModes
|
|
143
|
-
})
|
|
164
|
+
}, prefs.some(Boolean) && {
|
|
165
|
+
routePreferences: prefs.map(p => p !== null && p !== void 0 ? p : 'standard')
|
|
166
|
+
}));
|
|
144
167
|
} catch (error) {
|
|
145
168
|
reject(handleMqttError(error, 'Failed to set room clean'));
|
|
146
169
|
}
|
package/lib/mqtt/useSpotClean.js
CHANGED
|
@@ -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,31 @@ 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,
|
|
71
|
+
names
|
|
68
72
|
} = validatedData;
|
|
69
73
|
if (useMqtt) {
|
|
70
|
-
sendStructuredMessage(SpotCleanEnum.set, {
|
|
74
|
+
sendStructuredMessage(SpotCleanEnum.set, _objectSpread(_objectSpread(_objectSpread({
|
|
71
75
|
num,
|
|
72
76
|
polygons: spots.map(spot => pointsToString([spot], origin)),
|
|
73
|
-
suctions
|
|
74
|
-
|
|
77
|
+
suctions
|
|
78
|
+
}, waterPayload), {}, {
|
|
75
79
|
cleanCounts,
|
|
76
80
|
yMops,
|
|
77
81
|
sweepMopModes
|
|
78
|
-
},
|
|
82
|
+
}, routePreferences && {
|
|
83
|
+
routePreferences
|
|
84
|
+
}), names && {
|
|
85
|
+
names
|
|
86
|
+
}), resolve, error => reject(handleMqttError(error, 'Failed to set spot clean')), SpotCleanEnum.query // 响应类型是 query,不是 set
|
|
79
87
|
);
|
|
80
88
|
return;
|
|
81
89
|
}
|
|
@@ -87,19 +95,23 @@ export const useSpotClean = () => {
|
|
|
87
95
|
point: spots[0]
|
|
88
96
|
});
|
|
89
97
|
devices.common.model.actions.command_trans.set(command);
|
|
90
|
-
resolve({
|
|
98
|
+
resolve(_objectSpread(_objectSpread(_objectSpread({
|
|
91
99
|
success: true,
|
|
92
100
|
errCode: 0,
|
|
93
101
|
reqType: SpotCleanEnum.query,
|
|
94
102
|
version: commandVersion,
|
|
95
103
|
taskId: `${Date.now()}`,
|
|
96
104
|
polygons: spots.map(spot => pointsToString([spot], origin)),
|
|
97
|
-
suctions
|
|
98
|
-
|
|
105
|
+
suctions
|
|
106
|
+
}, waterPayload), {}, {
|
|
99
107
|
cleanCounts,
|
|
100
108
|
yMops,
|
|
101
109
|
sweepMopModes
|
|
102
|
-
}
|
|
110
|
+
}, routePreferences && {
|
|
111
|
+
routePreferences
|
|
112
|
+
}), names && {
|
|
113
|
+
names
|
|
114
|
+
}));
|
|
103
115
|
} catch (error) {
|
|
104
116
|
reject(handleMqttError(error, 'Failed to set spot clean'));
|
|
105
117
|
}
|
package/lib/mqtt/useWifiMap.js
CHANGED
|
@@ -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 进行参数验证
|
package/lib/mqtt/useZoneClean.js
CHANGED
|
@@ -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
|
|
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,46 @@ export const useZoneClean = () => {
|
|
|
96
97
|
};
|
|
97
98
|
}),
|
|
98
99
|
origin,
|
|
99
|
-
suctions
|
|
100
|
-
|
|
100
|
+
suctions
|
|
101
|
+
}, waterPayload), {}, {
|
|
101
102
|
cleanCounts,
|
|
102
103
|
yMops,
|
|
103
104
|
sweepMopModes
|
|
104
|
-
}
|
|
105
|
+
}, routePreferences && {
|
|
106
|
+
routePreferences
|
|
107
|
+
});
|
|
105
108
|
|
|
106
109
|
// 使用 TypeBox Schema 进行参数验证
|
|
107
110
|
const validatedData = validator.validate('set_zone_clean', zoneCleanData);
|
|
111
|
+
const polygons = zones.map(_ref2 => {
|
|
112
|
+
let {
|
|
113
|
+
points
|
|
114
|
+
} = _ref2;
|
|
115
|
+
return pointsToString(points, origin);
|
|
116
|
+
});
|
|
117
|
+
const names = zones.map(_ref3 => {
|
|
118
|
+
let {
|
|
119
|
+
name
|
|
120
|
+
} = _ref3;
|
|
121
|
+
return name || '';
|
|
122
|
+
});
|
|
123
|
+
const commonFields = _objectSpread(_objectSpread({
|
|
124
|
+
suctions: validatedData.suctions
|
|
125
|
+
}, waterPayload), {}, {
|
|
126
|
+
cleanCounts: validatedData.cleanCounts,
|
|
127
|
+
yMops: validatedData.yMops,
|
|
128
|
+
sweepMopModes: validatedData.sweepMopModes
|
|
129
|
+
}, validatedData.routePreferences && {
|
|
130
|
+
routePreferences: validatedData.routePreferences
|
|
131
|
+
});
|
|
108
132
|
if (useMqtt) {
|
|
109
|
-
|
|
110
|
-
|
|
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,
|
|
133
|
+
sendStructuredMessage(ZoneCleanEnum.set, _objectSpread(_objectSpread({
|
|
134
|
+
num,
|
|
124
135
|
switchGo: true,
|
|
125
|
-
polygons
|
|
126
|
-
|
|
127
|
-
cisterns: validatedData.cisterns,
|
|
128
|
-
cleanCounts: validatedData.cleanCounts,
|
|
129
|
-
yMops: validatedData.yMops,
|
|
130
|
-
sweepMopModes: validatedData.sweepMopModes,
|
|
136
|
+
polygons
|
|
137
|
+
}, commonFields), {}, {
|
|
131
138
|
names
|
|
132
|
-
}, resolve, error => reject(handleMqttError(error, 'Failed to set zone clean')), ZoneCleanEnum.query
|
|
133
|
-
);
|
|
139
|
+
}), resolve, error => reject(handleMqttError(error, 'Failed to set zone clean')), ZoneCleanEnum.query);
|
|
134
140
|
return;
|
|
135
141
|
}
|
|
136
142
|
|
|
@@ -146,19 +152,7 @@ export const useZoneClean = () => {
|
|
|
146
152
|
}))
|
|
147
153
|
});
|
|
148
154
|
devices.common.model.actions.command_trans.set(command);
|
|
149
|
-
|
|
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({
|
|
155
|
+
resolve(_objectSpread({
|
|
162
156
|
success: true,
|
|
163
157
|
errCode: 0,
|
|
164
158
|
reqType: ZoneCleanEnum.query,
|
|
@@ -166,7 +160,7 @@ export const useZoneClean = () => {
|
|
|
166
160
|
taskId: `${Date.now()}`,
|
|
167
161
|
polygons,
|
|
168
162
|
names
|
|
169
|
-
});
|
|
163
|
+
}, commonFields));
|
|
170
164
|
} catch (error) {
|
|
171
165
|
reject(handleMqttError(error, 'Failed to set zone clean'));
|
|
172
166
|
}
|
|
@@ -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
|
+
};
|