Commit 4b4d4736 authored by Samuel Elliott's avatar Samuel Elliott

Check if the TV is on every minute and timeout volume/mute requests after 2 seconds

parent 97ea679d
......@@ -17,6 +17,8 @@ npm install -g git+https://gitlab.fancy.org.uk/samuel/homebridge-vestel-network-
}
```
The TV generates a new UUID every time it is turned on so there's no way of discovering the IP address so you need to set a static IP address on the TV.
### Features
- Power ([requires HDMI CEC/IR device to turn the TV on](#turning-the-tv-on))
......@@ -25,7 +27,7 @@ npm install -g git+https://gitlab.fancy.org.uk/samuel/homebridge-vestel-network-
- Setting current input/app/channel
- Sending remote keys
[Apparently Vestel TVs support a lot more commands.](https://forum.digitalfernsehen.de/threads/medion-md-30465-42-led-backlight-tv-life%C2%AE-x17006.276321/page-64#post-7474289) I haven't tested any of these.
[Apparently Vestel TVs support a lot more commands.](https://forum.digitalfernsehen.de/threads/medion-md-30465-42-led-backlight-tv-life%C2%AE-x17006.276321/page-64#post-7474289) I haven't tested all of these.
Turning the TV on
---
......
......@@ -63,24 +63,23 @@ class TVAccessory {
this.name = config.name;
this.mac_address = config.mac_address;
this.ip_address = config.ip_address;
this.media_renderer_location = config.media_renderer_location !== undefined
? config.media_renderer_location : 'http://' + this.ip_address + ':2869/dmr.xml';
this.media_renderer_location = config.media_renderer_location !== undefined ?
config.media_renderer_location : 'http://' + this.ip_address + ':2869/dmr.xml';
this.storage_key = 'vestel-network-remote.TV.' + this.name + '.json';
// Services
this.expose_television_service = config.expose_television_service !== undefined ? config.expose_television_service
: !!config.tv_sources;
this.expose_television_speaker_service = config.expose_television_speaker_service !== undefined
? config.expose_television_speaker_service
: this.expose_television_service && this.media_renderer_location;
this.expose_power_service = config.expose_power_service !== undefined ? config.expose_power_service
: !this.expose_television_service;
this.expose_speaker_service = config.expose_speaker_service !== undefined ? config.expose_speaker_service
: !this.expose_television_speaker_service && this.media_renderer_location;
this.expose_speaker_lightbulb_service = config.expose_speaker_lightbulb_service !== undefined
? config.expose_speaker_lightbulb_service : false;
this.expose_television_service = config.expose_television_service !== undefined ?
config.expose_television_service : !!config.tv_sources;
this.expose_television_speaker_service = config.expose_television_speaker_service !== undefined ?
config.expose_television_speaker_service : this.expose_television_service && this.media_renderer_location;
this.expose_power_service = config.expose_power_service !== undefined ? config.expose_power_service :
!this.expose_television_service;
this.expose_speaker_service = config.expose_speaker_service !== undefined ? config.expose_speaker_service :
!this.expose_television_speaker_service && this.media_renderer_location;
this.expose_speaker_lightbulb_service = config.expose_speaker_lightbulb_service !== undefined ?
config.expose_speaker_lightbulb_service : false;
if (!this.expose_power_service && !this.expose_speaker_service && !this.expose_speaker_lightbulb_service && !this.expose_television_service && !this.expose_television_speaker_service) {
throw new Error('Trying to create a vestel-network-remote.TV accessory with no services');
......@@ -187,13 +186,18 @@ class TVAccessory {
.setCharacteristic(this.constructor.hap.Characteristic.FirmwareRevision, require('../package').version);
if (this.expose_power_service || this.expose_television_service) {
this.getPowerState().then(on => {
const updatePowerState = async () => {
const on = await this.getPowerState();
if (this.expose_power_service) this.power_service.getCharacteristic(this.constructor.hap.Characteristic.On)
.updateValue(on);
if (this.expose_television_service) this.tv_service.getCharacteristic(this.constructor.hap.Characteristic.Active)
.updateValue(on ? this.constructor.hap.Characteristic.Active.ACTIVE
: this.constructor.hap.Characteristic.Active.INACTIVE);
});
};
updatePowerState();
this.update_power_state_interval = setInterval(updatePowerState, 60000);
}
}
......@@ -250,15 +254,13 @@ class TVAccessory {
//
get power_service() {
if (this._power_service) return this._power_service;
const power_service = new this.constructor.hap.Service.Switch(this.name);
power_service.getCharacteristic(this.constructor.hap.Characteristic.On)
.on('get', callback => this.getPowerState().then(data => callback(undefined, data)).catch(callback))
.on('set', (on, callback) => this.setPowerState(on).then(data => callback(undefined, data)).catch(callback));
return this._power_service = power_service;
return Object.defineProperty(this, 'power_service', {configurable: true, value: power_service}).power_service;
}
async getPowerState() {
......@@ -318,8 +320,6 @@ class TVAccessory {
//
get speaker_service() {
if (this._speaker_service) return this._speaker_service;
const speaker_service = new this.constructor.hap.Service.Speaker(this.name);
speaker_service.getCharacteristic(this.constructor.hap.Characteristic.Mute)
......@@ -330,12 +330,10 @@ class TVAccessory {
.on('get', callback => this.getVolume().then(data => callback(undefined, data)).catch(callback))
.on('set', (volume, callback) => this.setVolume(volume).then(data => callback(undefined, data)).catch(callback));
return this._speaker_service = speaker_service;
return Object.defineProperty(this, 'speaker_service', {configurable: true, value: speaker_service}).speaker_service;
}
get speaker_lightbulb_service() {
if (this._speaker_lightbulb_service) return this._speaker_lightbulb_service;
const speaker_service = new this.constructor.hap.Service.Lightbulb(this.name + ' Speaker');
speaker_service.getCharacteristic(this.constructor.hap.Characteristic.On)
......@@ -346,7 +344,7 @@ class TVAccessory {
.on('get', callback => this.getVolume().then(data => callback(undefined, data)).catch(callback))
.on('set', (volume, callback) => this.setVolume(volume).then(data => callback(undefined, data)).catch(callback));
return this._speaker_lightbulb_service = speaker_service;
return Object.defineProperty(this, 'speaker_lightbulb_service', {configurable: true, value: speaker_lightbulb_service}).speaker_lightbulb_service;
}
callMediaRendererAction(service, action, args) {
......@@ -354,7 +352,14 @@ class TVAccessory {
throw new Error('MediaRenderer client not initialized');
}
return new Promise((resolve, reject) => this.media_renderer_client.callAction(service, action, args, (err, data) => err ? reject(err) : resolve(data)));
this.log('Calling MediaRenderer action', service, action, args);
// If the TV doesn't respond in 2 seconds assume the TV is off
return Promise.race([
new Promise((resolve, reject) => this.media_renderer_client
.callAction(service, action, args, (err, data) => err ? reject(err) : resolve(data))),
new Promise((rs, reject) => setTimeout(reject, 2000)),
]);
}
handleMediaRendererEvent(event) {
......@@ -410,8 +415,6 @@ class TVAccessory {
//
get tv_service() {
if (this._tv_service) return this._tv_service;
const tv_service = new this.constructor.hap.Service.Television(this.name);
tv_service.getCharacteristic(this.constructor.hap.Characteristic.Active)
......@@ -431,7 +434,7 @@ class TVAccessory {
tv_service.getCharacteristic(this.constructor.hap.Characteristic.RemoteKey)
.on('set', (key, callback) => this.sendRemoteKey(key).then(data => callback(undefined, data)).catch(callback));
return this._tv_service = tv_service;
return Object.defineProperty(this, 'tv_service', {configurable: true, value: tv_service}).tv_service;
}
async getInputIdentifier() {
......@@ -501,7 +504,7 @@ class TVAccessory {
//
get input_source_services() {
return this._input_source_services || (this._input_source_services = []);
return Object.defineProperty(this, 'input_source_services', {configurable: true, value: []}).input_source_services;
}
addInputSourceService(id, config, type, subtype) {
......@@ -571,8 +574,6 @@ class TVAccessory {
//
get tv_speaker_service() {
if (this._tv_speaker_service) return this._tv_speaker_service;
const speaker_service = new this.constructor.hap.Service.TelevisionSpeaker(this.name);
speaker_service.getCharacteristic(this.constructor.hap.Characteristic.Mute)
......@@ -585,7 +586,7 @@ class TVAccessory {
speaker_service.setCharacteristic(this.constructor.hap.Characteristic.VolumeControlType, this.constructor.hap.Characteristic.VolumeControlType.ABSOLUTE);
return this._tv_speaker_service = speaker_service;
return Object.defineProperty(this, 'tv_speaker_service', {configurable: true, value: speaker_service}).tv_speaker_service;
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment