node-red-contrib-symi-mesh 1.7.1 → 1.7.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.
@@ -76,10 +76,41 @@ class DeviceInfo {
76
76
  this.lastSeen = Date.now();
77
77
 
78
78
  switch (attrType) {
79
+ case 0x01:
79
80
  case 0x02:
80
- // TYPE_ON_OFF - 开关状态(仅用于开关、灯光、温控器)
81
- // 窗帘(type=5)不使用0x02,忽略此消息避免误操作
82
- if (this.deviceType !== 5) {
81
+ case 0x03:
82
+ case 0x04:
83
+ // 特殊协议:attrType直接表示风速值(无参数)
84
+ // 53 80 06 03 E3 01 01 35 - 高风(01)
85
+ // 53 80 06 03 E3 01 02 36 - 中风(02)
86
+ // 53 80 06 03 E3 01 03 37 - 低风(03)
87
+ // 53 80 06 03 E3 01 04 30 - 自动(04)
88
+ if (this.deviceType === 10 && parameters.length === 0) {
89
+ const oldFanMode = this.state.fanMode;
90
+ this.state.fanMode = attrType;
91
+ if (oldFanMode !== this.state.fanMode && this.manager) {
92
+ this.manager.emit('device-state-changed', {
93
+ device: this,
94
+ state: { fanMode: this.state.fanMode, acFanSpeed: this.state.fanMode },
95
+ attrType: 0x1C,
96
+ parameters: [],
97
+ subOpcode: 0x06,
98
+ isUserControl: true,
99
+ isSceneExecution: false
100
+ });
101
+ }
102
+ return; // 已处理,直接返回
103
+ }
104
+ // 非温控器设备,继续处理其他逻辑
105
+ if (attrType === 0x03 && parameters.length > 0) {
106
+ this.state.brightness = parameters[0];
107
+ this.state.switch = parameters[0] > 0;
108
+ }
109
+ if (attrType === 0x04 && parameters.length > 0) {
110
+ this.state.colorTemp = parameters[0];
111
+ }
112
+ // 0x02用于开关状态,如果是温控器且无参数已在上面处理为风速
113
+ if (attrType === 0x02 && parameters.length > 0 && this.deviceType !== 5) {
83
114
  this.handleSwitchState(parameters);
84
115
  }
85
116
  break;
@@ -92,15 +123,6 @@ class DeviceInfo {
92
123
  this.handleSwitchState(parameters);
93
124
  }
94
125
  break;
95
- case 0x03:
96
- if (parameters.length > 0) {
97
- this.state.brightness = parameters[0];
98
- this.state.switch = parameters[0] > 0;
99
- }
100
- break;
101
- case 0x04:
102
- if (parameters.length > 0) this.state.colorTemp = parameters[0];
103
- break;
104
126
  case 0x05:
105
127
  // CURT_RUN_STATUS - 窗帘运行状态
106
128
  // 【兼容两种协议】:
@@ -109,6 +131,8 @@ class DeviceInfo {
109
131
  // 通过status=0(仅米家)和status=3(仅小程序)来区分协议类型
110
132
  if (parameters.length > 0) {
111
133
  const status = parameters[0];
134
+ const oldStatus = this.state.curtainStatus;
135
+ const oldAction = this.state.curtainAction;
112
136
  this.state.curtainStatus = status;
113
137
 
114
138
  // 检测协议类型:status=0只在米家出现,status=3只在小程序出现
@@ -133,6 +157,19 @@ class DeviceInfo {
133
157
  this.state.curtainAction = 'closing';
134
158
  }
135
159
  }
160
+
161
+ // 触发状态变化事件
162
+ if ((oldStatus !== this.state.curtainStatus || oldAction !== this.state.curtainAction) && this.manager) {
163
+ this.manager.emit('device-state-changed', {
164
+ device: this,
165
+ state: { curtainStatus: this.state.curtainStatus, curtainAction: this.state.curtainAction },
166
+ attrType: attrType,
167
+ parameters: parameters,
168
+ subOpcode: 0x06,
169
+ isUserControl: true,
170
+ isSceneExecution: false
171
+ });
172
+ }
136
173
  }
137
174
  break;
138
175
  case 0x06:
@@ -202,12 +239,16 @@ class DeviceInfo {
202
239
  if (parameters.length > 0) {
203
240
  const oldFanMode = this.state.fanMode;
204
241
  this.state.fanMode = parameters[0];
205
- // 触发状态变化事件
206
- if (oldFanMode !== this.state.fanMode) {
207
- this.emit('stateChange', {
242
+ // 触发状态变化事件(通过DeviceManager)
243
+ if (oldFanMode !== this.state.fanMode && this.manager) {
244
+ this.manager.emit('device-state-changed', {
208
245
  device: this,
209
- state: { fanMode: this.state.fanMode },
210
- attrType: attrType
246
+ state: { fanMode: this.state.fanMode, acFanSpeed: this.state.fanMode },
247
+ attrType: attrType,
248
+ parameters: [],
249
+ subOpcode: 0x06,
250
+ isUserControl: true,
251
+ isSceneExecution: false
211
252
  });
212
253
  }
213
254
  }
@@ -399,40 +440,25 @@ class DeviceInfo {
399
440
  if (this.channels === 1) {
400
441
  // 单路开关
401
442
  const value = parameters[0];
402
- console.log(`[DeviceManager] handleSwitchState: deviceType=${this.deviceType}, channels=${this.channels}, value=${value}, name=${this.name}`);
403
- // 温控器设备:0x02消息可能是开关或风速
443
+ // 温控器设备:0x02消息的值含义
444
+ // 0x01=关, 0x02=开 (开关控制)
445
+ // 但某些协议中 1-4 表示风速(需要通过 attrType=0x1C 来区分)
446
+ // 这里只处理开关控制,风速控制由 0x1C 消息处理
404
447
  if (this.deviceType === 10) {
405
- console.log(`[DeviceManager] 温控器设备,检查风速: value=${value}`);
406
- // 如果值是1-4,是风速控制
407
- if (value >= 1 && value <= 4) {
408
- const oldFanMode = this.state.fanMode;
409
- this.state.fanMode = value;
410
- console.log(`[DeviceManager] 风速变化: ${oldFanMode} -> ${this.state.fanMode}`);
411
- // 总是触发事件,即使值没变
412
- console.log(`[DeviceManager] 触发fanMode事件`);
413
- // 注意:这里不能直接emit,因为这是DeviceInfo实例,不是DeviceManager
414
- // 需要通过DeviceManager来触发事件
415
- if (this.manager) {
416
- this.manager.emit('device-state-changed', {
417
- device: this,
418
- state: { fanMode: this.state.fanMode },
419
- attrType: 0x1C
420
- });
421
- }
422
- } else {
423
- // 否则是开关控制
424
- console.log(`[DeviceManager] 开关控制: value=${value}`);
425
- const oldSwitch = this.state.switch;
426
- this.state.switch = value === 0x02;
427
- // 触发开关状态变化事件
428
- if (oldSwitch !== this.state.switch && this.manager) {
429
- console.log(`[DeviceManager] 触发switch事件: ${oldSwitch} -> ${this.state.switch}`);
430
- this.manager.emit('device-state-changed', {
431
- device: this,
432
- state: { switch: this.state.switch },
433
- attrType: 0x02
434
- });
435
- }
448
+ // 温控器开关:0x01=关, 0x02=开
449
+ const oldSwitch = this.state.switch;
450
+ this.state.switch = value === 0x02;
451
+ // 触发开关状态变化事件
452
+ if (oldSwitch !== this.state.switch && this.manager) {
453
+ this.manager.emit('device-state-changed', {
454
+ device: this,
455
+ state: { switch: this.state.switch, acSwitch: this.state.switch },
456
+ attrType: 0x02,
457
+ parameters: [],
458
+ subOpcode: 0x06,
459
+ isUserControl: true,
460
+ isSceneExecution: false
461
+ });
436
462
  }
437
463
  } else {
438
464
  this.state.switch = value === 0x02;
@@ -500,6 +526,25 @@ class DeviceInfo {
500
526
  // 存储变化的按键信息,供外部使用
501
527
  this.lastChangedButtons = changedButtons;
502
528
 
529
+ // 触发状态变化事件(多路开关)
530
+ // 注意:这个事件会被symi-gateway.js转发给symi-485-bridge.js
531
+ if (changedButtons.length > 0 && this.manager) {
532
+ const changedState = {};
533
+ for (const btn of changedButtons) {
534
+ changedState[`switch_${btn.button}`] = btn.newState;
535
+ }
536
+ // 使用与symi-gateway.js相同的事件格式
537
+ this.manager.emit('device-state-changed', {
538
+ device: this,
539
+ state: changedState,
540
+ attrType: 0x02,
541
+ parameters: [],
542
+ subOpcode: 0x06,
543
+ isUserControl: true,
544
+ isSceneExecution: false
545
+ });
546
+ }
547
+
503
548
  return changedButtons;
504
549
  }
505
550
 
@@ -584,7 +629,7 @@ class DeviceManager extends EventEmitter {
584
629
  const addrMap = this.context.get(`symi_addr_map_${this.gatewayId}`) || {};
585
630
 
586
631
  Object.entries(saved).forEach(([mac, data]) => {
587
- const device = new DeviceInfo(data);
632
+ const device = new DeviceInfo(data, this); // 传递manager引用
588
633
  // 恢复三合一标记
589
634
  if (data.isThreeInOne) {
590
635
  device.isThreeInOne = true;
@@ -11,7 +11,8 @@
11
11
  },
12
12
  inputs: 1,
13
13
  outputs: 1,
14
- icon: 'serial.svg',
14
+ icon: 'font-awesome/fa-bug',
15
+ align: 'left',
15
16
  paletteLabel: 'RS485调试',
16
17
  label: function() {
17
18
  return this.name || 'RS485调试';