homebridge-skyq-tvremote
Version:
Exposes and Sky Q Box as a TV Accessory in HomeBridge, allow you to use the Remote UI in Control Centre
250 lines • 12.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SkyTVPlugin = void 0;
const settings_1 = require("./settings");
const SkyRemote = require("sky-remote");
const SkyQCheck = require("sky-q");
class SkyTVPlugin {
constructor(log, config, api) {
this.names = [];
this.getActive = async (boxCheck) => {
return new Promise((resolve, reject) => {
boxCheck.getPowerState().then(isOn => {
if (isOn) {
resolve(this.api.hap.Characteristic.Active.ACTIVE);
}
else {
resolve(this.api.hap.Characteristic.Active.INACTIVE);
}
}).catch(error => {
this.log.error(error);
reject(error);
});
});
};
this.send = async (remoteControl, command) => {
try {
remoteControl.press(command);
}
catch (error) {
this.log.error(error);
return Promise.reject(error);
}
};
this.log = log;
this.api = api;
if (config.devices) {
config.devices.forEach((deviceConfig, key) => {
deviceConfig = this.prepareDeviceConfig(key, deviceConfig);
this.publishExternalAccessory(deviceConfig);
this.names = [];
});
}
else {
const deviceConfig = this.prepareDeviceConfig(null, config);
this.publishExternalAccessory(deviceConfig);
}
log.info('Sky TV platform finished initializing!');
}
prepareDeviceConfig(key, config) {
if (!config.name) {
if (key === null) {
config.name = 'TV';
}
else {
config.name = `TV ${key + 1}`;
if (this.names.includes(config.name)) {
this.log.error(`Duplicate name at device ${key + 1}.`);
}
}
}
if (!config.ipAddress) {
if (key === null) {
if (!config.ipAddress) {
this.log.error('IP address not set.');
}
}
else {
if (!config.ipAddress) {
this.log.error(`IP address not set at device ${key + 1}.`);
}
}
}
return config;
}
publishExternalAccessory(config) {
if (!config.name) {
return;
}
if (!config.ipAddress) {
return;
}
const remoteControl = new SkyRemote(config.ipAddress);
const boxCheck = new SkyQCheck({ ip: config.ipAddress });
// Generate a UUID
const uuid = this.api.hap.uuid.generate(`homebridge:${settings_1.PLUGIN_NAME}:` + config.ipAddress);
// Create the accessory
const accessory = new this.api.platformAccessory(config.name, uuid);
// Set the accessory category
accessory.category = 35 /* TV_SET_TOP_BOX */;
// Add the accessory information service
const accessoryInfoService = accessory.getService(this.api.hap.Service.AccessoryInformation);
accessoryInfoService.setCharacteristic(this.api.hap.Characteristic.Manufacturer, 'Sky');
boxCheck._getSystemInformation({}).then(info => {
if (info.manufacturer) {
accessoryInfoService.setCharacteristic(this.api.hap.Characteristic.Manufacturer, info.manufacturer);
}
if (info.deviceType) {
accessoryInfoService.setCharacteristic(this.api.hap.Characteristic.Model, info.deviceType);
}
if (info.serialNumber) {
accessoryInfoService.setCharacteristic(this.api.hap.Characteristic.SerialNumber, info.serialNumber);
}
});
// Add the TV service
const tvService = accessory.addService(this.api.hap.Service.Television);
// Set the TV name
tvService.setCharacteristic(this.api.hap.Characteristic.ConfiguredName, config.name);
// Set sleep discovery characteristic
tvService.setCharacteristic(this.api.hap.Characteristic.SleepDiscoveryMode, this.api.hap.Characteristic.SleepDiscoveryMode.ALWAYS_DISCOVERABLE);
boxCheck._request('as/services/favourites').then(favoritesData => {
if (favoritesData.favourites) {
boxCheck._request('as/services').then(servicesData => {
if (servicesData.services) {
tvService.getCharacteristic(this.api.hap.Characteristic.ActiveIdentifier)
.on("set" /* SET */, (value, callback) => {
const input = value.toString();
this.log.info(`[${config.name}]`, 'Set Input:', value);
this.send(remoteControl, ['backup', 'backup', 'backup', ...input]).then(() => callback()).catch((error) => {
this.log.error(error);
callback(error);
});
});
favoritesData.favourites.forEach(favorite => {
const service = servicesData.services.filter(service => service.sid === favorite.sid)[0];
if (!service || !service.t || !service.c) {
return;
}
const inputService = accessory.addService(this.api.hap.Service.InputSource, service.c, service.t);
inputService.setCharacteristic(this.api.hap.Characteristic.Identifier, parseInt(service.c));
inputService.setCharacteristic(this.api.hap.Characteristic.ConfiguredName, service.t);
inputService.setCharacteristic(this.api.hap.Characteristic.IsConfigured, this.api.hap.Characteristic.IsConfigured.CONFIGURED);
inputService.setCharacteristic(this.api.hap.Characteristic.InputSourceType, this.api.hap.Characteristic.InputSourceType.TUNER);
inputService.setCharacteristic(this.api.hap.Characteristic.InputDeviceType, this.api.hap.Characteristic.InputDeviceType.TUNER);
tvService.addLinkedService(inputService);
});
}
});
}
});
// Handle on / off events using the active characteristic
tvService.getCharacteristic(this.api.hap.Characteristic.Active)
.on("get" /* GET */, (callback) => {
this.getActive(boxCheck).then((activeState) => {
this.log.debug(`[${config.name}]`, 'Get Active: ' + (activeState ? 'ACTIVE' : 'INACTIVE'));
callback(undefined, activeState);
}).catch((error) => {
this.log.error(`[${config.name}]`, 'Perhaps looking at this error will help you figure out why');
this.log.error(error);
callback(error);
});
})
.on("set" /* SET */, (value, callback) => {
this.getActive(boxCheck).then((activeState) => {
if (!!value === !!activeState) {
this.log.info(`[${config.name}]`, 'Skipping Active: new value is equal to current value');
return callback();
}
this.log.info(`[${config.name}]`, 'Set Active: ' + (value ? 'ACTIVE' : 'INACTIVE'));
this.send(remoteControl, 'power').then(() => {
activeState = value ? this.api.hap.Characteristic.Active.ACTIVE : this.api.hap.Characteristic.Active.INACTIVE;
tvService.updateCharacteristic(this.api.hap.Characteristic.Active, activeState);
callback();
}).catch((error) => {
this.log.error(error);
callback(error);
});
}).catch((error) => {
this.log.error(`[${config.name}]`, 'Perhaps looking at this error will help you figure out why');
this.log.error(error);
callback(error);
});
});
// Handle remote control input
tvService.getCharacteristic(this.api.hap.Characteristic.RemoteKey)
.on("set" /* SET */, (value, callback) => {
const command = (() => {
switch (value) {
case this.api.hap.Characteristic.RemoteKey.REWIND:
return 'rewind';
case this.api.hap.Characteristic.RemoteKey.FAST_FORWARD:
return 'fastforward';
case this.api.hap.Characteristic.RemoteKey.ARROW_UP:
return 'up';
case this.api.hap.Characteristic.RemoteKey.ARROW_DOWN:
return 'down';
case this.api.hap.Characteristic.RemoteKey.ARROW_LEFT:
return 'left';
case this.api.hap.Characteristic.RemoteKey.ARROW_RIGHT:
return 'right';
case this.api.hap.Characteristic.RemoteKey.SELECT:
return 'select';
case this.api.hap.Characteristic.RemoteKey.BACK:
return 'backup';
case this.api.hap.Characteristic.RemoteKey.PLAY_PAUSE:
return 'play';
case this.api.hap.Characteristic.RemoteKey.INFORMATION:
return 'tvguide';
case this.api.hap.Characteristic.RemoteKey.EXIT:
}
})();
if (!command) {
this.log.error(`[${config.name}]`, `Skipping Remote Key: unknown new value: ${value}`);
return callback();
}
this.log.info(`[${config.name}]`, 'Set Remote Key: ' + command);
this.send(remoteControl, command).then(() => callback()).catch((error) => {
this.log.error(error);
callback(error);
});
});
// Add the speaker service
const speakerService = accessory.addService(this.api.hap.Service.TelevisionSpeaker);
speakerService.setCharacteristic(this.api.hap.Characteristic.Active, this.api.hap.Characteristic.Active.ACTIVE);
speakerService.setCharacteristic(this.api.hap.Characteristic.VolumeControlType, this.api.hap.Characteristic.VolumeControlType.RELATIVE);
// Handle volume control
speakerService.getCharacteristic(this.api.hap.Characteristic.VolumeSelector)
.on("set" /* SET */, (value, callback) => {
const command = (() => {
switch (value) {
case this.api.hap.Characteristic.VolumeSelector.INCREMENT:
return 'channelup';
case this.api.hap.Characteristic.VolumeSelector.DECREMENT:
return 'channeldown';
}
})();
if (!command) {
this.log.error(`[${config.name}]`, `Skipping Volume Selector: unknown newValue: ${value}`);
return callback();
}
this.log.info(`[${config.name}]`, 'Set Volume Selector: ' + command);
this.send(remoteControl, command).then(() => callback()).catch((error) => {
this.log.error(error);
callback(error);
});
});
// will be exposed as an additional accessory and must be paired separately with the pincode of homebridge
this.api.publishExternalAccessories(settings_1.PLUGIN_NAME, [accessory]);
setInterval(() => {
this.getActive(boxCheck).then((activeState) => {
this.log.debug(`[${config.name}]`, 'Update Active: ' + (activeState ? 'ACTIVE' : 'INACTIVE'));
tvService.updateCharacteristic(this.api.hap.Characteristic.Active, activeState);
}).catch((error) => {
this.log.error(`[${config.name}]`, 'Perhaps looking at this error will help you figure out why');
this.log.error(error);
});
}, 10000);
}
}
exports.SkyTVPlugin = SkyTVPlugin;
//# sourceMappingURL=platform.js.map