homebridge-tuya-without-developer-account 1.0.6 → 1.0.7

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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.7
4
+
5
+ - Added Smart Pet Feeder support for `quick_feed`, `manual_feed`, `slow_feed`, `feed_state`, battery, and charging state.
6
+ - Added optional `deviceOverrides[].petFeeder.manualFeedAmount` and `deviceOverrides[].petFeeder.exposeSlowFeed`.
7
+ - Added Tuya alarm panel support as a HomeKit Security System using `master_mode`, `master_state`, and optional tamper/battery DPs.
8
+ - Added optional `deviceOverrides[].alarm` fields for alarm sound, muffling, and notification switches.
9
+ - Added clearer logging when Tuya returns an empty schema for aroma diffusers. Diffuser scenes remain exposed separately.
10
+
3
11
  ## 1.0.6
4
12
 
5
13
  - Fixed a Homebridge UI issue where clicking **Save Configuration** could leave the custom settings page spinner running indefinitely even when QR authentication data had already been saved.
package/README.md CHANGED
@@ -313,3 +313,10 @@ If this still happens after upgrading, open the plugin settings, clear the saved
313
313
 
314
314
  Version **1.0.5** adds support for DP10-style Tuya dimmer plugs that expose `switch_led` and `bright_value_v2`. These are exposed in HomeKit as Lightbulb accessories with On and Brightness. If the accessory was previously shown as **Not Supported**, remove only that cached accessory in Homebridge UI and restart Homebridge after upgrading.
315
315
 
316
+
317
+
318
+ ## Version 1.0.7 device support
319
+
320
+ This release adds native support for Tuya Smart Pet Feeders and Tuya alarm panels that expose `master_mode`. Pet feeders expose quick/manual feed controls, optional slow-feed control, feed-state sensor, and battery when available. Alarm panels are exposed as HomeKit Security System accessories, with optional extra switches controlled through `deviceOverrides[].alarm`.
321
+
322
+ Aroma diffuser devices whose Tuya QR cloud schema is empty remain visible as unsupported direct devices, but any diffuser scenes returned by Tuya are still exposed separately.
@@ -214,3 +214,18 @@ Supported from **v1.0.5**. These devices normally report category `tgq` and expo
214
214
 
215
215
  They are exposed to HomeKit as a Lightbulb with On and Brightness. After upgrading from an older version where the device showed as unsupported, remove the affected cached accessory from Homebridge UI and restart Homebridge.
216
216
 
217
+
218
+
219
+ ## Added in 1.0.7
220
+
221
+ ### Smart Pet Feeder
222
+
223
+ Supported when Tuya exposes one or more of: `quick_feed`, `manual_feed`, `slow_feed`, `feed_state`, `battery_percentage`, `charge_state`.
224
+
225
+ ### Alarm / Security System
226
+
227
+ Supported when Tuya exposes `master_mode`. Alarm-triggered state is detected from `master_state=alarm`, `sos_state=true`, or `master_mode=sos` when available. Optional extra switches can be enabled through `deviceOverrides[].alarm`.
228
+
229
+ ### Aroma Diffuser with Empty Schema
230
+
231
+ If Tuya QR cloud returns an empty schema for the diffuser device, direct device control cannot be mapped. The plugin keeps diffuser Tuya scenes exposed and logs a clearer explanation.
@@ -110,6 +110,49 @@
110
110
  "default": 1
111
111
  }
112
112
  }
113
+ },
114
+ "petFeeder": {
115
+ "type": "object",
116
+ "title": "Smart Pet Feeder Options",
117
+ "description": "Optional settings for Tuya pet feeders. The plugin exposes quick/manual feed switches, feed-state sensor, and battery when supported.",
118
+ "properties": {
119
+ "manualFeedAmount": {
120
+ "type": "integer",
121
+ "title": "Manual feed amount",
122
+ "description": "Portions sent when the Manual Feed switch is turned on.",
123
+ "minimum": 1,
124
+ "maximum": 12,
125
+ "default": 1
126
+ },
127
+ "exposeSlowFeed": {
128
+ "type": "boolean",
129
+ "title": "Expose Slow Feed switch",
130
+ "description": "Expose slow_feed as a HomeKit switch when the device supports it.",
131
+ "default": true
132
+ }
133
+ }
134
+ },
135
+ "alarm": {
136
+ "type": "object",
137
+ "title": "Alarm Options",
138
+ "description": "Optional extra switches for Tuya alarm panels. The main alarm is exposed as a HomeKit Security System when master_mode is available.",
139
+ "properties": {
140
+ "exposeAlarmSoundSwitch": {
141
+ "type": "boolean",
142
+ "title": "Expose Alarm Sound switch",
143
+ "default": false
144
+ },
145
+ "exposeMufflingSwitch": {
146
+ "type": "boolean",
147
+ "title": "Expose Mute/Muffling switch",
148
+ "default": false
149
+ },
150
+ "exposeNotificationSwitches": {
151
+ "type": "boolean",
152
+ "title": "Expose Call/SMS/App/Low Battery switches",
153
+ "default": false
154
+ }
155
+ }
113
156
  }
114
157
  },
115
158
  "required": [
package/dist/platform.js CHANGED
@@ -122,6 +122,34 @@ class TuyaPlatform {
122
122
  delete item.airConditioner;
123
123
  }
124
124
  }
125
+ if (item.petFeeder && typeof item.petFeeder === 'object') {
126
+ const normalizedPetFeeder = {};
127
+ const manualFeedAmount = Number(item.petFeeder.manualFeedAmount);
128
+ if (Number.isFinite(manualFeedAmount)) {
129
+ normalizedPetFeeder.manualFeedAmount = Math.max(1, Math.min(12, Math.round(manualFeedAmount)));
130
+ }
131
+ if (typeof item.petFeeder.exposeSlowFeed === 'boolean') {
132
+ normalizedPetFeeder.exposeSlowFeed = item.petFeeder.exposeSlowFeed;
133
+ }
134
+ if (Object.keys(normalizedPetFeeder).length > 0) {
135
+ item.petFeeder = normalizedPetFeeder;
136
+ } else {
137
+ delete item.petFeeder;
138
+ }
139
+ }
140
+ if (item.alarm && typeof item.alarm === 'object') {
141
+ const normalizedAlarm = {};
142
+ for (const key of ['exposeAlarmSoundSwitch', 'exposeMufflingSwitch', 'exposeNotificationSwitches']) {
143
+ if (typeof item.alarm[key] === 'boolean') {
144
+ normalizedAlarm[key] = item.alarm[key];
145
+ }
146
+ }
147
+ if (Object.keys(normalizedAlarm).length > 0) {
148
+ item.alarm = normalizedAlarm;
149
+ } else {
150
+ delete item.alarm;
151
+ }
152
+ }
125
153
  seenIds.add(id);
126
154
  validOverrides.push(item);
127
155
  }
@@ -249,6 +277,8 @@ class TuyaPlatform {
249
277
  unbridged: deviceConfig?.unbridged ?? false,
250
278
  schemaOverrides: deviceConfig?.schema ? JSON.stringify(deviceConfig.schema) : undefined,
251
279
  airConditioner: deviceConfig?.airConditioner ? JSON.stringify(deviceConfig.airConditioner) : undefined,
280
+ petFeeder: deviceConfig?.petFeeder ? JSON.stringify(deviceConfig.petFeeder) : undefined,
281
+ alarm: deviceConfig?.alarm ? JSON.stringify(deviceConfig.alarm) : undefined,
252
282
  adaptiveLighting: deviceConfig?.adaptiveLighting ?? false,
253
283
  };
254
284
  const { changed: configChanged } = this.configHash.hasConfigChanged(device.id, configToHash);
