Skip to content

Commit

Permalink
feat: make supported device types configurable
Browse files Browse the repository at this point in the history
Closes #430
  • Loading branch information
o-lukas committed Dec 1, 2024
1 parent 784d906 commit a013106
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 17 deletions.
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,13 @@ The following snippets shows all available properties you can use for the plugin
"ipAddress": "xx:xx:xx:xx:xx:xx"
}
],
"tvDeviceTypes": [
"oic.d.tv",
"x.com.st.d.monitor"
],
"soundbarDeviceTypes": [
"oic.d.networkaudio"
],
"platform": "smartthings-tv"
}
]
Expand Down Expand Up @@ -219,6 +226,14 @@ The application's possible ids. Since some applications have different ids for d

The icon to be used as a hint to iOS clients about what type of Accessory this represents. Can be used to override default values.

## tvDeviceTypes

List of SmartThings device types that should be registered as TVs (leave empty to use default values).

## soundbarDeviceTypes

List of SmartThings device types that should be registered as Soundbar (leave empty to use default values).

## Common issues

### TV does not show in HomeKit
Expand Down Expand Up @@ -293,6 +308,12 @@ For some TVs display port sources do not show up. When having the same problem y

The configured name can not be cached because TV is published as external accessory. To permanently change the name use [nameOverride](#nameoverride).

### Device does not get registered

TVs do have different device types returned from SmartThings API. If your TV does not get registered, activate debug logging and look for a log entry like `Ignoring SmartThings device ... because device type ... is not in list of implemented/configured types [...]`. Use the device type stated here and add it to the matching configuration property [tvDeviceTypes](#tvdevicetypes) or [soundbarDeviceType](#soundbardevicetypes).

Currently only the default values have been tested. So please create a ticket if you're running into any problems with your device type. If everything is working well please create a ticket as well so the device type can be added to the default configuration.

***

Since this is my first plugin it may contain some problems. Feel free to create an issue or pull request and I will try to help and fix the problems.
Expand Down
27 changes: 27 additions & 0 deletions config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,33 @@
}
}
}
},
"tvDeviceTypes": {
"title": "TV device types",
"description": "List of SmartThings device types that should be registered as TVs (leave empty to use default values)",
"type": "array",
"items": {
"title": "Device type",
"type": "string",
"description": "The SmartThings device type as appearing in the Debug log"
},
"default": [
"oic.d.tv",
"x.com.st.d.monitor"
]
},
"soundbarDeviceTypes": {
"title": "Soundbar device types",
"description": "List of SmartThings device types that should be registered as Soundbar (leave empty to use default values)",
"type": "array",
"items": {
"title": "Device type",
"type": "string",
"description": "The SmartThings device type as appearing in the Debug log"
},
"default": [
"oic.d.networkaudio"
]
}
}
}
Expand Down
50 changes: 33 additions & 17 deletions src/smartThingsPlatform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ export class SmartThingsPlatform implements DynamicPlatformPlugin {

void this.discoverDevices(config.token as string,
deviceBlocklist ?? [],
config.deviceMappings as [DeviceMapping] ?? []);
config.deviceMappings as [DeviceMapping] ?? [],
config.tvDeviceTypes as [string] ?? ['oic.d.tv', 'x.com.st.d.monitor'],
config.soundbarDeviceTypes as [string] ?? ['oic.d.networkaudio']);
});
}

Expand All @@ -88,8 +90,11 @@ export class SmartThingsPlatform implements DynamicPlatformPlugin {
* @param token the SmartThings API token
* @param deviceBlocklist the device ids to be ignored
* @param deviceMappings the array of configured DeviceMapping
* @param tvDeviceTypes the array of configured TV device types
* @param soundbarDeviceTypes the array of configured SoundBar device types
*/
async discoverDevices(token: string, deviceBlocklist: [string], deviceMappings: [DeviceMapping]) {
async discoverDevices(token: string, deviceBlocklist: [string], deviceMappings: [DeviceMapping],
tvDeviceTypes: [string], soundbarDeviceTypes: [string]) {
const client = new SmartThingsClient(new BearerTokenAuthenticator(token));

let externalAccessories: PlatformAccessory[] = [];
Expand All @@ -103,7 +108,8 @@ export class SmartThingsPlatform implements DynamicPlatformPlugin {
this.log.debug('Ignoring SmartThings device %s because it is on the blocklist',
device.name ? device.name + ' (' + device.deviceId + ')' : device.deviceId);
} else {
externalAccessories = externalAccessories.concat(await this.registerDevice(client, device, deviceMappings));
externalAccessories = externalAccessories.concat(
await this.registerDevice(client, device, deviceMappings, tvDeviceTypes, soundbarDeviceTypes));
}
}
} catch (error) {
Expand All @@ -124,24 +130,34 @@ export class SmartThingsPlatform implements DynamicPlatformPlugin {
* @param client the SmartThingsClient used to send API calls
* @param device the SmartThings Device
* @param deviceMappings the array of configured DeviceMapping
* @param tvDeviceTypes the array of configured TV device types
* @param soundbarDeviceTypes the array of configured SoundBar device types
* @returns the PlatformAccessory that must be published as external accessory or undefined
* if accessory must not be published as external accessory
*/
async registerDevice(client: SmartThingsClient, device: Device, deviceMappings: [DeviceMapping]): Promise<PlatformAccessory[]> {
switch (device.ocf?.ocfDeviceType) {
case 'oic.d.tv':
case 'x.com.st.d.monitor':
return await this.registerTvDevice(client, device, deviceMappings.find(mapping => mapping.deviceId === device.deviceId));

case 'oic.d.networkaudio':
return await this.registerSoundbarDevice(client, device, deviceMappings.find(mapping => mapping.deviceId === device.deviceId));

default:
this.log.debug('Ignoring SmartThings device %s because device type %s is not implemented: %s',
device.name ? device.name + ' (' + device.deviceId + ')' : device.deviceId,
device.ocf?.ocfDeviceType, JSON.stringify(device, null, 2));
return [];
async registerDevice(client: SmartThingsClient, device: Device, deviceMappings: [DeviceMapping],
tvDeviceTypes: [string], soundbarDeviceTypes: [string]): Promise<PlatformAccessory[]> {
const deviceType = device.ocf?.ocfDeviceType;

if (!deviceType) {
this.log.error('Ignoring SmartThings device %s because it has no device type',
device.name ? device.name + ' (' + device.deviceId + ')' : device.deviceId);
return [];
}

const deviceMapping = deviceMappings.find(mapping => mapping.deviceId === device.deviceId);

if (tvDeviceTypes.includes(deviceType)) {
return await this.registerTvDevice(client, device, deviceMapping);
} else if (soundbarDeviceTypes.includes(deviceType)) {
return await this.registerSoundbarDevice(client, device, deviceMapping);
}

this.log.debug('Ignoring SmartThings device %s because device type %s is not in list of implemented/configured types (%s): %s',
device.name ? device.name + ' (' + device.deviceId + ')' : device.deviceId,
device.ocf?.ocfDeviceType, tvDeviceTypes.concat(soundbarDeviceTypes).join(', '),
JSON.stringify(device, null, 2));
return [];
}

/**
Expand Down

0 comments on commit a013106

Please sign in to comment.