@switchbot/homebridge-switchbot 3.6.1-beta.10 → 3.6.1-beta.12

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 (110) hide show
  1. package/dist/device/blindtilt.d.ts.map +1 -1
  2. package/dist/device/blindtilt.js +9 -0
  3. package/dist/device/blindtilt.js.map +1 -1
  4. package/dist/device/bot.d.ts.map +1 -1
  5. package/dist/device/bot.js +34 -1
  6. package/dist/device/bot.js.map +1 -1
  7. package/dist/device/ceilinglight.d.ts.map +1 -1
  8. package/dist/device/ceilinglight.js +3 -0
  9. package/dist/device/ceilinglight.js.map +1 -1
  10. package/dist/device/contact.d.ts.map +1 -1
  11. package/dist/device/contact.js +12 -0
  12. package/dist/device/contact.js.map +1 -1
  13. package/dist/device/curtain.d.ts.map +1 -1
  14. package/dist/device/curtain.js +9 -0
  15. package/dist/device/curtain.js.map +1 -1
  16. package/dist/device/fan.d.ts.map +1 -1
  17. package/dist/device/fan.js +9 -0
  18. package/dist/device/fan.js.map +1 -1
  19. package/dist/device/hub.d.ts.map +1 -1
  20. package/dist/device/hub.js +9 -0
  21. package/dist/device/hub.js.map +1 -1
  22. package/dist/device/humidifier.d.ts.map +1 -1
  23. package/dist/device/humidifier.js +6 -0
  24. package/dist/device/humidifier.js.map +1 -1
  25. package/dist/device/iosensor.d.ts.map +1 -1
  26. package/dist/device/iosensor.js +9 -0
  27. package/dist/device/iosensor.js.map +1 -1
  28. package/dist/device/lightstrip.d.ts.map +1 -1
  29. package/dist/device/lightstrip.js +3 -0
  30. package/dist/device/lightstrip.js.map +1 -1
  31. package/dist/device/lock.d.ts.map +1 -1
  32. package/dist/device/lock.js +12 -0
  33. package/dist/device/lock.js.map +1 -1
  34. package/dist/device/meter.d.ts.map +1 -1
  35. package/dist/device/meter.js +9 -0
  36. package/dist/device/meter.js.map +1 -1
  37. package/dist/device/meterplus.d.ts.map +1 -1
  38. package/dist/device/meterplus.js +9 -0
  39. package/dist/device/meterplus.js.map +1 -1
  40. package/dist/device/motion.d.ts.map +1 -1
  41. package/dist/device/motion.js +10 -1
  42. package/dist/device/motion.js.map +1 -1
  43. package/dist/device/plug.d.ts.map +1 -1
  44. package/dist/device/plug.js +4 -1
  45. package/dist/device/plug.js.map +1 -1
  46. package/dist/device/robotvacuumcleaner.d.ts.map +1 -1
  47. package/dist/device/robotvacuumcleaner.js +7 -1
  48. package/dist/device/robotvacuumcleaner.js.map +1 -1
  49. package/dist/device/waterdetector.d.ts.map +1 -1
  50. package/dist/device/waterdetector.js +6 -0
  51. package/dist/device/waterdetector.js.map +1 -1
  52. package/dist/irdevice/airconditioner.d.ts.map +1 -1
  53. package/dist/irdevice/airconditioner.js +8 -1
  54. package/dist/irdevice/airconditioner.js.map +1 -1
  55. package/dist/irdevice/airpurifier.d.ts.map +1 -1
  56. package/dist/irdevice/airpurifier.js +6 -0
  57. package/dist/irdevice/airpurifier.js.map +1 -1
  58. package/dist/irdevice/camera.d.ts.map +1 -1
  59. package/dist/irdevice/camera.js +3 -0
  60. package/dist/irdevice/camera.js.map +1 -1
  61. package/dist/irdevice/fan.d.ts.map +1 -1
  62. package/dist/irdevice/fan.js +3 -0
  63. package/dist/irdevice/fan.js.map +1 -1
  64. package/dist/irdevice/irdevice.d.ts +9 -0
  65. package/dist/irdevice/irdevice.d.ts.map +1 -1
  66. package/dist/irdevice/irdevice.js +29 -2
  67. package/dist/irdevice/irdevice.js.map +1 -1
  68. package/dist/irdevice/light.d.ts.map +1 -1
  69. package/dist/irdevice/light.js +9 -0
  70. package/dist/irdevice/light.js.map +1 -1
  71. package/dist/irdevice/other.d.ts +1 -1
  72. package/dist/irdevice/other.d.ts.map +1 -1
  73. package/dist/irdevice/other.js +36 -16
  74. package/dist/irdevice/other.js.map +1 -1
  75. package/dist/irdevice/tv.d.ts.map +1 -1
  76. package/dist/irdevice/tv.js +9 -0
  77. package/dist/irdevice/tv.js.map +1 -1
  78. package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
  79. package/dist/irdevice/vacuumcleaner.js +3 -0
  80. package/dist/irdevice/vacuumcleaner.js.map +1 -1
  81. package/dist/irdevice/waterheater.js +1 -1
  82. package/dist/irdevice/waterheater.js.map +1 -1
  83. package/package.json +1 -1
  84. package/src/device/blindtilt.ts +12 -0
  85. package/src/device/bot.ts +45 -1
  86. package/src/device/ceilinglight.ts +4 -0
  87. package/src/device/contact.ts +16 -0
  88. package/src/device/curtain.ts +12 -0
  89. package/src/device/fan.ts +12 -0
  90. package/src/device/hub.ts +12 -0
  91. package/src/device/humidifier.ts +8 -0
  92. package/src/device/iosensor.ts +12 -0
  93. package/src/device/lightstrip.ts +4 -0
  94. package/src/device/lock.ts +16 -0
  95. package/src/device/meter.ts +12 -0
  96. package/src/device/meterplus.ts +12 -0
  97. package/src/device/motion.ts +14 -2
  98. package/src/device/plug.ts +5 -1
  99. package/src/device/robotvacuumcleaner.ts +9 -1
  100. package/src/device/waterdetector.ts +8 -0
  101. package/src/irdevice/airconditioner.ts +11 -2
  102. package/src/irdevice/airpurifier.ts +8 -0
  103. package/src/irdevice/camera.ts +4 -0
  104. package/src/irdevice/fan.ts +4 -0
  105. package/src/irdevice/irdevice.ts +35 -2
  106. package/src/irdevice/light.ts +12 -0
  107. package/src/irdevice/other.ts +46 -14
  108. package/src/irdevice/tv.ts +12 -0
  109. package/src/irdevice/vacuumcleaner.ts +4 -0
  110. package/src/irdevice/waterheater.ts +1 -1
