Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions ADVANCED_OPTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Before configuring, you may need to:
- `category` - **optional**: Device category code. See [SUPPORTED_DEVICES.md](./SUPPORTED_DEVICES.md). Also you can use `hidden` to hide the device, product, or scene. **⚠️Overriding this property may lead to unexpected behaviors and exceptions, so please remove the accessory cache after making changes.**
- `unbridged` - **optional**: Unbridge accessories. Defaults to `false`.
- `adaptiveLighting` - **optional**: Adaptive Lighting. Defaults to `false`. Not all light device support this feature, please use it on demand.
- `garageDoorUseContactSensorForState` - **optional**: For garage door controllers. When `true`, `CurrentDoorState` and `TargetDoorState` reads use `doorcontact_state` only, while set commands still use `switch_1`. Defaults to `false`.
- `schema` - **optional**: An array of schema overriding config objects, used for describing datapoint (DP). When your device has non-standard DP, you need to transform them manually with configuration. Each element in the schema array is described as follows:
- `code` - **required**: DP code.
- `newCode` - **optional**: New DP code.
Expand Down Expand Up @@ -94,6 +95,22 @@ An example of hide camera's floodlight (`floodlight_switch`):
}
```

### Use garage door contact sensor for state

Some `ckmkzq` garage door controllers keep `switch_1` as `true`, which can make HomeKit show the door as stuck Opening or Closing. Enable this per-device option to read the door state from `doorcontact_state`, while commands are still sent to `switch_1`.

```js
{
"options": {
// ...
"deviceOverrides": [{
"id": "{device_id}",
"garageDoorUseContactSensorForState": true
}]
}
}
```


### Offline as off

Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ Before you can configure, you must go to the [Tuya IoT Platform](https://iot.tuy
#### Advanced options
See [ADVANCED_OPTIONS.md](./ADVANCED_OPTIONS.md)

Garage door controllers that keep `switch_1=true` can opt in to contact-sensor-only state reads with `garageDoorUseContactSensorForState` in `options.deviceOverrides`. This keeps commands on `switch_1`, but reads HomeKit state from `doorcontact_state`.


## Limitations
- **⚠️Don't forget to extend the API trial period every 6 months. Maybe you can set up a reminder in calendar.**
Expand Down
11 changes: 11 additions & 0 deletions config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,14 @@
"functionBody": "return (model.options && model.options.deviceOverrides);"
}
},
"garageDoorUseContactSensorForState": {
"title": "Use Contact Sensor For Garage Door State",
"description": "For garage door controllers only. Derive CurrentDoorState and TargetDoorState reads from doorcontact_state instead of switch_1.",
"type": "boolean",
"condition": {
"functionBody": "return (model.options && model.options.deviceOverrides);"
}
},
"schema": {
"title": "Schema Overriding Configs",
"type": "array",
Expand Down Expand Up @@ -425,6 +433,9 @@
{
"key": "options.deviceOverrides[].unbridged"
},
{
"key": "options.deviceOverrides[].garageDoorUseContactSensorForState"
},
{
"key": "options.deviceOverrides[].schema",
"add": "Add New Schema",
Expand Down
31 changes: 27 additions & 4 deletions src/accessory/GarageDoorAccessory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,41 @@ export default class GarageDoorAccessory extends BaseAccessory {
}

configureServices() {

this.configureCurrentDoorState();
this.configureTargetDoorState();
}


mainService() {
return this.accessory.getService(this.Service.GarageDoorOpener)
|| this.accessory.addService(this.Service.GarageDoorOpener);
}

useContactSensorForState() {
return this.platform.getDeviceConfig(this.device)?.garageDoorUseContactSensorForState === true;
}

configureCurrentDoorState() {
const { OPEN, CLOSED, OPENING, CLOSING, STOPPED } = this.Characteristic.CurrentDoorState;
this.mainService().getCharacteristic(this.Characteristic.CurrentDoorState)
.onGet(() => {
const currentSchema = this.getSchema(...SCHEMA_CODE.CURRENT_DOOR_STATE);
const targetSchema = this.getSchema(...SCHEMA_CODE.TARGET_DOOR_STATE);
if (!currentSchema || !targetSchema) {
if (!currentSchema) {
return STOPPED;
}

const currentStatus = this.getStatus(currentSchema.code)!;

if (this.useContactSensorForState()) {
return currentStatus.value === false ? CLOSED : OPEN;
}

const targetSchema = this.getSchema(...SCHEMA_CODE.TARGET_DOOR_STATE);
if (!targetSchema) {
return STOPPED;
}

const targetStatus = this.getStatus(targetSchema.code)!;

if (currentStatus.value === true && targetStatus.value === true) {
return OPEN;
} else if (currentStatus.value === false && targetStatus.value === false) {
Expand All @@ -58,6 +70,17 @@ export default class GarageDoorAccessory extends BaseAccessory {
const { OPEN, CLOSED } = this.Characteristic.TargetDoorState;
this.mainService().getCharacteristic(this.Characteristic.TargetDoorState)
.onGet(() => {
if (this.useContactSensorForState()) {
const currentSchema = this.getSchema(...SCHEMA_CODE.CURRENT_DOOR_STATE);

if (!currentSchema) {
return CLOSED;
}

const currentStatus = this.getStatus(currentSchema.code)!;
return currentStatus.value === false ? CLOSED : OPEN;
}

const status = this.getStatus(schema.code)!;
return status.value as boolean ? OPEN : CLOSED;
})
Expand Down
1 change: 1 addition & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export interface TuyaPlatformDeviceConfig {
schema?: Array<TuyaPlatformDeviceSchemaConfig>;
unbridged?: boolean;
adaptiveLighting?: boolean;
garageDoorUseContactSensorForState?: boolean;
}

export interface TuyaPlatformServiceInformationConfig {
Expand Down
Loading