@ray-js/lamp-schedule-core 1.0.4-beta-4 → 1.0.4-beta-6

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.
@@ -176,8 +176,9 @@ describe('transform', () => {
176
176
  expect(result.data).toEqual({
177
177
  status: true,
178
178
  weeks: [1, 0, 0, 0, 0, 0, 0],
179
- startTime: '22:10',
180
- endTime: '22:30'
179
+ startTime: '22:20',
180
+ // 开始入睡时间 = hour:minute
181
+ endTime: '22:30' // 淡出至关灯时间 = hour:minute + step*5分钟 = 22:20 + 10 = 22:30
181
182
  });
182
183
  expect(result.id).toMatch(/^sleep_/);
183
184
  });
@@ -31,6 +31,9 @@ export declare const wakeUpDataToScheduleList: <T extends TWakeUpNode>(data: T[]
31
31
  * 入睡数据转换成适合冲突判断的日程对象
32
32
  * @param data TSleepNode
33
33
  * @returns Schedule
34
+ * 入睡任务时间段为开始入睡到淡出至关灯的时间段
35
+ * startTime = hour:minute(开始入睡时间)
36
+ * endTime = hour:minute + step*5分钟(淡出至关灯的时间)
34
37
  */
35
38
  export declare const sleepNodeToSchedule: <T extends TSleepNode>(data: T) => Schedule;
36
39
  /**
@@ -86,10 +86,13 @@ export const wakeUpDataToScheduleList = data => {
86
86
  * 入睡数据转换成适合冲突判断的日程对象
87
87
  * @param data TSleepNode
88
88
  * @returns Schedule
89
+ * 入睡任务时间段为开始入睡到淡出至关灯的时间段
90
+ * startTime = hour:minute(开始入睡时间)
91
+ * endTime = hour:minute + step*5分钟(淡出至关灯的时间)
89
92
  */
90
93
  export const sleepNodeToSchedule = data => {
91
- const startTime = getPreOffsetTimeByHourMins(data.hour, data.minute, data.step * 5);
92
- const endTime = data.time || getTimeFormatStrByHourMins(data.hour, data.minute);
94
+ const startTime = getTimeFormatStrByHourMins(data.hour, data.minute);
95
+ const endTime = getBackwardOffsetTimeByHourMins(data.hour, data.minute, (data.step || 0) * 5);
93
96
  const _data = {
94
97
  status: data.onOff,
95
98
  weeks: data.loops.split('').map(item => Number(item)),
@@ -10,6 +10,7 @@ const onGroupDpDataChangeEventMock = jest.fn();
10
10
  const offDpDataChangeMock = jest.fn();
11
11
  const offGroupDpDataChangeEventMock = jest.fn();
12
12
  const getDeviceInfoMock = jest.fn();
13
+ const getGroupInfoMock = jest.fn();
13
14
  const getTimerListWithFlushMock = jest.fn();
14
15
  const initDpStateMock = jest.fn();
15
16
  jest.mock('../../context/timer/context', () => ({
@@ -48,8 +49,8 @@ jest.mock('@ray-js/ray', () => ({
48
49
  getDeviceInfo: function () {
49
50
  return getDeviceInfoMock(...arguments);
50
51
  },
51
- getGroupDpsInfos: function () {
52
- return getGroupDpsInfosMock(...arguments);
52
+ getGroupInfo: function () {
53
+ return getGroupInfoMock(...arguments);
53
54
  },
54
55
  registerDeviceListListener: function () {
55
56
  return registerDeviceListListenerMock(...arguments);
@@ -121,8 +122,15 @@ describe('useCommonSupport suite', () => {
121
122
  }
122
123
  });
123
124
  });
124
- getGroupDpsInfosMock.mockResolvedValue({
125
- 1: true
125
+ getGroupInfoMock.mockImplementation(_ref4 => {
126
+ let {
127
+ success
128
+ } = _ref4;
129
+ return success === null || success === void 0 ? void 0 : success({
130
+ dps: {
131
+ 1: true
132
+ }
133
+ });
126
134
  });
127
135
  });
128
136
  it('initializes device support and sets ready state', async () => {
@@ -5,7 +5,7 @@ import "core-js/modules/esnext.iterator.every.js";
5
5
  import "core-js/modules/esnext.iterator.for-each.js";
6
6
  import "core-js/modules/esnext.iterator.some.js";
7
7
  import { useEffect, useMemo, useRef, useState } from 'react';
8
- import { getDeviceInfo, getGroupDpsInfos, onDpDataChange, onGroupDpDataChangeEvent, registerDeviceListListener, registerGroupChange, offDpDataChange, offGroupDpDataChangeEvent } from '@ray-js/ray';
8
+ import { getDeviceInfo, getGroupInfo, onDpDataChange, onGroupDpDataChangeEvent, registerDeviceListListener, registerGroupChange, offDpDataChange, offGroupDpDataChangeEvent } from '@ray-js/ray';
9
9
  import { Support } from '../utils/ScheduleSupport';
10
10
  import { useTimerContext } from '../context/timer/context';
11
11
  import { scheduleLogger, scheduleLogger as ScheduleLogger } from '../utils/ScheduleLogger';
@@ -161,23 +161,29 @@ export const useScheduleInit = props => {
161
161
  const promiseList = Promise.all([initStorage(props.devId, props.groupId), support.init()]);
162
162
  promiseList.then(() => {
163
163
  if (props.groupId) {
164
- // 获取群组 dp 数据
165
- getGroupDpsInfos(props.groupId).then(res => {
166
- scheduleLogger.debug('getGroupDpsInfos res', res);
167
- res && Object.keys(res).length && initDpState(res);
168
- supportIns = {
169
- isReady: true,
170
- support
171
- };
172
- emitter.emit('initDone');
173
- _isInit = true;
174
- ScheduleLogger.debug('useSupport: support init success', true);
175
- setScheduleState({
176
- isReady: true
177
- });
178
- }).catch(err => {
179
- scheduleLogger.error('Failed to get group info groupId:', props.groupId);
180
- scheduleLogger.error('Failed to get group info err:', err);
164
+ getGroupInfo({
165
+ groupId: props.groupId,
166
+ success: res => {
167
+ const dpMap = {};
168
+ Object.keys(res.dps).forEach(dpId => {
169
+ const dpCode = getDpCodeByDpId(dpId);
170
+ dpMap[dpCode] = res.dps[dpId];
171
+ });
172
+ dpMap && Object.keys(dpMap).length && initDpState(dpMap);
173
+ supportIns = {
174
+ isReady: true,
175
+ support
176
+ };
177
+ emitter.emit('initDone');
178
+ _isInit = true;
179
+ ScheduleLogger.debug('useSupport: support init success', true);
180
+ setScheduleState({
181
+ isReady: true
182
+ });
183
+ },
184
+ fail: err => {
185
+ scheduleLogger.error('Failed to get group info groupId:', props.groupId, err);
186
+ }
181
187
  });
182
188
  } else {
183
189
  // 获取单设备 dp 数据
@@ -237,7 +243,13 @@ export const isInitFn = () => {
237
243
  };
238
244
  export const useInit = () => {
239
245
  const [isInit, setIsInit] = useState(_isInit);
246
+ const initCheckedRef = useRef(false);
240
247
  useEffect(() => {
248
+ // 如果初始化已经完成,立即更新状态(只检查一次)
249
+ if (!initCheckedRef.current && _isInit) {
250
+ initCheckedRef.current = true;
251
+ setIsInit(true);
252
+ }
241
253
  const callback = () => {
242
254
  scheduleLogger.info('useInit: initDone');
243
255
  setIsInit(true);
@@ -247,7 +259,7 @@ export const useInit = () => {
247
259
  emitter.off('initDone', callback);
248
260
  };
249
261
  }, []);
250
- return isInit || _isInit;
262
+ return isInit;
251
263
  };
252
264
 
253
265
  /**
@@ -1,4 +1,4 @@
1
- import { useMemo } from 'react';
1
+ import { useCallback, useMemo } from 'react';
2
2
  import { useBaseLightDp } from './useBaseLightDp';
3
3
  import { scheduleDpCodes } from '../config/dpCodes';
4
4
  import { getCycleParser } from '../dpParser/cycle';
@@ -9,13 +9,17 @@ export function useCycleDp() {
9
9
  updateDp
10
10
  } = useBaseLightDp(dpCode);
11
11
  const cycleParser = getCycleParser();
12
+ const _updateDp = useCallback(dpData => {
13
+ updateDp(cycleParser.formatter(dpData));
14
+ }, [cycleParser]);
12
15
  const _dpValue = useMemo(() => {
16
+ if (dpValue === null || dpValue === undefined) {
17
+ return cycleParser.defaultValue;
18
+ }
13
19
  return cycleParser.parser(dpValue);
14
- }, [dpValue]);
20
+ }, [dpValue, cycleParser]);
15
21
  return {
16
22
  dpValue: _dpValue,
17
- updateDp: dpData => {
18
- updateDp(cycleParser.formatter(dpData));
19
- }
23
+ updateDp: _updateDp
20
24
  };
21
25
  }
@@ -1,4 +1,4 @@
1
- import { useMemo } from 'react';
1
+ import { useCallback, useMemo } from 'react';
2
2
  import { useBaseLightDp } from './useBaseLightDp';
3
3
  import { scheduleDpCodes } from '../config/dpCodes';
4
4
  import { getRandomParser } from '../dpParser/random';
@@ -9,13 +9,17 @@ export function useRandomDp() {
9
9
  updateDp
10
10
  } = useBaseLightDp(dpCode);
11
11
  const randomParser = getRandomParser();
12
+ const _updateDp = useCallback(dpData => {
13
+ updateDp(randomParser.formatter(dpData));
14
+ }, [randomParser]);
12
15
  const _dpValue = useMemo(() => {
16
+ if (dpValue === null || dpValue === undefined) {
17
+ return randomParser.defaultValue;
18
+ }
13
19
  return randomParser.parser(dpValue);
14
- }, [dpValue]);
20
+ }, [dpValue, randomParser]);
15
21
  return {
16
22
  dpValue: _dpValue,
17
- updateDp: dpData => {
18
- updateDp(randomParser.formatter(dpData));
19
- }
23
+ updateDp: _updateDp
20
24
  };
21
25
  }
@@ -1,6 +1,5 @@
1
1
  import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
2
  import "core-js/modules/esnext.iterator.constructor.js";
3
- import "core-js/modules/esnext.iterator.every.js";
4
3
  import "core-js/modules/esnext.iterator.find.js";
5
4
  import "core-js/modules/esnext.iterator.for-each.js";
6
5
  /* eslint-disable no-bitwise */
@@ -96,24 +95,42 @@ export class Support {
96
95
  return new Promise((resolve, reject) => {
97
96
  getGroupInfo({
98
97
  groupId,
99
- success: res => {
100
- var _res$deviceList;
101
- this.groupDevInfo = res;
98
+ success: groupRes => {
99
+ this.groupDevInfo = groupRes || {};
102
100
  ScheduleLogger.debug('getGroupInfo groupId: ', groupId);
103
- ScheduleLogger.debug('getGroupInfo success1: ', res);
104
- setScheduleCache(DEV_INFO_KEY, res);
105
- // 群组中为空
106
- groupId && (devIdOrGroupIdCache === null || devIdOrGroupIdCache === void 0 ? void 0 : devIdOrGroupIdCache.set('', groupId));
107
- const dpMap = {};
108
- Object.keys(res.dps).forEach(dpId => {
109
- const dpCode = getDpCodeByDpId(dpId);
110
- dpCode && setDpState(dpCode, res.dps[dpId]);
101
+ ScheduleLogger.debug('getGroupInfo success1: ', groupRes);
102
+ const {
103
+ deviceList = []
104
+ } = groupRes || {};
105
+ const firstDevice = deviceList === null || deviceList === void 0 ? void 0 : deviceList[0];
106
+ getDeviceInfo({
107
+ deviceId: firstDevice === null || firstDevice === void 0 ? void 0 : firstDevice.devId,
108
+ success: deviceInfoRes => {
109
+ var _res$deviceList;
110
+ // 从 deviceInfoRes 中筛选出 groupRes 中不存在的数据,合并到 res
111
+ const filteredDeviceInfo = {};
112
+ const _deviceInfo = _objectSpread(_objectSpread({}, groupRes), deviceInfoRes);
113
+ Object.keys(_deviceInfo).forEach(key => {
114
+ if (!(key in groupRes)) {
115
+ filteredDeviceInfo[key] = deviceInfoRes[key];
116
+ }
117
+ });
118
+ const res = _objectSpread(_objectSpread({}, groupRes), filteredDeviceInfo);
119
+ setScheduleCache(DEV_INFO_KEY, res);
120
+ // 群组中为空
121
+ groupId && (devIdOrGroupIdCache === null || devIdOrGroupIdCache === void 0 ? void 0 : devIdOrGroupIdCache.set('', groupId));
122
+ const dpMap = {};
123
+ Object.keys(res.dps).forEach(dpId => {
124
+ const dpCode = getDpCodeByDpId(dpId);
125
+ dpCode && setDpState(dpCode, res.dps[dpId]);
126
+ });
127
+ Object.keys(dpMap).length && initDpState(dpMap);
128
+ const deviceSchema = (_res$deviceList = res.deviceList) === null || _res$deviceList === void 0 || (_res$deviceList = _res$deviceList[0]) === null || _res$deviceList === void 0 ? void 0 : _res$deviceList.schema;
129
+ // 融合 deviceSchema 和 groupSchema 数据,优先使用 groupSchema
130
+ res.schema = [...(res.schema || []), ...(deviceSchema || [])];
131
+ resolve(true);
132
+ }
111
133
  });
112
- Object.keys(dpMap).length && initDpState(dpMap);
113
- const deviceSchema = (_res$deviceList = res.deviceList) === null || _res$deviceList === void 0 || (_res$deviceList = _res$deviceList[0]) === null || _res$deviceList === void 0 ? void 0 : _res$deviceList.schema;
114
- // 融合 deviceSchema 和 groupSchema 数据,优先使用 groupSchema
115
- res.schema = [...(res.schema || []), ...(deviceSchema || [])];
116
- resolve(true);
117
134
  },
118
135
  fail: err => {
119
136
  this.groupDevInfo = {};
@@ -213,31 +230,27 @@ export class Support {
213
230
  /**
214
231
  * @description 判断是否支持云端定时
215
232
  */
216
- isSupportCloudTimer = devInfo => {
217
- var _this$devInfo2;
218
- this.devInfo = devInfo !== null && devInfo !== void 0 ? devInfo : this.getCachedDevInfo();
219
- if (!this.devInfo) {
220
- return false;
221
- }
222
- // 群组设备需要从设备列表里面判断所有设备都支持定时才会显示
223
- if (this.devInfo.groupId) {
233
+ isSupportCloudTimer = (() => {
234
+ var _this = this;
235
+ return function () {
224
236
  var _this$devInfo;
225
- // @ts-ignore
226
- const deviceList = (_this$devInfo = this.devInfo) === null || _this$devInfo === void 0 ? void 0 : _this$devInfo.deviceList;
227
- if (!Array.isArray(deviceList) || deviceList.length === 0) return false;
228
- const isAllDeviceHasTimer = deviceList.every(d => {
229
- var _d$panelConfig;
230
- const timer = d === null || d === void 0 || (_d$panelConfig = d.panelConfig) === null || _d$panelConfig === void 0 || (_d$panelConfig = _d$panelConfig.bic) === null || _d$panelConfig === void 0 ? void 0 : _d$panelConfig.find(i => i.code === 'timer');
231
- if (!timer) {
232
- !this.isIniting && ScheduleLogger.info('isSupportCloudTimer: ', `${d.devId} 不支持云定时`);
233
- return false;
237
+ let devInfo = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
238
+ // this.getCachedDevInfo() 中将 devInfo 不存在的数据合并到 this.devInfo
239
+ const cachedDevInfo = _this.getCachedDevInfo();
240
+ const filteredDevInfo = {};
241
+ const _devInfo = _objectSpread(_objectSpread({}, cachedDevInfo), devInfo);
242
+ Object.keys(_devInfo).forEach(key => {
243
+ if (!(key in cachedDevInfo)) {
244
+ filteredDevInfo[key] = devInfo[key];
234
245
  }
235
- return timer.selected;
236
246
  });
237
- return isAllDeviceHasTimer;
238
- }
239
- return ((_this$devInfo2 = this.devInfo) === null || _this$devInfo2 === void 0 || (_this$devInfo2 = _this$devInfo2.panelConfig) === null || _this$devInfo2 === void 0 || (_this$devInfo2 = _this$devInfo2.bic) === null || _this$devInfo2 === void 0 ? void 0 : _this$devInfo2.find(i => i.code === 'timer' && i.selected)) !== undefined;
240
- };
247
+ _this.devInfo = _objectSpread(_objectSpread({}, cachedDevInfo), filteredDevInfo);
248
+ if (!_this.devInfo) {
249
+ return false;
250
+ }
251
+ return ((_this$devInfo = _this.devInfo) === null || _this$devInfo === void 0 || (_this$devInfo = _this$devInfo.panelConfig) === null || _this$devInfo === void 0 || (_this$devInfo = _this$devInfo.bic) === null || _this$devInfo === void 0 ? void 0 : _this$devInfo.find(i => i.code === 'timer' && i.selected)) !== undefined;
252
+ };
253
+ })();
241
254
  supportDp = (dpCode, devInfo) => {
242
255
  this.devInfo = devInfo !== null && devInfo !== void 0 ? devInfo : this.getCachedDevInfo();
243
256
  if (!this.devInfo) {
@@ -267,7 +280,7 @@ export class Support {
267
280
  * @return {boolean} - 如果dpCode支持则返回true,否则返回false。
268
281
  */
269
282
  isSupportDp = (() => {
270
- var _this = this;
283
+ var _this2 = this;
271
284
  return function (dpCode) {
272
285
  let isForce = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
273
286
  let devInfo = arguments.length > 2 ? arguments[2] : undefined;
@@ -276,11 +289,11 @@ export class Support {
276
289
  return cache[dpCode];
277
290
  }
278
291
  }
279
- if (!_this.isInit) {
292
+ if (!_this2.isInit) {
280
293
  return false;
281
294
  }
282
295
  // 是否存在相关dp
283
- const isDpSupport = _this.supportDp(dpCode, devInfo);
296
+ const isDpSupport = _this2.supportDp(dpCode, devInfo);
284
297
  cache[dpCode] = isDpSupport;
285
298
  return isDpSupport;
286
299
  };
@@ -352,7 +365,7 @@ export class Support {
352
365
  * @returns {boolean} - 是否是 Matter 设备
353
366
  */
354
367
  isMatterDevice(devInfo, isMatter) {
355
- var _this$devInfo3;
368
+ var _this$devInfo2;
356
369
  if (isMatter !== undefined) {
357
370
  return isMatter;
358
371
  }
@@ -360,30 +373,30 @@ export class Support {
360
373
  return !!devInfo.isMatter;
361
374
  }
362
375
  this.devInfo = this.getCachedDevInfo();
363
- return !!((_this$devInfo3 = this.devInfo) !== null && _this$devInfo3 !== void 0 && _this$devInfo3.isMatter);
376
+ return !!((_this$devInfo2 = this.devInfo) !== null && _this$devInfo2 !== void 0 && _this$devInfo2.isMatter);
364
377
  }
365
378
 
366
379
  /**
367
380
  * @description 是否是 涂鸦 Matter 设备
368
381
  */
369
382
  isTuyaMatterDevice(devInfo) {
370
- var _this$devInfo4, _this$devInfo5;
383
+ var _this$devInfo3, _this$devInfo4;
371
384
  if (devInfo) {
372
385
  return !!(devInfo !== null && devInfo !== void 0 && devInfo.isMatter && !(devInfo !== null && devInfo !== void 0 && devInfo.isTripartiteMatter));
373
386
  }
374
387
  this.devInfo = this.getCachedDevInfo();
375
- return !!((_this$devInfo4 = this.devInfo) !== null && _this$devInfo4 !== void 0 && _this$devInfo4.isMatter && !((_this$devInfo5 = this.devInfo) !== null && _this$devInfo5 !== void 0 && _this$devInfo5.isTripartiteMatter));
388
+ return !!((_this$devInfo3 = this.devInfo) !== null && _this$devInfo3 !== void 0 && _this$devInfo3.isMatter && !((_this$devInfo4 = this.devInfo) !== null && _this$devInfo4 !== void 0 && _this$devInfo4.isTripartiteMatter));
376
389
  }
377
390
 
378
391
  /**
379
392
  * @description 是否是 三方 Matter 设备
380
393
  */
381
394
  isTripartiteMatter(devInfo) {
382
- var _this$devInfo6;
395
+ var _this$devInfo5;
383
396
  if (devInfo) {
384
397
  return !!devInfo.isTripartiteMatter;
385
398
  }
386
399
  this.devInfo = this.getCachedDevInfo();
387
- return !!((_this$devInfo6 = this.devInfo) !== null && _this$devInfo6 !== void 0 && _this$devInfo6.isTripartiteMatter);
400
+ return !!((_this$devInfo5 = this.devInfo) !== null && _this$devInfo5 !== void 0 && _this$devInfo5.isTripartiteMatter);
388
401
  }
389
402
  }
@@ -1,7 +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 { scheduleLogger } from './ScheduleLogger';
4
- const __dpState = {};
5
+ let __dpState = {};
5
6
  export const getDpState = dpCode => {
6
7
  scheduleLogger.debug('getDpState', dpCode, __dpState);
7
8
  return __dpState[dpCode];
@@ -22,6 +23,6 @@ export const getAllDpState = () => {
22
23
  };
23
24
  export const initDpState = function () {
24
25
  let dpState = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
25
- Object.assign(__dpState, dpState);
26
+ __dpState = _objectSpread(_objectSpread({}, __dpState), dpState);
26
27
  scheduleLogger.debug('initDpState', __dpState);
27
28
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ray-js/lamp-schedule-core",
3
- "version": "1.0.4-beta-4",
3
+ "version": "1.0.4-beta-6",
4
4
  "description": "照明计划模块核心能力",
5
5
  "main": "./lib/index.js",
6
6
  "files": [