homebridge-sharp-aquos-tv 3.0.1

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.
@@ -0,0 +1,30 @@
1
+ "inputs": [
2
+ {
3
+ "inputID": "1",
4
+ "name": "HDMI 1"
5
+ },
6
+ {
7
+ "inputID": "2",
8
+ "name": "HDMI 2"
9
+ },
10
+ {
11
+ "inputID": "3",
12
+ "name": "HDMI 3"
13
+ },
14
+ {
15
+ "inputID": "4",
16
+ "name": "HDMI 4"
17
+ },
18
+ {
19
+ "inputID": "5",
20
+ "name": "Component"
21
+ },
22
+ {
23
+ "inputID": "6",
24
+ "name": "Video 1"
25
+ },
26
+ {
27
+ "inputID": "7",
28
+ "name": "Video 2"
29
+ }
30
+ ]
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020 Marcin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,41 @@
1
+ # homebridge-sharp-aquos
2
+ Homebridge plugin for Sharp Aquos TVs.
3
+ Exposes TV accessories with power and input controls.
4
+ TV will be unbridged, so you will have to add it manually in Home via + > Add Accessory > More options...
5
+
6
+ ## Installation
7
+ Place the files in `node_modules/homenbridge-sharp-tv` and `npm install .`
8
+ Or package it and install with npm:
9
+ ```
10
+ tar -zcvf ../homebridge-sharp-tv.tar.gz .
11
+ cd ..
12
+ npm install homebridge-sharp-tv.tar.gz
13
+ ```
14
+
15
+ ## Sample Config
16
+ ```
17
+ {
18
+ "pollInterval": 60,
19
+ "debugToInfo": false,
20
+ "devices": [
21
+ {
22
+ "name": "Sharp TV",
23
+ "ip": "10.0.0.41",
24
+ "defaultInputID": "1",
25
+ "inputs": [
26
+ {
27
+ "inputID": "1",
28
+ "name": "HDMI 1"
29
+ }
30
+ ]
31
+ }
32
+ ],
33
+ "platform": "SharpTV"
34
+ }
35
+ ```
36
+
37
+ ## Control Center Remote
38
+
39
+ * Info maps to DISPLAY
40
+ * Play/Pause maps to MENU
41
+ * Back maps to RETURN
package/build.sh ADDED
@@ -0,0 +1,18 @@
1
+ PKG=`basename $PWD`
2
+ DEST=../build
3
+ rm -rf ../build
4
+ mkdir -p ../build || exit
5
+ for f in *; do
6
+ if [ "$f" != "node_modules" ] && \
7
+ [ "$f" != "build.sh" ] && \
8
+ [ "$f" != "nodemon.json" ] && \
9
+ [ "$f" != "src" ]
10
+ then
11
+ cp -rv $f ../build
12
+ fi
13
+ done
14
+ cd ../build || exit
15
+ npm pkg delete devDependencies || exit
16
+ cd ../$PKG || exit
17
+ tar -zcvf ../$PKG.tar.gz -C ../build . || exit
18
+ rm -rf ../build
@@ -0,0 +1,100 @@
1
+ {
2
+ "pluginAlias": "SharpTV",
3
+ "pluginType": "platform",
4
+ "footerDisplay": "Homebridge plugin for Sharp Aquos TVs.",
5
+ "schema": {
6
+ "type": "object",
7
+ "properties": {
8
+ "pollInterval": {
9
+ "title": "Polling interval",
10
+ "description": "The state of the TV is polled every 60 seconds. Change this interval with this value. The value is the interval in seconds.",
11
+ "type": "integer",
12
+ "placeholder": 60,
13
+ "required": false
14
+ },
15
+ "debugToInfo": {
16
+ "title": "Print debug log in info log.",
17
+ "description": "Set to true if you wan't to debug the plugin but you don't have access to the debug log.",
18
+ "type": "boolean",
19
+ "default": false,
20
+ "required": false
21
+ },
22
+ "devices": {
23
+ "description": "Name and IP of TVs to create accessories for",
24
+ "title": "Devices",
25
+ "type": "array",
26
+ "items": {
27
+ "type": "object",
28
+ "properties": {
29
+ "name": {
30
+ "title": "Name",
31
+ "type": "string",
32
+ "default": "Sharp TV",
33
+ "required": true,
34
+ "minLength": 4
35
+ },
36
+ "ip": {
37
+ "title": "IP address",
38
+ "type": "string",
39
+ "placeholder": "192.168.xx.xx",
40
+ "format": "ipv4",
41
+ "required": true,
42
+ "minLength": 4
43
+ },
44
+ "defaultInputID": {
45
+ "title": "Default InputID",
46
+ "type": "string",
47
+ "placeholder": "None",
48
+ "required": false,
49
+ "typeahead": {
50
+ "source": [
51
+ "1",
52
+ "2",
53
+ "3",
54
+ "4",
55
+ "5",
56
+ "6",
57
+ "7"
58
+ ]
59
+ }
60
+ },
61
+ "inputs": {
62
+ "title": "List with selectable inputs",
63
+ "description": "The list with used inputs.",
64
+ "type": "array",
65
+ "items": {
66
+ "type": "object",
67
+ "properties": {
68
+ "inputID": {
69
+ "title": "Input ID",
70
+ "type": "string",
71
+ "placeholder": "1",
72
+ "required": true,
73
+ "typeahead": {
74
+ "source": [
75
+ "1",
76
+ "2",
77
+ "3",
78
+ "4",
79
+ "5",
80
+ "6",
81
+ "7"
82
+ ]
83
+ }
84
+ },
85
+ "name": {
86
+ "title": "Input name",
87
+ "type": "string",
88
+ "placeholder": "HDMI 1",
89
+ "required": true,
90
+ "minLength": 1
91
+ }
92
+ }
93
+ }
94
+ }
95
+ }
96
+ }
97
+ }
98
+ }
99
+ }
100
+ }
package/index.js ADDED
@@ -0,0 +1,660 @@
1
+ const { Telnet } = require('telnet-client');
2
+
3
+ const pluginName = 'homebridge-sharp-aquos-tv';
4
+ const platformName = 'SharpTV';
5
+ const pluginVersion = '3.0.0';
6
+
7
+ const defaultPollingInterval = 3;
8
+ const infoRetDelay = 250;
9
+ const defaultTrace = false;
10
+ const autoDiscoverTime = 3000;
11
+
12
+ let Service;
13
+ let Characteristic;
14
+ let Accessory;
15
+ let UUIDGen;
16
+
17
+ var traceOn;
18
+ var debugToInfo;
19
+ var discoverDev;
20
+ var g_log;
21
+
22
+ var cachedAccessories = [];
23
+ var didFinishLaunching = false;
24
+
25
+ /* Variables for telnet polling system */
26
+ var g_powerState = [false,false,false];
27
+ var g_volLevel = [0,0,0];
28
+ var g_muteState = [false,false,false];
29
+ var g_inputID = [null,null,null];
30
+
31
+ module.exports = (homebridge) => {
32
+ Service = homebridge.hap.Service;
33
+ Characteristic = homebridge.hap.Characteristic;
34
+ Accessory = homebridge.platformAccessory;
35
+ UUIDGen = homebridge.hap.uuid;
36
+
37
+ homebridge.registerPlatform(pluginName, platformName, sharpClient, true);
38
+ };
39
+
40
+ exports.logDebug = function(string) {
41
+ if (!debugToInfo)
42
+ g_log.debug(string);
43
+ else
44
+ g_log.warn(string);
45
+ }
46
+ function logDebug(string) {
47
+ if (!debugToInfo)
48
+ g_log.debug(string);
49
+ else
50
+ g_log.warn(string);
51
+ }
52
+
53
+ class sharpClient {
54
+ constructor(log, config, api) {
55
+ g_log = log;
56
+ this.api = api;
57
+
58
+ /* Stop loading if plugin is not configured */
59
+ if (!config || (!Array.isArray(config.devices) && !Array.isArray(config.volumeControl))) {
60
+ g_log.warn("WARNING: No config settings found for homebridge-sharp-tv plugin.")
61
+ return;
62
+ }
63
+
64
+ traceOn = config.debugTrace || defaultTrace;
65
+
66
+ debugToInfo = config.debugToInfo || false;
67
+
68
+ /* Search for all available Denon tvs */
69
+
70
+ api.on('didFinishLaunching', function() {
71
+ logDebug("DidFinishLaunching");
72
+ didFinishLaunching = true;
73
+
74
+ this.configTVs = [];
75
+
76
+ try {
77
+ for (let i in config.devices) {
78
+ if (config.devices[i].ip !== undefined && !this.configTVs[config.devices[i].ip])
79
+ this.configTVs[config.devices[i].ip] =
80
+ new tv(this, config, config.devices[i].ip);
81
+ }
82
+ } catch (error) {
83
+ g_log.error(error);
84
+ return;
85
+ }
86
+ setTimeout(this.removeCachedAccessory.bind(this), autoDiscoverTime+5000);
87
+ }.bind(this));
88
+ }
89
+
90
+ configureAccessory(platformAccessory){
91
+ if (traceOn) {
92
+ logDebug('DEBUG: configureAccessory');
93
+ try {
94
+ logDebug(platformAccessory.displayName);
95
+ } catch (error) {
96
+ g_log.error(error);
97
+ }
98
+ }
99
+
100
+ cachedAccessories.push(platformAccessory);
101
+ }
102
+
103
+ removeCachedAccessory(){
104
+ if (traceOn) {
105
+ logDebug('DEBUG: removeCachedAccessory');
106
+ try {
107
+ for (let i in cachedAccessories)
108
+ logDebug(cachedAccessories[0].displayName);
109
+ } catch (error) {
110
+ g_log.error(error);
111
+ }
112
+ }
113
+
114
+ try {
115
+ this.api.unregisterPlatformAccessories(pluginName, platformName, cachedAccessories);
116
+ } catch (error) {
117
+ g_log.error(error);
118
+ }
119
+ }
120
+ }
121
+
122
+ class tv {
123
+ constructor(base, config, ip) {
124
+ this.port = 10002;
125
+ this.api = base.api;
126
+ this.ip = ip;
127
+ this.base = base;
128
+ this.queue = [];
129
+ this.last_command=null;
130
+
131
+ this.tvAccessories = [];
132
+
133
+ this.devices = config.devices;
134
+
135
+ this.devicesDuplicates = [];
136
+
137
+ g_log.info('Start TV with IP: ' + this.ip);
138
+
139
+ this.pollingInterval = config.pollInterval || defaultPollingInterval;
140
+ this.pollingInterval = this.pollingInterval * 1000;
141
+
142
+ this.telnetPort = 10002;
143
+ this.devInfoSet = false;
144
+ this.telnet = null;
145
+
146
+ this.manufacturer = 'Sharp';
147
+ this.modelName = pluginName;
148
+ this.serialNumber = 'Aquos';
149
+ this.firmwareRevision = pluginVersion;
150
+
151
+ this.disabletv = false;
152
+ this.pollingTimeout = false;
153
+
154
+ this.poweredOn = [false,false,false];
155
+ this.currentInputID = [null,null,null];
156
+ this.volDisp = [null,null,null];
157
+ this.volumeLevel = [30,30,30];
158
+ this.muteState = [false,false,false];
159
+
160
+ this.startConfiguration();
161
+ //start polling
162
+ setInterval(this.pollForUpdates.bind(this, 1), this.pollingInterval)
163
+ this.pollForUpdates(1); //initial poll to get state on startup
164
+ }
165
+
166
+ getDevInfoSet() {
167
+ return this.devInfoSet;
168
+ }
169
+ setDevInfoSet(set) {
170
+ this.devInfoSet = set;
171
+ }
172
+ returnIP() {
173
+ return this.ip;
174
+ }
175
+
176
+ /*
177
+ * Try configure the devices. Wait until tv discovery is finished.
178
+ */
179
+ startConfiguration () {
180
+
181
+ if ( !didFinishLaunching) {
182
+ setTimeout(this.startConfiguration.bind(this), infoRetDelay);
183
+ return;
184
+ }
185
+
186
+ /* Configure devices */
187
+ for (let i in this.devices) {
188
+ if (this.devices[i].ip === this.ip) {
189
+ try {
190
+ if (this.devicesDuplicates[this.devices[i].name]) {
191
+ g_log.warn("WARNING: A Device with the name: %s and ip: %s is already added. It will be ignored.", this.devices[i].name, this.devices[i].ip);
192
+ continue;
193
+ } else {
194
+ this.devicesDuplicates[this.devices[i].name] = true;
195
+ this.tvAccessories.push(new tvClient(this, this.devices[i]));
196
+ }
197
+ } catch (error) {
198
+ g_log.error(error);
199
+ }
200
+ }
201
+ }
202
+
203
+ }
204
+
205
+ /*
206
+ * This will start a polling loop that goes on forever and updates
207
+ * the on characteristic periodically.
208
+ */
209
+ pollForUpdates(zone) {
210
+ // if (traceOn)
211
+ // logDebug('DEBUG: pollForUpdates zone: ' + zone + ': ' + this.ip);
212
+
213
+ /* Make sure that no poll is happening just after switch in input/power */
214
+ if (this.pollingTimeout) {
215
+ this.pollingTimeout = false;
216
+ return;
217
+ }
218
+
219
+ var that = this;
220
+ this.send('POWR? ');
221
+ this.send('IAVD? ');
222
+ this.send('RSPW2 '); //ensure TV can be turned on from IP control
223
+
224
+ }
225
+
226
+
227
+ /*
228
+ * Used to update the state of all. Disable polling for one poll.
229
+ */
230
+ updateStates(that, stateInfo, curName) {
231
+ if (curName)
232
+ that.pollingTimeout = true;
233
+
234
+ if (traceOn)
235
+ logDebug(stateInfo);
236
+
237
+ if (stateInfo.power === true || stateInfo.power === false)
238
+ that.poweredOn[stateInfo.zone-1] = stateInfo.power;
239
+
240
+ if (stateInfo.inputID)
241
+ that.currentInputID[stateInfo.zone-1] = stateInfo.inputID;
242
+
243
+ for (let i in that.tvAccessories) {
244
+ if (that.tvAccessories[i].getName() != curName) {
245
+ that.tvAccessories[i].settvState(stateInfo);
246
+ }
247
+ }
248
+ }
249
+
250
+ /*
251
+ * Setup Telnet connection if no HTML control is possible.
252
+ */
253
+ connect() {
254
+ this.telnet = new Telnet();
255
+ const params = {
256
+ host: this.ip,
257
+ port: this.port,
258
+ negotiationMandatory: false,
259
+ timeout: 1500,
260
+ ors: '\r',
261
+ irs: '\r',
262
+ shellPrompt: null
263
+ }
264
+ this.telnet.connect(params).then(
265
+ res => { logDebug('Connected to '+this.ip) }).catch(
266
+ error => { logDebug(error) }
267
+ );
268
+ }
269
+
270
+ send(cmd) {
271
+ if (this.telnet == null)
272
+ this.connect();
273
+ this.telnet.send(cmd).then(
274
+ res => { this.responseHandler(cmd,res.slice(0, -1)) }).catch(
275
+ error => {
276
+ logDebug(error);
277
+ this.telnet=null;
278
+ }
279
+ );
280
+ }
281
+
282
+ responseHandler(cmd,res) {
283
+
284
+ logDebug('Received response for ' + cmd + res);
285
+ res=res.split('\r')
286
+ switch (cmd) {
287
+ case 'POWR? ':
288
+ case 'IAVD? ':
289
+ if (res[0] === '1')
290
+ g_powerState[0] = true;
291
+ else if (res[0] === '0')
292
+ g_powerState[0] = false;
293
+ let stateInfo = {
294
+ zone: 1,
295
+ power: g_powerState[0],
296
+ inputID: res[1],
297
+ }
298
+ logDebug(stateInfo);
299
+ if (!this.pollingTimeout)
300
+ this.updateStates(this, stateInfo, null);
301
+ this.telnet.end().then( () => { this.telnet = null; } )
302
+
303
+ break;
304
+ }
305
+ }
306
+ }
307
+
308
+ class tvClient {
309
+ constructor(tv, device) {
310
+ this.api = tv.api;
311
+ this.tv = tv;
312
+
313
+ this.manufacturer = tv.manufacturer;
314
+ this.modelName = tv.modelName;
315
+ this.serialNumber = tv.serialNumber;
316
+ this.firmwareRevision = tv.firmwareRevision;
317
+
318
+ // configuration
319
+ this.name = device.name || 'Sharp TV';
320
+ this.ip = device.ip;
321
+ this.inputs = device.inputs;
322
+ this.zone = device.zone || 1;
323
+ this.zone = 1;
324
+
325
+ this.iterator = this.zone - 1;
326
+ this.defaultInputID = device.defaultInputID;
327
+
328
+ /* setup variables */
329
+ this.inputIDSet = false;
330
+ this.inputIDs = new Array();
331
+
332
+ this.setDefaultInputTimeout;
333
+
334
+ /* Delay to wait for retrieve device info */
335
+ this.setupTvService();
336
+ }
337
+
338
+
339
+ /*****************************************
340
+ * Start of TV integration service
341
+ ****************************************/
342
+ setupTvService() {
343
+ logDebug('setupTvService: ' + this.name);
344
+
345
+ this.tvAccesory = new Accessory(this.name, UUIDGen.generate(this.ip+this.name+"tvService"));
346
+ this.tvAccesory.category = this.api.hap.Categories.TELEVISION;
347
+
348
+ this.tvService = new Service.Television(this.name, 'tvService');
349
+ this.tvService
350
+ .setCharacteristic(Characteristic.ConfiguredName, this.name);
351
+ this.tvService
352
+ .setCharacteristic(Characteristic.SleepDiscoveryMode, Characteristic.SleepDiscoveryMode.ALWAYS_DISCOVERABLE);
353
+ this.tvService
354
+ .getCharacteristic(Characteristic.Active)
355
+ .on('get', this.getPowerState.bind(this))
356
+ .on('set', this.setPowerState.bind(this));
357
+ this.tvService
358
+ .getCharacteristic(Characteristic.ActiveIdentifier)
359
+ .on('set', (inputIdentifier, callback) => {
360
+ this.setAppSwitchState(true, callback, this.inputIDs[inputIdentifier]);
361
+ })
362
+ .on('get', this.getAppSwitchState.bind(this));
363
+ this.tvAccesory
364
+ .getService(Service.AccessoryInformation)
365
+ .setCharacteristic(Characteristic.Manufacturer, this.manufacturer)
366
+ .setCharacteristic(Characteristic.Model, this.modelName)
367
+ .setCharacteristic(Characteristic.SerialNumber, this.serialNumber)
368
+ .setCharacteristic(Characteristic.FirmwareRevision, this.firmwareRevision);
369
+ this.tvService
370
+ .getCharacteristic(Characteristic.RemoteKey)
371
+ .on('set', this.remoteKeyPress.bind(this));
372
+
373
+ this.tvAccesory.addService(this.tvService);
374
+
375
+ this.setupTvSpeakerService();
376
+ this.setupInputSourcesService();
377
+
378
+ logDebug('PublishExternalAccessories: '+ this.name);
379
+ this.api.publishExternalAccessories(pluginName, [this.tvAccesory]);
380
+ }
381
+
382
+ setupTvSpeakerService() {
383
+ logDebug('setupTvSpeakerService: ' + this.name);
384
+ this.tvSpeakerService = new Service.TelevisionSpeaker(this.name + ' Volume', 'tvSpeakerService');
385
+ this.tvSpeakerService
386
+ .setCharacteristic(Characteristic.Active,
387
+ Characteristic.Active.ACTIVE)
388
+ .setCharacteristic(Characteristic.VolumeControlType,
389
+ Characteristic.VolumeControlType.RELATIVE);
390
+ this.tvSpeakerService
391
+ .getCharacteristic(Characteristic.VolumeSelector)
392
+ .on('set', this.setVolume.bind(this));
393
+ this.tvSpeakerService
394
+ .getCharacteristic(Characteristic.Mute)
395
+ .on('set', this.setMute.bind(this));
396
+ this.tvAccesory.addService(this.tvSpeakerService);
397
+ this.tvService.addLinkedService(this.tvSpeakerService);
398
+ }
399
+
400
+ setupInputSourcesService() {
401
+ logDebug('setupInputSourcesService: ' + this.name);
402
+ if (this.inputs === undefined || this.inputs === null || this.inputs.length <= 0) {
403
+ return;
404
+ }
405
+
406
+ if (Array.isArray(this.inputs) === false) {
407
+ this.inputs = [this.inputs];
408
+ }
409
+
410
+ let savedNames = {};
411
+
412
+ this.inputs.forEach((value, i) => {
413
+
414
+ // get inputID
415
+ let inputID = null;
416
+
417
+ if (value.inputID !== undefined) {
418
+ inputID = value.inputID;
419
+ } else {
420
+ inputID = value;
421
+ }
422
+
423
+ // get name
424
+ let inputName = inputID;
425
+
426
+ if (savedNames && savedNames[inputID]) {
427
+ inputName = savedNames[inputID];
428
+ } else if (value.name) {
429
+ inputName = value.name;
430
+ }
431
+
432
+ // if inputID not null or empty add the input
433
+ if (inputID !== undefined && inputID !== null && inputID !== '') {
434
+ inputID = inputID.replace(/\s/g, ''); // remove all white spaces from the string
435
+
436
+ let tempInput = new Service.InputSource(inputID, 'inputSource' + i);
437
+ tempInput
438
+ .setCharacteristic(Characteristic.Identifier, i)
439
+ .setCharacteristic(Characteristic.ConfiguredName, inputName)
440
+ .setCharacteristic(Characteristic.IsConfigured, Characteristic.IsConfigured.CONFIGURED)
441
+ .setCharacteristic(Characteristic.InputSourceType, Characteristic.InputSourceType.APPLICATION)
442
+ .setCharacteristic(Characteristic.CurrentVisibilityState,
443
+ Characteristic.CurrentVisibilityState.SHOWN);
444
+
445
+ tempInput
446
+ .getCharacteristic(Characteristic.ConfiguredName)
447
+ .on('set', (name, callback) => {
448
+ savedNames[inputID] = name;
449
+ callback()
450
+ });
451
+
452
+ this.tvAccesory.addService(tempInput);
453
+ if (!tempInput.linked)
454
+ this.tvService.addLinkedService(tempInput);
455
+ this.inputIDs.push(inputID);
456
+ }
457
+
458
+ });
459
+ }
460
+ /*****************************************
461
+ * End of TV integration service
462
+ ****************************************/
463
+
464
+
465
+ /*****************************************
466
+ * Start of helper methods
467
+ ****************************************/
468
+ updatetvState(tvStatus) {
469
+ if (!tvStatus) {
470
+ if (this.tvService)
471
+ this.tvService
472
+ .getCharacteristic(Characteristic.Active)
473
+ .updateValue(false); //tv service
474
+ } else {
475
+ if (this.tvService)
476
+ this.tvService
477
+ .getCharacteristic(Characteristic.Active)
478
+ .updateValue(true); //tv service
479
+ }
480
+ }
481
+
482
+ settvState(stateInfo) {
483
+ if (this.zone != stateInfo.zone)
484
+ return;
485
+
486
+ if (stateInfo.power === true || stateInfo.power === false)
487
+ this.updatetvState(this.tv.poweredOn[this.iterator]);
488
+
489
+ if (stateInfo.inputID) {
490
+ if (this.tv.poweredOn[this.iterator]) {
491
+ let inputName = stateInfo.inputID;
492
+ for (let i = 0; i < this.inputIDs.length; i++) {
493
+ if (inputName === this.inputIDs[i]) {
494
+ if (this.inputIDSet === false)
495
+ this.tvService
496
+ .getCharacteristic(Characteristic.ActiveIdentifier)
497
+ .updateValue(i);
498
+ else
499
+ this.inputIDSet = false;
500
+ }
501
+ }
502
+ }
503
+ }
504
+ }
505
+ /*****************************************
506
+ * End of helper methods
507
+ ****************************************/
508
+
509
+ /*****************************************
510
+ * Start of Homebridge Setters/Getters
511
+ ****************************************/
512
+ getPowerState(callback) {
513
+ if (traceOn)
514
+ logDebug('DEBUG: getPowerState: '+ this.name);
515
+
516
+ callback(null, this.tv.poweredOn[this.iterator] ? 1 : 0);
517
+ }
518
+
519
+ setPowerState(state, callback) {
520
+ if (traceOn)
521
+ logDebug('DEBUG: setPowerState' + state + ': ' + this.name);
522
+
523
+ if (state === 0)
524
+ state = false;
525
+ else if (state === 1)
526
+ state = true;
527
+ var stateString;
528
+ if (this.zone == 1)
529
+ stateString = 'POWR' + (state ? '1 ' : '0 ');
530
+ this.tv.send(stateString);
531
+ /* Update possible other switches and accessories too */
532
+ let stateInfo = {
533
+ zone: this.zone,
534
+ power: state,
535
+ inputID: null,
536
+ masterVol: null,
537
+ mute: null
538
+ }
539
+ this.tv.updateStates(this.tv, stateInfo, this.name);
540
+
541
+ callback();
542
+ }
543
+
544
+
545
+ getAppSwitchState(callback) {
546
+ if (traceOn)
547
+ logDebug('DEBUG: getAppSwitchState: ' + this.name);
548
+
549
+ if (this.tv.poweredOn[this.iterator]) {
550
+ let inputName = this.tv.currentInputID[this.iterator];
551
+ for (let i = 0; i < this.inputIDs.length; i++) {
552
+ if (inputName === this.inputIDs[i]) {
553
+ this.tvService
554
+ .getCharacteristic(Characteristic.ActiveIdentifier)
555
+ .updateValue(i);
556
+ callback(null, i);
557
+ return;
558
+ }
559
+ }
560
+ }
561
+ callback(null, 0);
562
+ }
563
+
564
+ setAppSwitchState(state, callback, inputName) {
565
+ if (traceOn)
566
+ logDebug('DEBUG: setAppSwitchState zone: ' + this.name);
567
+
568
+ this.inputIDSet = true;
569
+
570
+ var level = this.defaultVolume[inputName];
571
+
572
+ var inputString;
573
+ let inputNameN = inputName.replace('/', '%2F');
574
+ if (this.zone == 1) {
575
+ inputString = 'IAVD' + inputNameN+' ';
576
+ }
577
+
578
+ var that = this;
579
+
580
+
581
+
582
+ that.tv.send(inputString);
583
+
584
+ /* Update possible other switches and accessories too */
585
+ let stateInfo = {
586
+ zone: that.zone,
587
+ power: that.tv.poweredOn[that.iterator],
588
+ inputID: inputName
589
+ }
590
+ that.tv.updateStates(that.tv, stateInfo, that.name);
591
+
592
+ callback();
593
+ }
594
+
595
+ setVolume(state, callback) {
596
+ logDebug('DEBUG: setVolume ' + state + ': ' + this.name);
597
+
598
+ var that = this;
599
+ if (this.tv.poweredOn[this.iterator]) {
600
+ var stateString = state ? 'RCKY32 ' : 'RCKY33 '; // UP : DOWN
601
+ that.tv.send(stateString);
602
+ }
603
+ callback();
604
+ }
605
+
606
+ setMute(callback) {
607
+ logDebug('DEBUG: setMute: ' + this.name);
608
+
609
+ var that = this;
610
+ if (this.tv.poweredOn[this.iterator])
611
+ that.tv.send('RCKY31 ');
612
+ callback();
613
+ }
614
+
615
+ remoteKeyPress(remoteKey, callback) {
616
+ var ctrlString = '';
617
+ switch (remoteKey) {
618
+ case Characteristic.RemoteKey.INFORMATION:
619
+ ctrlString = 'RCKY13';
620
+ break;
621
+ case Characteristic.RemoteKey.ARROW_UP:
622
+ ctrlString = 'RCKY41';
623
+ break;
624
+ case Characteristic.RemoteKey.ARROW_DOWN:
625
+ ctrlString = 'RCKY42';
626
+ break;
627
+ case Characteristic.RemoteKey.ARROW_LEFT:
628
+ ctrlString = 'RCKY43';
629
+ break;
630
+ case Characteristic.RemoteKey.ARROW_RIGHT:
631
+ ctrlString = 'RCKY44';
632
+ break;
633
+ case Characteristic.RemoteKey.SELECT:
634
+ ctrlString = 'RCKY40';
635
+ break;
636
+ case Characteristic.RemoteKey.BACK:
637
+ ctrlString = 'RCKY45';
638
+ break;
639
+ case Characteristic.RemoteKey.EXIT:
640
+ ctrlString = 'RCKY46';
641
+ break;
642
+ case Characteristic.RemoteKey.PLAY_PAUSE:
643
+ ctrlString = 'RCKY38';
644
+ break;
645
+ }
646
+
647
+ if (ctrlString != '' && this.tv.poweredOn[this.iterator]) {
648
+ this.tv.send(ctrlString+' ');
649
+ }
650
+ callback();
651
+ }
652
+
653
+
654
+ getName() {
655
+ return this.name;
656
+ }
657
+ /*****************************************
658
+ * End of Homebridge Setters/Getters
659
+ ****************************************/
660
+ }
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "homebridge-sharp-aquos-tv",
3
+ "version": "3.0.1",
4
+ "description": "Sharp Aquos TV control",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/traviswparker/homebridge-sharp-tv.git"
12
+ },
13
+ "keywords": [
14
+ "homebridge",
15
+ "homebridge-plugin",
16
+ "HomeKit",
17
+ "homebridge-sharp-aquos",
18
+ "Sharp",
19
+ "Aquos",
20
+ "TV"
21
+ ],
22
+ "author": "Travis Parker, Nicolas Neubauer, Mart van Vliet",
23
+ "license": "MIT",
24
+ "bugs": {
25
+ "url": "https://github.com/traviswparker/homebridge-sharp-aquos/issues"
26
+ },
27
+ "homepage": "https://github.com/traviswparker/homebridge-sharp-aquos#readme",
28
+ "engines": {
29
+ "node": ">=9.11.2",
30
+ "homebridge": ">=0.4.53",
31
+ "hap-nodejs": ">=0.4.13"
32
+ },
33
+ "dependencies": {
34
+ "telnet-client": ">=1.2.11"
35
+ }
36
+ }