@ray-js/lamp-schedule-core 1.0.4-beta-15 → 1.0.5-beta.10

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 (63) hide show
  1. package/lib/config/dpCodes.d.ts +18 -1
  2. package/lib/config/dpCodes.js +34 -1
  3. package/lib/conflict/index.d.ts +13 -3
  4. package/lib/conflict/index.js +27 -1
  5. package/lib/conflict/scheduleDataManager.js +7 -3
  6. package/lib/conflict/transform.js +2 -1
  7. package/lib/conflict/type.d.ts +4 -0
  8. package/lib/dpParser/__test__/rhythms.test.js +7 -2
  9. package/lib/dpParser/__test__/rhythmsSigmesh.test.d.ts +1 -0
  10. package/lib/dpParser/__test__/rhythmsSigmesh.test.js +263 -0
  11. package/lib/dpParser/__test__/sleepSigmesh.test.d.ts +1 -0
  12. package/lib/dpParser/__test__/sleepSigmesh.test.js +185 -0
  13. package/lib/dpParser/__test__/wakeupSigmesh.test.js +4 -2
  14. package/lib/dpParser/brightAdjustData.d.ts +10 -0
  15. package/lib/dpParser/brightAdjustData.js +43 -0
  16. package/lib/dpParser/colourDataRaw.d.ts +14 -0
  17. package/lib/dpParser/colourDataRaw.js +56 -0
  18. package/lib/dpParser/index.d.ts +4 -1
  19. package/lib/dpParser/index.js +14 -1
  20. package/lib/dpParser/rhythms/index.d.ts +9 -0
  21. package/lib/dpParser/rhythms/index.js +27 -0
  22. package/lib/dpParser/{rhythms.d.ts → rhythms/rhythmsCommon.d.ts} +2 -3
  23. package/lib/dpParser/{rhythms.js → rhythms/rhythmsCommon.js} +6 -9
  24. package/lib/dpParser/rhythms/rhythmsSigmesh.d.ts +17 -0
  25. package/lib/dpParser/rhythms/rhythmsSigmesh.js +143 -0
  26. package/lib/dpParser/sleep/index.d.ts +1 -2
  27. package/lib/dpParser/sleep/index.js +13 -12
  28. package/lib/dpParser/sleep/sleepSigmesh.d.ts +20 -0
  29. package/lib/dpParser/sleep/sleepSigmesh.js +88 -97
  30. package/lib/dpParser/stripLocalTimer.d.ts +41 -0
  31. package/lib/dpParser/stripLocalTimer.js +275 -0
  32. package/lib/dpParser/wakeup/index.d.ts +0 -2
  33. package/lib/dpParser/wakeup/index.js +12 -16
  34. package/lib/dpParser/wakeup/wakeupSigmesh.js +10 -1
  35. package/lib/hooks/__test__/useBaseLightDp.test.js +10 -2
  36. package/lib/hooks/__test__/useTimerDp.test.js +5 -5
  37. package/lib/hooks/useBaseLightDp.d.ts +7 -2
  38. package/lib/hooks/useBaseLightDp.js +34 -16
  39. package/lib/hooks/useCommonSupport.js +19 -0
  40. package/lib/hooks/useCycleDp.js +2 -0
  41. package/lib/hooks/useDPByProtocol.d.ts +11 -0
  42. package/lib/hooks/useRandomDp.js +2 -0
  43. package/lib/hooks/useRhythmsDp.d.ts +3 -3
  44. package/lib/hooks/useRhythmsDp.js +2 -0
  45. package/lib/hooks/useSleepDp.js +2 -0
  46. package/lib/hooks/useTimerDp.d.ts +4 -3
  47. package/lib/hooks/useTimerDp.js +21 -4
  48. package/lib/hooks/useTimerReportDp.js +1 -0
  49. package/lib/hooks/useWakeUpDp.js +2 -0
  50. package/lib/hooks/useWakeupDp.js +2 -0
  51. package/lib/types/rhythms.d.ts +16 -0
  52. package/lib/types/rhythms.js +3 -1
  53. package/lib/types/timer.d.ts +11 -0
  54. package/lib/utils/ScheduleDataSync.js +1 -0
  55. package/lib/utils/ScheduleSupport.d.ts +4 -0
  56. package/lib/utils/ScheduleSupport.js +23 -3
  57. package/lib/utils/__test__/ScheduleDataSync.test.d.ts +1 -0
  58. package/lib/utils/__test__/ScheduleDataSync.test.js +2 -0
  59. package/lib/utils/__test__/objectToId.test.d.ts +1 -0
  60. package/lib/utils/__test__/objectToId.test.js +98 -0
  61. package/lib/utils/getDPByProtocol.d.ts +22 -0
  62. package/lib/utils/matterDeviceUtils.d.ts +22 -0
  63. package/package.json +1 -1