@@ -23,6 +23,13 @@ class DiffuserAccessory extends BaseAccessory_1.default {
23
23
  requiredSchema() {
24
24
  return [SCHEMA_CODE.SPRAY_ON];
25
25
  }
26
+
27
+ checkRequirements() {
28
+ if (this.device && Array.isArray(this.device.schema) && this.device.schema.length === 0) {
29
+ this.log.warn('Tuya returned an empty schema for this diffuser. Direct diffuser control cannot be mapped until Tuya exposes switch_spray or equivalent DPs. Any Tuya scenes for this diffuser will still be exposed separately.');
30
+ }
31
+ return super.checkRequirements();
32
+ }
26
33
  configureServices() {
27
34
  // Main Switch
28
35
  (0, On_1.configureOn)(this, undefined, this.getSchema(...SCHEMA_CODE.ON));
@@ -4,136 +4,107 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const BaseAccessory_1 = __importDefault(require("./BaseAccessory"));
7
- const Active_1 = require("./characteristic/Active");
7
+ const Name_1 = require("./characteristic/Name");
8
8
  const SCHEMA_CODE = {
9
- ACTIVE: ['switch'],
10
- LIGHT: ['light'],
11
9
  QUICK_FEED: ['quick_feed'],
12
10
  SLOW_FEED: ['slow_feed'],
13
11
  MANUAL_FEED: ['manual_feed'],
14
- MEAL_PLAN: ['meal_plan'],
15
- BATTERY_PERCENTAGE: ['battery_percentage'],
16
- FEED_REPORT: ['feed_report'],
17
12
  FEED_STATE: ['feed_state'],
18
13
  };
19
14
  class PetFeederAccessory extends BaseAccessory_1.default {
20
15
  requiredSchema() {
21
- return [SCHEMA_CODE.ACTIVE];
16
+ // Tuya pet feeders often do not expose a generic "switch" DP. A feeder is
17
+ // considered supported when it has at least one command DP we can expose.
18
+ return [[...SCHEMA_CODE.QUICK_FEED, ...SCHEMA_CODE.MANUAL_FEED, ...SCHEMA_CODE.SLOW_FEED]];
19
+ }
20
+ getPetFeederConfig() {
21
+ const config = this.device ? this.platform.getDeviceConfig(this.device) : undefined;
22
+ const feeder = (config && typeof config.petFeeder === 'object') ? config.petFeeder : {};
23
+ const manualFeedAmount = Number(feeder.manualFeedAmount);
24
+ return {
25
+ manualFeedAmount: Number.isFinite(manualFeedAmount) ? Math.max(1, Math.min(12, Math.round(manualFeedAmount))) : 1,
26
+ exposeSlowFeed: feeder.exposeSlowFeed !== false,
27
+ };
22
28
  }
23
29
  configureServices() {
24
- (0, Active_1.configureActive)(this, this.mainService(), this.getSchema(...SCHEMA_CODE.ACTIVE));
25
- this.configureLight();
26
30
  this.configureQuickFeed();
27
- this.configureSlowFeed();
28
31
  this.configureManualFeed();
29
- this.configureMealPlan();
30
- this.configureBatteryPercentage();
31
- this.configureFeedReport();
32
+ this.configureSlowFeed();
32
33
  this.configureFeedState();
33
34
  }
34
- mainService() {
35
- return this.accessory.getService(this.Service.Switch)
36
- || this.accessory.addService(this.Service.Switch);
37
- }
38
- configureLight() {
39
- const schema = this.getSchema(...SCHEMA_CODE.LIGHT);
40
- if (!schema) {
41
- this.log.warn('Light is not supported.');
42
- return;
43
- }
44
- this.mainService().getCharacteristic(this.Characteristic.On)
45
- .onSet(async (value) => {
46
- await this.sendCommands([{ code: schema.code, value: value }]);
47
- });
48
- }
49
- configureQuickFeed() {
50
- const schema = this.getSchema(...SCHEMA_CODE.QUICK_FEED);
35
+ configureActionSwitch(schema, name, subtype, onSet) {
51
36
  if (!schema) {
52
- this.log.warn('Quick feed is not supported.');
53
37
  return;
54
38
  }
55
- this.mainService().getCharacteristic(this.Characteristic.On)
39
+ const service = this.accessory.getServiceById(this.Service.Switch, subtype)
40
+ || this.accessory.addService(this.Service.Switch, name, subtype);
41
+ (0, Name_1.configureName)(this, service, name);
42
+ service.getCharacteristic(this.Characteristic.On)
43
+ .onGet(() => {
44
+ this.checkOnlineStatus();
45
+ // quick_feed/manual_feed are momentary actions. Always display them as off.
46
+ return false;
47
+ })
56
48
  .onSet(async (value) => {
57
49
  if (value) {
58
- await this.sendCommands([{ code: schema.code, value: true }]);
50
+ await onSet();
59
51
  }
52
+ setTimeout(() => service.getCharacteristic(this.Characteristic.On).updateValue(false), 500);
60
53
  });
61
54
  }
62
- configureSlowFeed() {
63
- const schema = this.getSchema(...SCHEMA_CODE.SLOW_FEED);
55
+ configureBooleanSwitch(schema, name, subtype) {
64
56
  if (!schema) {
65
- this.log.warn('Slow feed is not supported.');
66
57
  return;
67
58
  }
68
- this.mainService().getCharacteristic(this.Characteristic.On)
69
- .onSet(async (value) => {
70
- if (value) {
71
- await this.sendCommands([{ code: schema.code, value: true }]);
72
- }
73
- });
74
- }
75
- configureManualFeed() {
76
- const schema = this.getSchema(...SCHEMA_CODE.MANUAL_FEED);
77
- if (!schema) {
78
- this.log.warn('Manual feed is not supported.');
79
- return;
80
- }
81
- this.mainService().getCharacteristic(this.Characteristic.On)
59
+ const service = this.accessory.getServiceById(this.Service.Switch, subtype)
60
+ || this.accessory.addService(this.Service.Switch, name, subtype);
61
+ (0, Name_1.configureName)(this, service, name);
62
+ service.getCharacteristic(this.Characteristic.On)
63
+ .onGet(() => {
64
+ this.checkOnlineStatus();
65
+ return !!(this.getStatus(schema.code)?.value ?? false);
66
+ })
82
67
  .onSet(async (value) => {
83
- if (value) {
84
- await this.sendCommands([{ code: schema.code, value: 1 }]);
85
- }
68
+ await this.sendCommands([{ code: schema.code, value: !!value }], true);
86
69
  });
87
70
  }
88
- configureMealPlan() {
89
- const schema = this.getSchema(...SCHEMA_CODE.MEAL_PLAN);
90
- if (!schema) {
91
- this.log.warn('Meal plan is not supported.');
92
- return;
93
- }
94
- this.mainService().getCharacteristic(this.Characteristic.On)
95
- .onSet(async (value) => {
96
- if (value) {
97
- await this.sendCommands([{ code: schema.code, value: value }]);
98
- }
71
+ configureQuickFeed() {
72
+ const schema = this.getSchema(...SCHEMA_CODE.QUICK_FEED);
73
+ this.configureActionSwitch(schema, `${this.device?.name || 'Pet Feeder'} Quick Feed`, 'quick_feed', async () => {
74
+ await this.sendCommands([{ code: schema.code, value: true }], true);
99
75
  });
100
76
  }
101
- configureBatteryPercentage() {
102
- const schema = this.getSchema(...SCHEMA_CODE.BATTERY_PERCENTAGE);
103
- if (!schema) {
104
- this.log.warn('Battery percentage is not supported.');
105
- return;
106
- }
107
- this.mainService().getCharacteristic(this.Characteristic.BatteryLevel)
108
- .onGet(() => {
109
- const status = this.getStatus(schema.code);
110
- return status.value;
77
+ configureManualFeed() {
78
+ const schema = this.getSchema(...SCHEMA_CODE.MANUAL_FEED);
79
+ const { manualFeedAmount } = this.getPetFeederConfig();
80
+ this.configureActionSwitch(schema, `${this.device?.name || 'Pet Feeder'} Manual Feed`, 'manual_feed', async () => {
81
+ await this.sendCommands([{ code: schema.code, value: manualFeedAmount }], true);
111
82
  });
112
83
  }
113
- configureFeedReport() {
114
- const schema = this.getSchema(...SCHEMA_CODE.FEED_REPORT);
115
- if (!schema) {
116
- this.log.warn('Feed report is not supported.');
84
+ configureSlowFeed() {
85
+ const schema = this.getSchema(...SCHEMA_CODE.SLOW_FEED);
86
+ const { exposeSlowFeed } = this.getPetFeederConfig();
87
+ if (!exposeSlowFeed) {
117
88
  return;
118
89
  }
119
- this.mainService().getCharacteristic(this.Characteristic.StatusActive)
120
- .onGet(() => {
121
- const status = this.getStatus(schema.code);
122
- return status.value;
123
- });
90
+ this.configureBooleanSwitch(schema, `${this.device?.name || 'Pet Feeder'} Slow Feed`, 'slow_feed');
124
91
  }
125
92
  configureFeedState() {
126
93
  const schema = this.getSchema(...SCHEMA_CODE.FEED_STATE);
127
94
  if (!schema) {
128
- this.log.warn('Feed state is not supported.');
129
95
  return;
130
96
  }
131
- this.mainService().getCharacteristic(this.Characteristic.StatusActive)
97
+ const service = this.accessory.getServiceById(this.Service.OccupancySensor, 'feed_state')
98
+ || this.accessory.addService(this.Service.OccupancySensor, `${this.device?.name || 'Pet Feeder'} Feeding`, 'feed_state');
99
+ (0, Name_1.configureName)(this, service, `${this.device?.name || 'Pet Feeder'} Feeding`);
100
+ const { OCCUPANCY_DETECTED, OCCUPANCY_NOT_DETECTED } = this.Characteristic.OccupancyDetected;
101
+ service.getCharacteristic(this.Characteristic.OccupancyDetected)
132
102
  .onGet(() => {
133
- const status = this.getStatus(schema.code);
134
- return status.value === 'feeding';
103
+ this.checkOnlineStatus();
104
+ const value = this.getStatus(schema.code)?.value;
105
+ return value === 'feeding' ? OCCUPANCY_DETECTED : OCCUPANCY_NOT_DETECTED;
135
106
  });
136
107
  }
137
108
  }
138
109
  exports.default = PetFeederAccessory;
139
- //# sourceMappingURL=PetFeederAccessory.js.map
110
+ //# sourceMappingURL=PetFeederAccessory.js.map
@@ -4,11 +4,19 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const BaseAccessory_1 = __importDefault(require("./BaseAccessory"));
7
- const SecuritySystemState_1 = require("./characteristic/SecuritySystemState");
8
7
  const Name_1 = require("./characteristic/Name");
9
8
  const SCHEMA_CODE = {
10
9
  MASTER_MODE: ['master_mode'],
10
+ MASTER_STATE: ['master_state'],
11
11
  SOS_STATE: ['sos_state'],
12
+ TAMPER_ALARM: ['temper_alarm', 'tamper_alarm'],
13
+ ALARM_SOUND: ['switch_alarm_sound'],
14
+ MUFFLING: ['muffling'],
15
+ ALARM_CALL: ['switch_alarm_call'],
16
+ ALARM_SMS: ['switch_alarm_sms'],
17
+ ALARM_PROPEL: ['switch_alarm_propel'],
18
+ LOW_BATTERY_ALERT: ['switch_low_battery'],
19
+ MODE_DELAY_SOUND: ['switch_mode_dl_sound'],
12
20
  };
13
21
  class SecuritySystemAccessory extends BaseAccessory_1.default {
14
22
  constructor() {
@@ -16,15 +24,146 @@ class SecuritySystemAccessory extends BaseAccessory_1.default {
16
24
  this.isNightArm = false;
17
25
  }
18
26
  requiredSchema() {
19
- return [SCHEMA_CODE.MASTER_MODE, SCHEMA_CODE.SOS_STATE];
27
+ // Some Tuya alarm panels expose master_mode + master_state, but not sos_state.
28
+ return [SCHEMA_CODE.MASTER_MODE];
29
+ }
30
+ getAlarmConfig() {
31
+ const config = this.device ? this.platform.getDeviceConfig(this.device) : undefined;
32
+ const alarm = (config && typeof config.alarm === 'object') ? config.alarm : {};
33
+ return {
34
+ exposeAlarmSoundSwitch: !!alarm.exposeAlarmSoundSwitch,
35
+ exposeMufflingSwitch: !!alarm.exposeMufflingSwitch,
36
+ exposeNotificationSwitches: !!alarm.exposeNotificationSwitches,
37
+ };
20
38
  }
21
39
  configureServices() {
22
40
  const service = this.accessory.getService(this.Service.SecuritySystem)
23
41
  || this.accessory.addService(this.Service.SecuritySystem);
24
42
  (0, Name_1.configureName)(this, service, this.device.name);
25
- (0, SecuritySystemState_1.configureSecuritySystemCurrentState)(this, service, this.getSchema(...SCHEMA_CODE.MASTER_MODE), this.getSchema(...SCHEMA_CODE.SOS_STATE));
26
- (0, SecuritySystemState_1.configureSecuritySystemTargetState)(this, service, this.getSchema(...SCHEMA_CODE.MASTER_MODE), this.getSchema(...SCHEMA_CODE.SOS_STATE));
43
+ this.configureCurrentState(service);
44
+ this.configureTargetState(service);
45
+ this.configureTamper(service);
46
+ this.configureExtraSwitches();
47
+ }
48
+ mapTuyaModeToHomeKit(value, current = true) {
49
+ const Current = this.Characteristic.SecuritySystemCurrentState;
50
+ const Target = this.Characteristic.SecuritySystemTargetState;
51
+ const map = current ? {
52
+ disarmed: Current.DISARMED,
53
+ arm: Current.AWAY_ARM,
54
+ home: this.isNightArm ? Current.NIGHT_ARM : Current.STAY_ARM,
55
+ sos: Current.ALARM_TRIGGERED,
56
+ } : {
57
+ disarmed: Target.DISARM,
58
+ arm: Target.AWAY_ARM,
59
+ home: this.isNightArm ? Target.NIGHT_ARM : Target.STAY_ARM,
60
+ sos: Target.AWAY_ARM,
61
+ };
62
+ return map[value] ?? (current ? Current.DISARMED : Target.DISARM);
63
+ }
64
+ mapHomeKitTargetToTuya(value) {
65
+ const Target = this.Characteristic.SecuritySystemTargetState;
66
+ switch (value) {
67
+ case Target.DISARM:
68
+ return 'disarmed';
69
+ case Target.STAY_ARM:
70
+ case Target.NIGHT_ARM:
71
+ return 'home';
72
+ case Target.AWAY_ARM:
73
+ default:
74
+ return 'arm';
75
+ }
76
+ }
77
+ isAlarmTriggered() {
78
+ const masterStateSchema = this.getSchema(...SCHEMA_CODE.MASTER_STATE);
79
+ if (masterStateSchema && this.getStatus(masterStateSchema.code)?.value === 'alarm') {
80
+ return true;
81
+ }
82
+ const sosStateSchema = this.getSchema(...SCHEMA_CODE.SOS_STATE);
83
+ if (sosStateSchema && this.getStatus(sosStateSchema.code)?.value) {
84
+ return true;
85
+ }
86
+ const masterModeSchema = this.getSchema(...SCHEMA_CODE.MASTER_MODE);
87
+ if (masterModeSchema && this.getStatus(masterModeSchema.code)?.value === 'sos') {
88
+ return true;
89
+ }
90
+ return false;
91
+ }
92
+ configureCurrentState(service) {
93
+ const masterModeSchema = this.getSchema(...SCHEMA_CODE.MASTER_MODE);
94
+ service.getCharacteristic(this.Characteristic.SecuritySystemCurrentState)
95
+ .onGet(() => {
96
+ this.checkOnlineStatus();
97
+ if (this.isAlarmTriggered()) {
98
+ return this.Characteristic.SecuritySystemCurrentState.ALARM_TRIGGERED;
99
+ }
100
+ return this.mapTuyaModeToHomeKit(this.getStatus(masterModeSchema.code)?.value, true);
101
+ });
102
+ }
103
+ configureTargetState(service) {
104
+ const masterModeSchema = this.getSchema(...SCHEMA_CODE.MASTER_MODE);
105
+ service.getCharacteristic(this.Characteristic.SecuritySystemTargetState)
106
+ .onGet(() => {
107
+ this.checkOnlineStatus();
108
+ return this.mapTuyaModeToHomeKit(this.getStatus(masterModeSchema.code)?.value, false);
109
+ })
110
+ .onSet(async (value) => {
111
+ this.isNightArm = value === this.Characteristic.SecuritySystemTargetState.NIGHT_ARM;
112
+ const commands = [{ code: masterModeSchema.code, value: this.mapHomeKitTargetToTuya(value) }];
113
+ const sosStateSchema = this.getSchema(...SCHEMA_CODE.SOS_STATE);
114
+ if (sosStateSchema && value === this.Characteristic.SecuritySystemTargetState.DISARM) {
115
+ commands.push({ code: sosStateSchema.code, value: false });
116
+ }
117
+ await this.sendCommands(commands, true);
118
+ });
119
+ }
120
+ configureTamper(service) {
121
+ const schema = this.getSchema(...SCHEMA_CODE.TAMPER_ALARM);
122
+ if (!schema) {
123
+ return;
124
+ }
125
+ if (!service.testCharacteristic(this.Characteristic.StatusTampered)) {
126
+ service.addOptionalCharacteristic(this.Characteristic.StatusTampered);
127
+ }
128
+ const { TAMPERED, NOT_TAMPERED } = this.Characteristic.StatusTampered;
129
+ service.getCharacteristic(this.Characteristic.StatusTampered)
130
+ .onGet(() => {
131
+ this.checkOnlineStatus();
132
+ return this.getStatus(schema.code)?.value ? TAMPERED : NOT_TAMPERED;
133
+ });
134
+ }
135
+ configureExtraSwitches() {
136
+ const config = this.getAlarmConfig();
137
+ if (config.exposeAlarmSoundSwitch) {
138
+ this.configureBooleanSwitch(this.getSchema(...SCHEMA_CODE.ALARM_SOUND), `${this.device.name} Alarm Sound`, 'switch_alarm_sound');
139
+ }
140
+ if (config.exposeMufflingSwitch) {
141
+ this.configureBooleanSwitch(this.getSchema(...SCHEMA_CODE.MUFFLING), `${this.device.name} Mute`, 'muffling');
142
+ }
143
+ if (config.exposeNotificationSwitches) {
144
+ this.configureBooleanSwitch(this.getSchema(...SCHEMA_CODE.ALARM_CALL), `${this.device.name} Alarm Call`, 'switch_alarm_call');
145
+ this.configureBooleanSwitch(this.getSchema(...SCHEMA_CODE.ALARM_SMS), `${this.device.name} Alarm SMS`, 'switch_alarm_sms');
146
+ this.configureBooleanSwitch(this.getSchema(...SCHEMA_CODE.ALARM_PROPEL), `${this.device.name} App Push`, 'switch_alarm_propel');
147
+ this.configureBooleanSwitch(this.getSchema(...SCHEMA_CODE.LOW_BATTERY_ALERT), `${this.device.name} Low Battery Alert`, 'switch_low_battery');
148
+ this.configureBooleanSwitch(this.getSchema(...SCHEMA_CODE.MODE_DELAY_SOUND), `${this.device.name} Mode Delay Sound`, 'switch_mode_dl_sound');
149
+ }
150
+ }
151
+ configureBooleanSwitch(schema, name, subtype) {
152
+ if (!schema) {
153
+ return;
154
+ }
155
+ const service = this.accessory.getServiceById(this.Service.Switch, subtype)
156
+ || this.accessory.addService(this.Service.Switch, name, subtype);
157
+ (0, Name_1.configureName)(this, service, name);
158
+ service.getCharacteristic(this.Characteristic.On)
159
+ .onGet(() => {
160
+ this.checkOnlineStatus();
161
+ return !!(this.getStatus(schema.code)?.value ?? false);
162
+ })
163
+ .onSet(async (value) => {
164
+ await this.sendCommands([{ code: schema.code, value: !!value }], true);
165
+ });
27
166
  }
28
167
  }
29
168
  exports.default = SecuritySystemAccessory;
30
- //# sourceMappingURL=SecuritySystemAccessory.js.map
169
+ //# sourceMappingURL=SecuritySystemAccessory.js.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "homebridge-tuya-without-developer-account",
3
3
  "displayName": "Tuya without developer account for Homebridge",
4
- "version": "1.0.6",
4
+ "version": "1.0.7",
5
5
  "description": "Homebridge plugin for Tuya and Smart Life devices using QR cloud authentication without a Tuya IoT developer account.",
6
6
  "license": "MIT",
7
7
  "author": "Kosztyk",