@@ -70,6 +70,10 @@ export class MeterPlus extends deviceBase {
70
70
 
71
71
  // Initialize Battery Service
72
72
  accessory.context.Battery = accessory.context.Battery ?? {};
73
+ if (accessory.context.Battery.Name) {
74
+ accessory.context.Battery.Name = this.validateAndCleanString(accessory.context.Battery.Name,
75
+ 'Battery Name', accessory.context.Battery.Name);
76
+ }
73
77
  this.Battery = {
74
78
  Name: accessory.context.Battery.Name ?? `${accessory.displayName} Battery`,
75
79
  Service: accessory.getService(this.hap.Service.Battery) ?? accessory.addService(this.hap.Service.Battery) as Service,
@@ -102,6 +106,10 @@ export class MeterPlus extends deviceBase {
102
106
  }
103
107
  } else {
104
108
  accessory.context.TemperatureSensor = accessory.context.TemperatureSensor ?? {};
109
+ if (accessory.context.TemperatureSensor.Name) {
110
+ accessory.context.TemperatureSensor.Name = this.validateAndCleanString(accessory.context.TemperatureSensor.Name,
111
+ 'TemperatureSensor Name', accessory.context.TemperatureSensor.Name);
112
+ }
105
113
  this.TemperatureSensor = {
106
114
  Name: accessory.context.TemperatureSensor.Name ?? `${accessory.displayName} Temperature Sensor`,
107
115
  Service: accessory.getService(this.hap.Service.TemperatureSensor) ?? this.accessory.addService(this.hap.Service.TemperatureSensor) as Service,
@@ -133,6 +141,10 @@ export class MeterPlus extends deviceBase {
133
141
  }
134
142
  } else {
135
143
  accessory.context.HumiditySensor = accessory.context.HumiditySensor ?? {};
144
+ if (accessory.context.HumiditySensor.Name) {
145
+ accessory.context.HumiditySensor.Name = this.validateAndCleanString(accessory.context.HumiditySensor.Name,
146
+ 'HumiditySensor Name', accessory.context.HumiditySensor.Name);
147
+ }
136
148
  this.HumiditySensor = {
137
149
  Name: accessory.context.HumiditySensor.Name ?? `${accessory.displayName} Humidity Sensor`,
138
150
  Service: accessory.getService(this.hap.Service.HumiditySensor) ?? this.accessory.addService(this.hap.Service.HumiditySensor) as Service,
@@ -69,6 +69,10 @@ export class Motion extends deviceBase {
69
69
 
70
70
  // Initialize Motion Sensor property
71
71
  accessory.context.MotionSensor = accessory.context.MotionSensor ?? {};
72
+ if (accessory.context.MotionSensor.Name) {
73
+ accessory.context.MotionSensor.Name = this.validateAndCleanString(accessory.context.MotionSensor.Name,
74
+ 'MotionSensor Name', accessory.context.MotionSensor.Name);
75
+ }
72
76
  this.MotionSensor = {
73
77
  Name: accessory.context.MotionSensor.Name ?? `${accessory.displayName} Motion Sensor`,
74
78
  Service: accessory.getService(this.hap.Service.MotionSensor) ?? accessory.addService(this.hap.Service.MotionSensor) as Service,
@@ -78,7 +82,7 @@ export class Motion extends deviceBase {
78
82
 
79
83
  // Initialize Motion Sensor Characteristics
80
84
  this.MotionSensor.Service
81
- .setCharacteristic(this.hap.Characteristic.Name, accessory.displayName)
85
+ .setCharacteristic(this.hap.Characteristic.Name, this.MotionSensor.Name)
82
86
  .setCharacteristic(this.hap.Characteristic.StatusActive, true)
83
87
  .getCharacteristic(this.hap.Characteristic.MotionDetected)
84
88
  .onGet(() => {
@@ -88,6 +92,10 @@ export class Motion extends deviceBase {
88
92
 
89
93
  // Initialize Battery Service
90
94
  accessory.context.Battery = accessory.context.Battery ?? {};
95
+ if (accessory.context.Battery.Name) {
96
+ accessory.context.Battery.Name = this.validateAndCleanString(accessory.context.Battery.Name,
97
+ 'Battery Name', accessory.context.Battery.Name);
98
+ }
91
99
  this.Battery = {
92
100
  Name: accessory.context.Battery.Name ?? `${accessory.displayName} Battery`,
93
101
  Service: accessory.getService(this.hap.Service.Battery) ?? accessory.addService(this.hap.Service.Battery) as Service,
@@ -121,6 +129,10 @@ export class Motion extends deviceBase {
121
129
  }
122
130
  } else {
123
131
  accessory.context.LightSensor = accessory.context.LightSensor ?? {};
132
+ if (accessory.context.LightSensor.Name) {
133
+ accessory.context.LightSensor.Name = this.validateAndCleanString(accessory.context.LightSensor.Name,
134
+ 'LightSensor Name', accessory.context.LightSensor.Name);
135
+ }
124
136
  this.LightSensor = {
125
137
  Name: accessory.context.LightSensor.Name ?? `${accessory.displayName} Light Sensor`,
126
138
  Service: accessory.getService(this.hap.Service.LightSensor) ?? this.accessory.addService(this.hap.Service.LightSensor) as Service,
@@ -130,7 +142,7 @@ export class Motion extends deviceBase {
130
142
 
131
143
  // Initialize LightSensor Characteristics
132
144
  this.LightSensor!.Service
133
- .setCharacteristic(this.hap.Characteristic.Name, this.LightSensor!.Name)
145
+ .setCharacteristic(this.hap.Characteristic.Name, this.LightSensor.Name)
134
146
  .setCharacteristic(this.hap.Characteristic.StatusActive, true)
135
147
  .getCharacteristic(this.hap.Characteristic.CurrentAmbientLightLevel)
136
148
  .onGet(() => {
@@ -49,6 +49,10 @@ export class Plug extends deviceBase {
49
49
 
50
50
  // Initialize Outlet Service
51
51
  accessory.context.Outlet = accessory.context.Outlet ?? {};
52
+ if (accessory.context.Outlet.Name) {
53
+ accessory.context.Outlet.Name = this.validateAndCleanString(accessory.context.Outlet.Name,
54
+ 'Outlet Name', accessory.context.Outlet.Name);
55
+ }
52
56
  this.Outlet = {
53
57
  Name: accessory.context.Outlet.Name ?? accessory.displayName,
54
58
  Service: accessory.getService(this.hap.Service.Outlet) ?? accessory.addService(this.hap.Service.Outlet) as Service,
@@ -58,7 +62,7 @@ export class Plug extends deviceBase {
58
62
 
59
63
  // Initialize Outlet Characteristics
60
64
  this.Outlet.Service
61
- .setCharacteristic(this.hap.Characteristic.Name, accessory.displayName)
65
+ .setCharacteristic(this.hap.Characteristic.Name, this.Outlet.Name)
62
66
  .getCharacteristic(this.hap.Characteristic.On)
63
67
  .onGet(() => {
64
68
  return this.Outlet.On;
@@ -63,6 +63,10 @@ export class RobotVacuumCleaner extends deviceBase {
63
63
 
64
64
  // Initialize Lightbulb Service
65
65
  accessory.context.LightBulb = accessory.context.LightBulb ?? {};
66
+ if (accessory.context.LightBulb.Name) {
67
+ accessory.context.LightBulb.Name = this.validateAndCleanString(accessory.context.LightBulb.Name,
68
+ 'LightBulb Name', accessory.context.LightBulb.Name);
69
+ }
66
70
  this.LightBulb = {
67
71
  Name: accessory.context.LightBulb.Name ?? accessory.displayName,
68
72
  Service: accessory.getService(this.hap.Service.Lightbulb) ?? accessory.addService(this.hap.Service.Lightbulb) as Service,
@@ -73,7 +77,7 @@ export class RobotVacuumCleaner extends deviceBase {
73
77
 
74
78
  // Initialize LightBulb Characteristics
75
79
  this.LightBulb.Service
76
- .setCharacteristic(this.hap.Characteristic.Name, accessory.displayName)
80
+ .setCharacteristic(this.hap.Characteristic.Name, this.LightBulb.Name)
77
81
  .getCharacteristic(this.hap.Characteristic.On)
78
82
  .onGet(() => {
79
83
  return this.LightBulb.On;
@@ -97,6 +101,10 @@ export class RobotVacuumCleaner extends deviceBase {
97
101
 
98
102
  // Initialize Battery Service
99
103
  accessory.context.Battery = accessory.context.Battery ?? {};
104
+ if (accessory.context.Battery.Name) {
105
+ accessory.context.Battery.Name = this.validateAndCleanString(accessory.context.Battery.Name,
106
+ 'Battery Name', accessory.context.Battery.Name);
107
+ }
100
108
  this.Battery = {
101
109
  Name: accessory.context.Battery.Name ?? `${accessory.displayName} Battery`,
102
110
  Service: accessory.getService(this.hap.Service.Battery) ?? accessory.addService(this.hap.Service.Battery) as Service,
@@ -64,6 +64,10 @@ export class WaterDetector extends deviceBase {
64
64
 
65
65
  // Initialize Battery Service
66
66
  accessory.context.Battery = accessory.context.Battery ?? {};
67
+ if (accessory.context.Battery.Name) {
68
+ accessory.context.Battery.Name = this.validateAndCleanString(accessory.context.Battery.Name,
69
+ 'Battery Name', accessory.context.Battery.Name);
70
+ }
67
71
  this.Battery = {
68
72
  Name: accessory.context.Battery.Name ?? `${accessory.displayName} Battery`,
69
73
  Service: accessory.getService(this.hap.Service.Battery) ?? accessory.addService(this.hap.Service.Battery) as Service,
@@ -99,6 +103,10 @@ export class WaterDetector extends deviceBase {
99
103
  }
100
104
  } else {
101
105
  accessory.context.LeakSensor = accessory.context.LeakSensor ?? {};
106
+ if (accessory.context.LeakSensor.Name) {
107
+ accessory.context.LeakSensor.Name = this.validateAndCleanString(accessory.context.LeakSensor.Name,
108
+ 'LeakSensor Name', accessory.context.LeakSensor.Name);
109
+ }
102
110
  this.LeakSensor = {
103
111
  Name: accessory.context.LeakSensor.Name ?? `${accessory.displayName} Leak Sensor`,
104
112
  Service: accessory.getService(this.hap.Service.LeakSensor) ?? this.accessory.addService(this.hap.Service.LeakSensor) as Service,
@@ -66,6 +66,10 @@ export class AirConditioner extends irdeviceBase {
66
66
 
67
67
  // Initialize HeaterCooler Service
68
68
  accessory.context.HeaterCooler = accessory.context.HeaterCooler ?? {};
69
+ if (accessory.context.HeaterCooler.Name) {
70
+ accessory.context.HeaterCooler.Name = this.validateAndCleanString(accessory.context.HeaterCooler.Name,
71
+ 'HeaterCooler Name', accessory.context.HeaterCooler.Name);
72
+ }
69
73
  this.HeaterCooler = {
70
74
  Name: accessory.context.HeaterCooler.Name ?? `${accessory.displayName} ${device.remoteType}`,
71
75
  Service: accessory.getService(this.hap.Service.HeaterCooler) ?? accessory.addService(this.hap.Service.HeaterCooler) as Service,
@@ -151,6 +155,10 @@ export class AirConditioner extends irdeviceBase {
151
155
  const meterUuid = this.platform.api.hap.uuid.generate(`${this.device.irair.meterId}-${this.device.irair.meterType}`);
152
156
  this.meter = this.platform.accessories.find((accessory) => accessory.UUID === meterUuid);
153
157
  accessory.context.HumiditySensor = accessory.context.HumiditySensor ?? {};
158
+ if (accessory.context.HumiditySensor.Name) {
159
+ accessory.context.HumiditySensor.Name = this.validateAndCleanString(accessory.context.HumiditySensor.Name,
160
+ 'HumiditySensor Name', accessory.context.HumiditySensor.Name);
161
+ }
154
162
  this.HumiditySensor = {
155
163
  Name: accessory.context.HumiditySensor ?? this.meter!.displayName,
156
164
  Service: this.meter!.getService(this.hap.Service.HumiditySensor) ?? this.meter!.addService(this.hap.Service.HumiditySensor) as Service,
@@ -164,8 +172,9 @@ export class AirConditioner extends irdeviceBase {
164
172
  this.meter = this.platform.accessories.find((accessory) => accessory.UUID === meterUuid);
165
173
  }
166
174
 
167
- if (this.meter) {
168
- this.HumiditySensor!.Service
175
+ if (this.meter && this.HumiditySensor) {
176
+ this.HumiditySensor.Service
177
+ .setCharacteristic(this.hap.Characteristic.Name, this.HumiditySensor.Name)
169
178
  .getCharacteristic(this.hap.Characteristic.CurrentRelativeHumidity)
170
179
  .onGet(async () => {
171
180
  return await this.CurrentRelativeHumidityGet();
@@ -59,6 +59,10 @@ export class AirPurifier extends irdeviceBase {
59
59
 
60
60
  // Initialize AirPurifier Service
61
61
  accessory.context.AirPurifier = accessory.context.AirPurifier ?? {};
62
+ if (accessory.context.AirPurifier.Name) {
63
+ accessory.context.AirPurifier.Name = this.validateAndCleanString(accessory.context.AirPurifier.Name,
64
+ 'AirPurifier Name', accessory.context.AirPurifier.Name);
65
+ }
62
66
  this.AirPurifier = {
63
67
  Name: accessory.context.AirPurifier.Name ?? `${accessory.displayName} Air Purifier`,
64
68
  Service: accessory.getService(this.hap.Service.AirPurifier) ?? accessory.addService(this.hap.Service.AirPurifier) as Service,
@@ -93,6 +97,10 @@ export class AirPurifier extends irdeviceBase {
93
97
 
94
98
  // Initialize TemperatureSensor Service
95
99
  accessory.context.TemperatureSensor = accessory.context.TemperatureSensor ?? {};
100
+ if (accessory.context.TemperatureSensor.Name) {
101
+ accessory.context.TemperatureSensor.Name = this.validateAndCleanString(accessory.context.TemperatureSensor.Name,
102
+ 'TemperatureSensor Name', accessory.context.TemperatureSensor.Name);
103
+ }
96
104
  this.TemperatureSensor = {
97
105
  Name: accessory.context.TemperatureSensor.Name ?? `${accessory.displayName} Temperature Sensor`,
98
106
  Service: accessory.getService(this.hap.Service.TemperatureSensor) ?? accessory.addService(this.hap.Service.TemperatureSensor) as Service,
@@ -33,6 +33,10 @@ export class Camera extends irdeviceBase {
33
33
 
34
34
  // Initialize Switch Service
35
35
  accessory.context.Switch = accessory.context.Switch ?? {};
36
+ if (accessory.context.Switch.Name) {
37
+ accessory.context.Switch.Name = this.validateAndCleanString(accessory.context.Switch.Name,
38
+ 'Switch Name', accessory.context.Switch.Name);
39
+ }
36
40
  this.Switch = {
37
41
  Name: accessory.context.Switch.Name ?? `${accessory.displayName} Camera`,
38
42
  Service: accessory.getService(this.hap.Service.Switch) ?? accessory.addService(this.hap.Service.Switch) as Service,
@@ -36,6 +36,10 @@ export class IRFan extends irdeviceBase {
36
36
 
37
37
  // Initialize Switch Service
38
38
  accessory.context.Fan = accessory.context.Fan ?? {};
39
+ if (accessory.context.Fan.Name) {
40
+ accessory.context.Fan.Name = this.validateAndCleanString(accessory.context.Fan.Name,
41
+ 'Fan Name', accessory.context.Fan.Name);
42
+ }
39
43
  this.Fan = {
40
44
  Name: accessory.context.Fan.Name ?? `${accessory.displayName} Fan`,
41
45
  Service: accessory.getService(this.hap.Service.Fanv2) ?? accessory.addService(this.hap.Service.Fanv2) as Service,
@@ -43,13 +43,20 @@ export abstract class irdeviceBase {
43
43
  .getService(this.hap.Service.AccessoryInformation)!
44
44
  .setCharacteristic(this.hap.Characteristic.Manufacturer, 'SwitchBot')
45
45
  .setCharacteristic(this.hap.Characteristic.AppMatchingIdentifier, 'id1087374760')
46
- .setCharacteristic(this.hap.Characteristic.Name, device.configDeviceName ?? device.deviceName ?? accessory.displayName)
47
- .setCharacteristic(this.hap.Characteristic.ConfiguredName, device.configDeviceName ?? device.deviceName ?? accessory.displayName)
46
+ .setCharacteristic(this.hap.Characteristic.Name, this.validName(accessory, device))
47
+ .setCharacteristic(this.hap.Characteristic.ConfiguredName, this.validName(accessory, device))
48
48
  .setCharacteristic(this.hap.Characteristic.Model, accessory.context.model ?? 'Unknown')
49
49
  .setCharacteristic(this.hap.Characteristic.ProductData, accessory.context.deviceId)
50
50
  .setCharacteristic(this.hap.Characteristic.SerialNumber, accessory.context.deviceId);
51
51
  }
52
52
 
53
+ public validName(accessory: PlatformAccessory, device: irdevice & irDevicesConfig) {
54
+ const Name = device.configDeviceName ?? device.deviceName ?? accessory.displayName;
55
+ const NameOfName = device.configDeviceName ? 'configDeviceName' : device.deviceName ? 'deviceName' : 'displayName';
56
+ const validName = this.validateAndCleanString(Name, NameOfName, Name);
57
+ return validName;
58
+ }
59
+
53
60
  async getDeviceLogSettings(device: irdevice & irDevicesConfig): Promise<void> {
54
61
  if (this.platform.debugMode) {
55
62
  this.deviceLogging = this.accessory.context.logging = 'debugMode';
@@ -346,6 +353,32 @@ export abstract class irdeviceBase {
346
353
  }
347
354
  }
348
355
 
356
+ /**
357
+ * Validate and clean a string value for a Name Characteristic.
358
+ * @param displayName
359
+ * @param name
360
+ * @param value
361
+ * @returns string value
362
+ */
363
+ validateAndCleanString(displayName: string, name: string, value: string): string {
364
+ const validPattern = /^[a-zA-Z0-9][a-zA-Z0-9 ']*[a-zA-Z0-9]$/;
365
+ const invalidCharsPattern = /[^a-zA-Z0-9 ']/g;
366
+
367
+ if (!validPattern.test(value)) {
368
+ this.warnLog(`WARNING: The accessory '${displayName}' has an invalid '${name}' characteristic ('${value}'). Please use only alphanumeric,`
369
+ + ' space, and apostrophe characters. Ensure it starts and ends with an alphabetic or numeric character, and avoid emojis. This may'
370
+ + ' prevent the accessory from being added in the Home App or cause unresponsiveness.');
371
+
372
+ // Remove invalid characters
373
+ value = value.replace(invalidCharsPattern, '');
374
+
375
+ // Ensure it starts and ends with an alphanumeric character
376
+ value = value.replace(/^[^a-zA-Z0-9]+|[^a-zA-Z0-9]+$/g, '');
377
+ }
378
+
379
+ return value;
380
+ }
381
+
349
382
  /**
350
383
  * Logging for Device
351
384
  */
@@ -48,6 +48,10 @@ export class Light extends irdeviceBase {
48
48
  if (!device.irlight?.stateless) {
49
49
  // Initialize LightBulb Service
50
50
  accessory.context.LightBulb = accessory.context.LightBulb ?? {};
51
+ if (accessory.context.LightBulb.Name) {
52
+ accessory.context.LightBulb.Name = this.validateAndCleanString(accessory.context.LightBulb.Name,
53
+ 'LightBulb Name', accessory.context.LightBulb.Name);
54
+ }
51
55
  this.LightBulb = {
52
56
  Name: accessory.context.LightBulb.Name ?? `${accessory.displayName} ${device.remoteType}`,
53
57
  Service: accessory.getService(this.hap.Service.Lightbulb) ?? accessory.addService(this.hap.Service.Lightbulb) as Service,
@@ -65,6 +69,10 @@ export class Light extends irdeviceBase {
65
69
  } else {
66
70
  // Initialize ProgrammableSwitchOn Service
67
71
  accessory.context.ProgrammableSwitchOn = accessory.context.ProgrammableSwitchOn ?? {};
72
+ if (accessory.context.ProgrammableSwitchOn.Name) {
73
+ accessory.context.ProgrammableSwitchOn.Name = this.validateAndCleanString(accessory.context.ProgrammableSwitchOn.Name,
74
+ 'ProgrammableSwitchOn Name', accessory.context.ProgrammableSwitchOn.Name);
75
+ }
68
76
  this.ProgrammableSwitchOn = {
69
77
  Name: accessory.context.ProgrammableSwitchOn.Name ?? `${accessory.displayName} ${device.remoteType} On`,
70
78
  Service: accessory.getService(this.hap.Service.StatefulProgrammableSwitch)
@@ -96,6 +104,10 @@ export class Light extends irdeviceBase {
96
104
 
97
105
  // Initialize ProgrammableSwitchOff Service
98
106
  accessory.context.ProgrammableSwitchOff = accessory.context.ProgrammableSwitchOff ?? {};
107
+ if (accessory.context.ProgrammableSwitchOff.Name) {
108
+ accessory.context.ProgrammableSwitchOff.Name = this.validateAndCleanString(accessory.context.ProgrammableSwitchOff.Name,
109
+ 'ProgrammableSwitchOff Name', accessory.context.ProgrammableSwitchOff.Name);
110
+ }
99
111
  this.ProgrammableSwitchOff = {
100
112
  Name: accessory.context.ProgrammableSwitchOff.Name ?? `${accessory.displayName} ${device.remoteType} Off`,
101
113
  Service: accessory.getService(this.hap.Service.StatefulProgrammableSwitch)
@@ -79,7 +79,7 @@ export class Others extends irdeviceBase {
79
79
  super(platform, accessory, device);
80
80
 
81
81
  // default placeholders
82
- this.getOtherConfigSettings(device);
82
+ this.getOtherConfigSettings(accessory, device);
83
83
 
84
84
  // deviceType
85
85
  if (this.otherDeviceType === 'switch') {
@@ -87,6 +87,10 @@ export class Others extends irdeviceBase {
87
87
  accessory.category = this.hap.Categories.SWITCH;
88
88
  // Initialize Switch Service
89
89
  accessory.context.Switch = accessory.context.Switch ?? {};
90
+ if (accessory.context.Switch.Name) {
91
+ accessory.context.Switch.Name = this.validateAndCleanString(accessory.context.Switch.Name,
92
+ 'Switch Name', accessory.context.Switch.Name);
93
+ }
90
94
  this.Switch = {
91
95
  Name: accessory.context.Switch.Name ?? accessory.displayName,
92
96
  Service: accessory.getService(this.hap.Service.Switch) ?? accessory.addService(this.hap.Service.Switch) as Service,
@@ -113,6 +117,10 @@ export class Others extends irdeviceBase {
113
117
  accessory.category = this.hap.Categories.GARAGE_DOOR_OPENER;
114
118
  // Initialize GarageDoor Service
115
119
  accessory.context.GarageDoor = accessory.context.GarageDoor ?? {};
120
+ if (accessory.context.GarageDoor.Name) {
121
+ accessory.context.GarageDoor.Name = this.validateAndCleanString(accessory.context.GarageDoor.Name,
122
+ 'GarageDoor Name', accessory.context.GarageDoor.Name);
123
+ }
116
124
  this.GarageDoor = {
117
125
  Name: accessory.context.GarageDoor.Name ?? accessory.displayName,
118
126
  Service: accessory.getService(this.hap.Service.GarageDoorOpener) ?? accessory.addService(this.hap.Service.GarageDoorOpener) as Service,
@@ -146,6 +154,10 @@ export class Others extends irdeviceBase {
146
154
  accessory.category = this.hap.Categories.DOOR;
147
155
  // Initialize Door Service
148
156
  accessory.context.Door = accessory.context.Door ?? {};
157
+ if (accessory.context.Door.Name) {
158
+ accessory.context.Door.Name = this.validateAndCleanString(accessory.context.Door.Name,
159
+ 'Door Name', accessory.context.Door.Name);
160
+ }
149
161
  this.Door = {
150
162
  Name: accessory.context.Door.Name ?? accessory.displayName,
151
163
  Service: accessory.getService(this.hap.Service.Door) ?? accessory.addService(this.hap.Service.Door) as Service,
@@ -178,6 +190,10 @@ export class Others extends irdeviceBase {
178
190
  accessory.category = this.hap.Categories.WINDOW;
179
191
  // Initialize Window Service
180
192
  accessory.context.Window = accessory.context.Window ?? {};
193
+ if (accessory.context.Window.Name) {
194
+ accessory.context.Window.Name = this.validateAndCleanString(accessory.context.Window.Name,
195
+ 'Window Name', accessory.context.Window.Name);
196
+ }
181
197
  this.Window = {
182
198
  Name: accessory.context.Window.Name ?? accessory.displayName,
183
199
  Service: accessory.getService(this.hap.Service.Window) ?? accessory.addService(this.hap.Service.Window) as Service,
@@ -210,6 +226,10 @@ export class Others extends irdeviceBase {
210
226
  accessory.category = this.hap.Categories.WINDOW_COVERING;
211
227
  // Initialize WindowCovering Service
212
228
  accessory.context.WindowCovering = accessory.context.WindowCovering ?? {};
229
+ if (accessory.context.WindowCovering.Name) {
230
+ accessory.context.WindowCovering.Name = this.validateAndCleanString(accessory.context.WindowCovering.Name,
231
+ 'WindowCovering Name', accessory.context.WindowCovering.Name);
232
+ }
213
233
  this.WindowCovering = {
214
234
  Name: accessory.context.WindowCovering.Name ?? accessory.displayName,
215
235
  Service: accessory.getService(this.hap.Service.WindowCovering) ?? accessory.addService(this.hap.Service.WindowCovering) as Service,
@@ -243,6 +263,10 @@ export class Others extends irdeviceBase {
243
263
  accessory.category = this.hap.Categories.DOOR_LOCK;
244
264
  // Initialize Lock Service
245
265
  accessory.context.LockMechanism = accessory.context.LockMechanism ?? {};
266
+ if (accessory.context.LockMechanism.Name) {
267
+ accessory.context.LockMechanism.Name = this.validateAndCleanString(accessory.context.LockMechanism.Name,
268
+ 'LockMechanism Name', accessory.context.LockMechanism.Name);
269
+ }
246
270
  this.LockMechanism = {
247
271
  Name: accessory.context.LockMechanism.Name ?? accessory.displayName,
248
272
  Service: accessory.getService(this.hap.Service.LockMechanism) ?? accessory.addService(this.hap.Service.LockMechanism) as Service,
@@ -270,6 +294,10 @@ export class Others extends irdeviceBase {
270
294
  accessory.category = this.hap.Categories.FAUCET;
271
295
  // Initialize Faucet Service
272
296
  accessory.context.Faucet = accessory.context.Faucet ?? {};
297
+ if (accessory.context.Faucet.Name) {
298
+ accessory.context.Faucet.Name = this.validateAndCleanString(accessory.context.Faucet.Name,
299
+ 'Faucet Name', accessory.context.Faucet.Name);
300
+ }
273
301
  this.Faucet = {
274
302
  Name: accessory.context.Faucet.Name ?? accessory.displayName,
275
303
  Service: accessory.getService(this.hap.Service.Faucet) ?? accessory.addService(this.hap.Service.Faucet) as Service,
@@ -296,6 +324,10 @@ export class Others extends irdeviceBase {
296
324
  accessory.category = this.hap.Categories.FAN;
297
325
  // Initialize Fan Service
298
326
  accessory.context.Fan = accessory.context.Fan ?? {};
327
+ if (accessory.context.Fan.Name) {
328
+ accessory.context.Fan.Name = this.validateAndCleanString(accessory.context.Fan.Name,
329
+ 'Fan Name', accessory.context.Fan.Name);
330
+ }
299
331
  this.Fan = {
300
332
  Name: accessory.context.Fan.Name ?? accessory.displayName,
301
333
  Service: accessory.getService(this.hap.Service.Fanv2) ?? accessory.addService(this.hap.Service.Fanv2) as Service,
@@ -322,6 +354,10 @@ export class Others extends irdeviceBase {
322
354
  accessory.category = this.hap.Categories.PROGRAMMABLE_SWITCH;
323
355
  // Initialize StatefulProgrammableSwitch Service
324
356
  accessory.context.StatefulProgrammableSwitch = accessory.context.StatefulProgrammableSwitch ?? {};
357
+ if (accessory.context.StatefulProgrammableSwitch.Name) {
358
+ accessory.context.StatefulProgrammableSwitch.Name = this.validateAndCleanString(accessory.context.StatefulProgrammableSwitch.Name,
359
+ 'StatefulProgrammableSwitch Name', accessory.context.StatefulProgrammableSwitch.Name);
360
+ }
325
361
  this.StatefulProgrammableSwitch = {
326
362
  Name: accessory.context.StatefulProgrammableSwitch.Name ?? accessory.displayName,
327
363
  Service: accessory.getService(this.hap.Service.StatefulProgrammableSwitch)
@@ -349,6 +385,10 @@ export class Others extends irdeviceBase {
349
385
  accessory.category = this.hap.Categories.OUTLET;
350
386
  // Initialize Switch property
351
387
  accessory.context.Outlet = accessory.context.Outlet ?? {};
388
+ if (accessory.context.Outlet.Name) {
389
+ accessory.context.Outlet.Name = this.validateAndCleanString(accessory.context.Outlet.Name,
390
+ 'Outlet Name', accessory.context.Outlet.Name);
391
+ }
352
392
  this.Outlet = {
353
393
  Name: accessory.context.Outlet.Name ?? accessory.displayName,
354
394
  Service: accessory.getService(this.hap.Service.Outlet) ?? accessory.addService(this.hap.Service.Outlet) as Service,
@@ -829,18 +869,10 @@ export class Others extends irdeviceBase {
829
869
  accessory.removeService(this.Switch.Service);
830
870
  }
831
871
 
832
- async getOtherConfigSettings(device: irdevice & irDevicesConfig): Promise<void> {
833
- if (!device.other?.deviceType && this.accessory.context.deviceType) {
834
- this.otherDeviceType = this.accessory.context.deviceType;
835
- await this.debugWarnLog(`Using Device Type: ${this.otherDeviceType}, from Accessory Cache.`);
836
- } else if (device.other?.deviceType) {
837
- this.accessory.context.deviceType = device.other.deviceType;
838
- await this.debugWarnLog(`Accessory Cache: ${this.accessory.context.deviceType}`);
839
- this.otherDeviceType = this.accessory.context.deviceType;
840
- await this.debugWarnLog(`Using Device Type: ${this.otherDeviceType}`);
841
- } else {
842
- this.otherDeviceType = 'outlet';
843
- this.warnLog(`no deviceType set, using default deviceType: ${this.otherDeviceType}`);
844
- }
872
+ async getOtherConfigSettings(accessory: PlatformAccessory, device: irdevice & irDevicesConfig): Promise<void> {
873
+ this.otherDeviceType = accessory.context.otherDeviceType ? accessory.context.otherDeviceType
874
+ : device.other?.deviceType ? device.other.deviceType : 'outlet';
875
+ const deviceType = accessory.context.otherDeviceType ? 'Accessory Cache': device.other?.deviceType ? 'Device Config' : 'Default';
876
+ await this.debugLog(`Use ${deviceType} Type: ${this.otherDeviceType}`);
845
877
  }
846
878
  }
@@ -45,6 +45,14 @@ export class TV extends irdeviceBase {
45
45
 
46
46
  // Initialize Television Service
47
47
  accessory.context.Television = accessory.context.Television ?? {};
48
+ if (accessory.context.Television.Name) {
49
+ accessory.context.Television.Name = this.validateAndCleanString(accessory.context.Television.Name,
50
+ 'Television Name', accessory.context.Television.Name);
51
+ }
52
+ if (accessory.context.Television.ConfiguredName) {
53
+ accessory.context.Television.ConfiguredName = this.validateAndCleanString(accessory.context.Television.ConfiguredName,
54
+ 'Television ConfiguredName', accessory.context.Television.ConfiguredName);
55
+ }
48
56
  this.Television = {
49
57
  Name: accessory.context.Television.Name ?? `${accessory.displayName} ${device.remoteType}`,
50
58
  ConfiguredName: accessory.context.Television.ConfiguredName ?? `${accessory.displayName} ${device.remoteType}`,
@@ -104,6 +112,10 @@ export class TV extends irdeviceBase {
104
112
 
105
113
  // Initialize TelevisionSpeaker Service
106
114
  accessory.context.TelevisionSpeaker = accessory.context.TelevisionSpeaker ?? {};
115
+ if (accessory.context.TelevisionSpeaker.Name) {
116
+ accessory.context.TelevisionSpeaker.Name = this.validateAndCleanString(accessory.context.TelevisionSpeaker.Name,
117
+ 'TelevisionSpeaker Name', accessory.context.TelevisionSpeaker.Name);
118
+ }
107
119
  this.TelevisionSpeaker = {
108
120
  Name: accessory.context.TelevisionSpeaker.Name ?? `${accessory.displayName} ${device.remoteType} Speaker`,
109
121
  Service: accessory.getService(this.hap.Service.TelevisionSpeaker) ?? accessory.addService(this.hap.Service.TelevisionSpeaker) as Service,
@@ -33,6 +33,10 @@ export class VacuumCleaner extends irdeviceBase {
33
33
 
34
34
  // Initialize Switch Service
35
35
  accessory.context.Switch = accessory.context.Switch ?? {};
36
+ if (accessory.context.Switch.Name) {
37
+ accessory.context.Switch.Name = this.validateAndCleanString(accessory.context.Switch.Name,
38
+ 'Switch Name', accessory.context.Switch.Name);
39
+ }
36
40
  this.Switch = {
37
41
  Name: accessory.context.Switch.Name ?? `${accessory.displayName} ${device.remoteType}`,
38
42
  Service: accessory.getService(this.hap.Service.Switch) ?? accessory.addService(this.hap.Service.Switch) as Service,
@@ -41,7 +41,7 @@ export class WaterHeater extends irdeviceBase {
41
41
  accessory.context.Valve = this.Valve as object;
42
42
 
43
43
  this.Valve.Service
44
- .setCharacteristic(this.hap.Characteristic.Name, accessory.displayName)
44
+ .setCharacteristic(this.hap.Characteristic.Name, this.Valve.Name)
45
45
  .setCharacteristic(this.hap.Characteristic.ValveType, this.hap.Characteristic.ValveType.GENERIC_VALVE)
46
46
  .getCharacteristic(this.hap.Characteristic.Active)
47
47
  .onGet(() => {