@@ -19,7 +19,7 @@ export declare const scheduleDpCodes: {
19
19
  readonly CYCLE_TIMING: "cycle_timing";
20
20
  /** 通用本地定时 */
21
21
  readonly LOCAL_TIMER: "local_timer";
22
- /** 灯带本地定时 */
22
+ /** 灯带本地定时 Beacon */
23
23
  readonly STRIP_LOCAL_TIMER: "strip_local_timer";
24
24
  /** 定时同步 一般用于 Beacon */
25
25
  readonly TIMER_SYNC: "timer_sync";
@@ -33,6 +33,23 @@ export declare const scheduleDpCodes: {
33
33
  readonly BRIGHTNESS: "bright_value";
34
34
  /** 彩光 */
35
35
  readonly COLOUR_DATA: "colour_data";
36
+ /** 彩光原始数据 Beacon */
37
+ readonly COLOUR_DATA_RAW: "colour_data_raw";
38
+ /** 亮度调节 Beacon */
39
+ readonly BRIGHT_ADJUST_DATA: "bright_adjust_data";
40
+ /** ------ 风扇灯 Beacon DP -------- */
41
+ /** 风扇模式 Beacon */
42
+ readonly FAN_MODE: "fan_mode";
43
+ /** 风向 Beacon */
44
+ readonly FAN_DIRECTION: "fan_direction";
45
+ /** 摇头 Beacon */
46
+ readonly SHAKE: "shake";
47
+ readonly WHITE_SWITCH: "white_switch";
48
+ readonly COLOUR_SWITCH: "colour_switch";
49
+ readonly FAN_SWITCH: "fan_switch";
50
+ readonly FAN_SPEED: "fan_speed";
51
+ readonly FAN_BEEP: "fan_beep";
52
+ readonly STRIP_SCENE: "strip_scene";
36
53
  /** 模式 */
37
54
  readonly WORK_MODE: "work_mode";
38
55
  };
@@ -22,7 +22,7 @@ export const scheduleDpCodes = {
22
22
  [EScheduleType.CYCLE_TIMING]: 'cycle_timing',
23
23
  /** 通用本地定时 */
24
24
  [EScheduleType.LOCAL_TIMER]: 'local_timer',
25
- /** 灯带本地定时 */
25
+ /** 灯带本地定时 Beacon */
26
26
  [EScheduleType.STRIP_LOCAL_TIMER]: 'strip_local_timer',
27
27
  /** 定时同步 一般用于 Beacon */
28
28
  [EScheduleType.TIMER_SYNC]: 'timer_sync',
@@ -36,6 +36,39 @@ export const scheduleDpCodes = {
36
36
  BRIGHTNESS: 'bright_value',
37
37
  /** 彩光 */
38
38
  COLOUR_DATA: 'colour_data',
39
+ /** 彩光原始数据 Beacon */
40
+ COLOUR_DATA_RAW: 'colour_data_raw',
41
+ /** 亮度调节 Beacon */
42
+ BRIGHT_ADJUST_DATA: 'bright_adjust_data',
43
+ /** ------ 风扇灯 Beacon DP -------- */
44
+ /** 风扇模式 Beacon */
45
+ FAN_MODE: 'fan_mode',
46
+ // 枚举值: fresh, nature
47
+ /** 风向 Beacon */
48
+ FAN_DIRECTION: 'fan_direction',
49
+ // 枚举值: forward, reverse
50
+ /** 摇头 Beacon */
51
+ SHAKE: 'shake',
52
+ // boolean
53
+ // 主灯开关
54
+ WHITE_SWITCH: 'white_switch',
55
+ // boolean
56
+ // 氛围灯开关
57
+ COLOUR_SWITCH: 'colour_switch',
58
+ // boolean
59
+ // 风扇开关
60
+ FAN_SWITCH: 'fan_switch',
61
+ // boolean
62
+ // 风扇速度
63
+ FAN_SPEED: 'fan_speed',
64
+ // number 1-100
65
+ // 声音
66
+ FAN_BEEP: 'fan_beep',
67
+ // boolean
68
+ // 情景
69
+ STRIP_SCENE: 'strip_scene',
70
+ // beacon mesh情景功能,支持速度,亮度编辑
71
+
39
72
  /** 模式 */
40
73
  WORK_MODE: 'work_mode'
41
74
  };
@@ -1,10 +1,15 @@
1
- import { TConflictRes, ConflictRule, TFoldScheduleList, TSchedule } from './type';
1
+ import { TConflictRes, ConflictRule, TFoldScheduleList, TSchedule, PartialSchedule } from './type';
2
+ import { EScheduleFunctionType } from '../types';
2
3
  /**
3
4
  * 冲突检测
4
5
  */
5
6
  export declare class Conflict {
6
7
  static rule: ConflictRule;
7
8
  static isInit: boolean;
9
+ /**
10
+ * 获取冲突检测数据
11
+ */
12
+ static getData(): Record<string, any>[];
8
13
  /**
9
14
  * 添加冲突规则
10
15
  */
@@ -18,13 +23,18 @@ export declare class Conflict {
18
23
  * conflictList - 具体的冲突检测结果数组
19
24
  */
20
25
  static add(current: TSchedule): TConflictRes;
26
+ /**
27
+ * 删除指定类型的日程
28
+ * @param type - 日程类型
29
+ */
30
+ static removeByType(type: EScheduleFunctionType): void;
21
31
  /**
22
32
  * 删除日程
23
33
  *
24
- * @param current - 待添加的日程对象,类型为 Schedule
34
+ * @param current - 待添加的日程对象,类型为 Schedule, 如果没有 detail 则认为是删除指定类型的日程
25
35
  * @returns void
26
36
  */
27
- static remove(current: TSchedule): void;
37
+ static remove(current: TSchedule | PartialSchedule): void;
28
38
  /**
29
39
  * 更新新日程时检测冲突
30
40
  *
@@ -1,6 +1,7 @@
1
1
  import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
2
  import "core-js/modules/es.json.stringify.js";
3
3
  import "core-js/modules/esnext.iterator.constructor.js";
4
+ import "core-js/modules/esnext.iterator.filter.js";
4
5
  import "core-js/modules/esnext.iterator.find.js";
5
6
  import { scheduleLogger } from '../utils/ScheduleLogger';
6
7
  import { checkConflicts } from './ConflictResolver';
@@ -12,6 +13,13 @@ import { EScheduleFunctionType } from '../types';
12
13
  * 冲突检测
13
14
  */
14
15
  export class Conflict {
16
+ /**
17
+ * 获取冲突检测数据
18
+ */
19
+ static getData() {
20
+ return ScheduleDataManager.getInstance().getData();
21
+ }
22
+
15
23
  /**
16
24
  * 添加冲突规则
17
25
  */
@@ -50,13 +58,31 @@ export class Conflict {
50
58
  };
51
59
  }
52
60
 
61
+ /**
62
+ * 删除指定类型的日程
63
+ * @param type - 日程类型
64
+ */
65
+ static removeByType(type) {
66
+ const instance = ScheduleDataManager.getInstance();
67
+ const list = instance.getData() || [];
68
+ const filteredList = list.filter(item => item.type !== type);
69
+ ScheduleDataManager.list = filteredList;
70
+ }
71
+
53
72
  /**
54
73
  * 删除日程
55
74
  *
56
- * @param current - 待添加的日程对象,类型为 Schedule
75
+ * @param current - 待添加的日程对象,类型为 Schedule, 如果没有 detail 则认为是删除指定类型的日程
57
76
  * @returns void
58
77
  */
59
78
  static remove(current) {
79
+ if (!current) {
80
+ return;
81
+ }
82
+ if (current.type && !current.detail) {
83
+ this.removeByType(current.type);
84
+ return;
85
+ }
60
86
  const [cur] = transScheduleListToConflictList([current]);
61
87
  scheduleLogger.debug('Conflict.remove cur, current:', cur, current);
62
88
 
@@ -1,3 +1,4 @@
1
+ import "core-js/modules/es.json.stringify.js";
1
2
  import "core-js/modules/esnext.iterator.constructor.js";
2
3
  import "core-js/modules/esnext.iterator.filter.js";
3
4
  import "core-js/modules/esnext.iterator.for-each.js";
@@ -63,10 +64,11 @@ export class ScheduleDataManager {
63
64
  }
64
65
  const idsToAdd = new Set(itemsMap.keys());
65
66
  const filteredList = ScheduleDataManager.list.filter(item => !idsToAdd.has(item.id));
66
- ScheduleDataManager.list = [...filteredList, ...itemsMap.values()].filter(item => {
67
+ const newList = [...filteredList, ...itemsMap.values()].filter(item => {
67
68
  var _item$data;
68
69
  return (item === null || item === void 0 || (_item$data = item.data) === null || _item$data === void 0 ? void 0 : _item$data.status) === true;
69
70
  });
71
+ ScheduleDataManager.list = newList;
70
72
  }
71
73
  clearData() {
72
74
  scheduleLogger.debug('ScheduleDataManager.clearData pre', ScheduleDataManager.list);
@@ -76,12 +78,14 @@ export class ScheduleDataManager {
76
78
  if (!current) {
77
79
  return;
78
80
  }
79
- scheduleLogger.debug('ScheduleDataManager.deleteData pre', current);
81
+ scheduleLogger.debug('ScheduleDataManager.deleteData pre', current, JSON.stringify(ScheduleDataManager.list));
80
82
  const index = ScheduleDataManager.list.findIndex(item => item.id === current.id);
81
83
  if (index !== -1) {
82
84
  ScheduleDataManager.list.splice(index, 1);
85
+ scheduleLogger.debug('ScheduleDataManager.deleteData post', JSON.stringify(ScheduleDataManager.list));
86
+ } else {
87
+ scheduleLogger.debug('ScheduleDataManager.deleteData post not found', JSON.stringify(ScheduleDataManager.list));
83
88
  }
84
- scheduleLogger.debug('ScheduleDataManager.deleteData post', ScheduleDataManager.list);
85
89
  }
86
90
 
87
91
  // 添加remove方法作为deleteData的别名,用于测试
@@ -18,6 +18,7 @@ import { scheduleLogger } from '../utils/ScheduleLogger';
18
18
  export const timerDataToSchedule = data => {
19
19
  var _data$status;
20
20
  scheduleLogger.debug('timerDataToSchedule:', data);
21
+ const stableTimerId = data.timerId || (data === null || data === void 0 ? void 0 : data.id);
21
22
  const _data = {
22
23
  status: (_data$status = data.status) !== null && _data$status !== void 0 ? _data$status : false,
23
24
  weeks: data.loops.split('').map(item => Number(item)),
@@ -26,7 +27,7 @@ export const timerDataToSchedule = data => {
26
27
  dps: data.dps,
27
28
  aliasName: data.aliasName || '',
28
29
  isAppPush: data.isAppPush || false,
29
- id: (data === null || data === void 0 ? void 0 : data.id) || data.timerId
30
+ id: stableTimerId
30
31
  };
31
32
  const timerId = `${EScheduleFunctionType.TIMER}_${_data.id}`;
32
33
  return {
@@ -52,5 +52,9 @@ export type TSchedule = {
52
52
  type: EScheduleFunctionType;
53
53
  detail: ScheduleNodeType[];
54
54
  };
55
+ export type PartialSchedule = {
56
+ type: EScheduleFunctionType;
57
+ detail?: ScheduleNodeType[];
58
+ };
55
59
  export type TFoldScheduleList = TSchedule[];
56
60
  export {};
@@ -71,7 +71,9 @@ describe('RhythmParser', () => {
71
71
  expect(result).toBe('');
72
72
  });
73
73
  it('should return empty string when support instance is missing', () => {
74
- getSupportIns.mockReturnValueOnce(null);
74
+ // getSupportIns is called in both the dispatcher and the common formatter,
75
+ // so we need to mock it for all calls within this test
76
+ getSupportIns.mockReturnValue(null);
75
77
  const result = rhythmParser.formatter({
76
78
  version: 1,
77
79
  power: true,
@@ -91,9 +93,12 @@ describe('RhythmParser', () => {
91
93
  });
92
94
  expect(result).toBe('');
93
95
  expect(scheduleLogger.error).toHaveBeenCalledWith('协议解析 rhythms formatter =====', '数据为空');
96
+ // Restore default mock
97
+ getSupportIns.mockReturnValue(createSupport(true));
94
98
  });
95
99
  it('should force temperature to 100 when device does not support temperature DP', () => {
96
- getSupportIns.mockReturnValueOnce(createSupport(false));
100
+ // getSupportIns is called in both the dispatcher and the common formatter
101
+ getSupportIns.mockReturnValue(createSupport(false));
97
102
  const result = rhythmParser.formatter({
98
103
  version: 0,
99
104
  power: true,
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,263 @@
1
+ import "core-js/modules/esnext.iterator.constructor.js";
2
+ import "core-js/modules/esnext.iterator.map.js";
3
+ jest.mock('@ray-js/panel-sdk/lib/utils', () => ({
4
+ generateDpStrStep: jest.fn(str => {
5
+ let index = 0;
6
+ return len => {
7
+ const segment = str.slice(index, index + len);
8
+ index += len;
9
+ return {
10
+ value: parseInt(segment, 16)
11
+ };
12
+ };
13
+ }),
14
+ numToHexString: jest.fn(num => num.toString(16).padStart(2, '0'))
15
+ }));
16
+ jest.mock('../../utils/ScheduleLogger', () => {
17
+ const logger = {
18
+ debug: jest.fn(),
19
+ warn: jest.fn(),
20
+ error: jest.fn(),
21
+ info: jest.fn()
22
+ };
23
+ return {
24
+ scheduleLogger: logger
25
+ };
26
+ });
27
+ jest.mock('../../hooks/useCommonSupport', () => ({
28
+ getSupportIns: jest.fn()
29
+ }));
30
+ jest.mock('../../utils/getDPByProtocol', () => ({
31
+ getDPByProtocol: jest.fn().mockReturnValue({
32
+ TEMPERATURE: 'temp_value'
33
+ })
34
+ }));
35
+ import { rhythmParserSigmesh, RhythmSigmesh } from '../rhythms/rhythmsSigmesh';
36
+ const {
37
+ getSupportIns
38
+ } = require('../../hooks/useCommonSupport');
39
+ const createSupport = function () {
40
+ let isSupportTemp = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
41
+ return {
42
+ isSigMeshDevice: jest.fn().mockReturnValue(true),
43
+ isSupportDp: jest.fn().mockImplementation(dp => {
44
+ if (dp === 'temp_value') {
45
+ return isSupportTemp;
46
+ }
47
+ return true;
48
+ })
49
+ };
50
+ };
51
+
52
+ /**
53
+ * 构建 sigmesh rhythms DP 字符串
54
+ * 格式: version(2) + power(2) + mode(2) + weeks(2) + paramMode(2) + number(2)
55
+ * + nodes[valid(2) + hour(2) + minute(2) + brightness(2) + temperature(2)]
56
+ */
57
+ const buildDpStr = function (nodes) {
58
+ let version = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
59
+ let power = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
60
+ let mode = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
61
+ let weeks = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0x7f;
62
+ let paramMode = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 1;
63
+ const header = [version, power, mode, weeks, paramMode, nodes.length].map(v => v.toString(16).padStart(2, '0')).join('');
64
+ const body = nodes.map(node => [node.valid, node.hour, node.minute, node.brightness, node.temperature].map(v => v.toString(16).padStart(2, '0')).join('')).join('');
65
+ return `${header}${body}`;
66
+ };
67
+ describe('RhythmSigmesh parser & formatter', () => {
68
+ beforeEach(() => {
69
+ jest.clearAllMocks();
70
+ getSupportIns.mockReturnValue(createSupport(true));
71
+ });
72
+ describe('parser', () => {
73
+ it('returns default value when dp string is empty', () => {
74
+ const result = rhythmParserSigmesh.parser('');
75
+ expect(result).toEqual(new RhythmSigmesh().defaultValue);
76
+ });
77
+ it('returns default value when dp string length is invalid', () => {
78
+ // Too short
79
+ const result = rhythmParserSigmesh.parser('010100');
80
+ expect(result).toEqual(new RhythmSigmesh().defaultValue);
81
+ });
82
+ it('returns default value when node data is not aligned', () => {
83
+ // Header (12 chars) + partial node data (not multiple of 10)
84
+ // 14 chars header + 2 chars body (not 10)
85
+ const result = rhythmParserSigmesh.parser('01010000007f0104' + '01');
86
+ expect(result).toEqual(new RhythmSigmesh().defaultValue);
87
+ });
88
+ it('parses valid dp string with 4 nodes', () => {
89
+ const dpStr = buildDpStr([{
90
+ valid: 1,
91
+ hour: 6,
92
+ minute: 30,
93
+ brightness: 100,
94
+ temperature: 50
95
+ }, {
96
+ valid: 1,
97
+ hour: 11,
98
+ minute: 30,
99
+ brightness: 100,
100
+ temperature: 100
101
+ }, {
102
+ valid: 1,
103
+ hour: 17,
104
+ minute: 0,
105
+ brightness: 70,
106
+ temperature: 50
107
+ }, {
108
+ valid: 1,
109
+ hour: 20,
110
+ minute: 30,
111
+ brightness: 70,
112
+ temperature: 50
113
+ }]);
114
+ const result = rhythmParserSigmesh.parser(dpStr);
115
+ expect(result.version).toBe(1);
116
+ expect(result.power).toBe(true);
117
+ expect(result.mode).toBe(0);
118
+ expect(result.paramMode).toBe(1);
119
+ expect(result.number).toBe(4);
120
+ expect(result.rhythms).toHaveLength(4);
121
+ expect(result.rhythms[0]).toMatchObject({
122
+ power: true,
123
+ hour: 6,
124
+ minute: 30,
125
+ brightness: 100,
126
+ temperature: 50
127
+ });
128
+ expect(result.rhythms[3]).toMatchObject({
129
+ power: true,
130
+ hour: 20,
131
+ minute: 30,
132
+ brightness: 70,
133
+ temperature: 50
134
+ });
135
+ });
136
+ it('parses power=false correctly', () => {
137
+ const dpStr = buildDpStr([{
138
+ valid: 0,
139
+ hour: 8,
140
+ minute: 0,
141
+ brightness: 50,
142
+ temperature: 30
143
+ }], 1, 0);
144
+ const result = rhythmParserSigmesh.parser(dpStr);
145
+ expect(result.power).toBe(false);
146
+ expect(result.rhythms[0].power).toBe(false);
147
+ });
148
+ });
149
+ describe('formatter', () => {
150
+ it('returns empty string when data is null', () => {
151
+ const result = rhythmParserSigmesh.formatter(null);
152
+ expect(result).toBe('');
153
+ });
154
+ it('returns empty string when support is null', () => {
155
+ getSupportIns.mockReturnValueOnce(null);
156
+ const result = rhythmParserSigmesh.formatter({
157
+ version: 1,
158
+ power: true,
159
+ mode: 0,
160
+ weeks: [1, 1, 1, 1, 1, 1, 1, 0],
161
+ paramMode: 1,
162
+ number: 1,
163
+ rhythms: [{
164
+ power: true,
165
+ hour: 6,
166
+ minute: 30,
167
+ brightness: 100,
168
+ temperature: 50
169
+ }]
170
+ });
171
+ expect(result).toBe('');
172
+ });
173
+ it('formats valid data to dp string', () => {
174
+ const result = rhythmParserSigmesh.formatter({
175
+ version: 1,
176
+ power: true,
177
+ mode: 0,
178
+ weeks: [1, 1, 1, 1, 1, 1, 1, 0],
179
+ paramMode: 1,
180
+ number: 2,
181
+ rhythms: [{
182
+ power: true,
183
+ hour: 6,
184
+ minute: 30,
185
+ brightness: 100,
186
+ temperature: 50
187
+ }, {
188
+ power: false,
189
+ hour: 20,
190
+ minute: 0,
191
+ brightness: 70,
192
+ temperature: 30
193
+ }]
194
+ });
195
+ const expected = buildDpStr([{
196
+ valid: 1,
197
+ hour: 6,
198
+ minute: 30,
199
+ brightness: 100,
200
+ temperature: 50
201
+ }, {
202
+ valid: 0,
203
+ hour: 20,
204
+ minute: 0,
205
+ brightness: 70,
206
+ temperature: 30
207
+ }], 1, 1, 0, 0x7f, 1);
208
+ expect(result).toBe(expected);
209
+ });
210
+ it('forces temperature to 100 when device does not support temperature DP', () => {
211
+ getSupportIns.mockReturnValueOnce(createSupport(false));
212
+ const result = rhythmParserSigmesh.formatter({
213
+ version: 1,
214
+ power: true,
215
+ mode: 0,
216
+ weeks: [1, 1, 1, 1, 1, 1, 1, 0],
217
+ paramMode: 1,
218
+ number: 1,
219
+ rhythms: [{
220
+ power: true,
221
+ hour: 6,
222
+ minute: 0,
223
+ brightness: 50,
224
+ temperature: 30
225
+ }]
226
+ });
227
+ // temperature should be 100 (0x64), not 30 (0x1e)
228
+ expect(result.slice(-2)).toBe('64');
229
+ });
230
+ });
231
+ describe('round-trip', () => {
232
+ it('round-trips dp string through parser and formatter', () => {
233
+ const dpStr = buildDpStr([{
234
+ valid: 1,
235
+ hour: 6,
236
+ minute: 30,
237
+ brightness: 100,
238
+ temperature: 50
239
+ }, {
240
+ valid: 1,
241
+ hour: 11,
242
+ minute: 30,
243
+ brightness: 100,
244
+ temperature: 100
245
+ }, {
246
+ valid: 1,
247
+ hour: 17,
248
+ minute: 0,
249
+ brightness: 70,
250
+ temperature: 50
251
+ }, {
252
+ valid: 1,
253
+ hour: 20,
254
+ minute: 30,
255
+ brightness: 70,
256
+ temperature: 50
257
+ }]);
258
+ const parsed = rhythmParserSigmesh.parser(dpStr);
259
+ const formatted = rhythmParserSigmesh.formatter(parsed);
260
+ expect(formatted).toBe(dpStr);
261
+ });
262
+ });
263
+ });
@@ -0,0 +1 @@
1
+ export {};