Skip to content

Commit

Permalink
"ready" event now returns controller object with scanned devices and …
Browse files Browse the repository at this point in the history
…functions
  • Loading branch information
Rafostar committed Jul 25, 2019
1 parent 0db5191 commit 9dec1cd
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 109 deletions.
145 changes: 59 additions & 86 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ module.exports = class Client
this.sourceNumber = 0;
this.keyReleaseTimeout = null;

this.cec = { ...EventEmitter.prototype, ...this._getGlobalFunctions() };
this.cec = new EventEmitter()
this.myDevice = null;
this.devices = {};

this._scanDevices();

Expand All @@ -33,19 +34,20 @@ module.exports = class Client
{
if(error) return this.cec.emit('error', new Error('App cec-client had an error!'));

const scannedDevices = this._parseScanOutput(String(stdout));
const scannedKeys = Object.keys(scannedDevices);
this.devices = this._parseScanOutput(String(stdout));

const scannedKeys = Object.keys(this.devices);
if(scannedKeys.length === 0)
return this.cec.emit('error', new Error('CEC scan did not find any devices!'));

this.myDevice = this._getMyDevice(scannedDevices);
this.myDevice = this._getMyDevice(this.devices);
if(!this.myDevice)
return this.cec.emit('error', new Error(`Could not obtain this CEC adapter info!`));

this.cec = { ...this.cec, ...scannedDevices };
for(var deviceId in this.devices)
this.devices[deviceId] = { ...this.devices[deviceId], ...this._getDeviceFunctions(deviceId) };

for(var deviceId in this.cec)
this.cec[deviceId] = { ...this.cec[deviceId], ...this._getDeviceFunctions(deviceId) };
this.devices = { ...this.devices, ...this._getGlobalFunctions() };

this._createClient();
});
Expand Down Expand Up @@ -116,13 +118,13 @@ module.exports = class Client
_createClient()
{
this.doneInit = false;
this.cecClient = spawn('cec-client',
this.client = spawn('cec-client',
['-t', this.type, '-o', this.osdString, '-d', 8],
{ stdio: ['pipe', 'pipe', 'ignore'] });

this.cecClient.stdin.setEncoding('utf8');
this.cecClient.stdout.on('data', (data) => this._parseClientOutput(String(data)));
this.cecClient.once('close', (code) =>
this.client.stdin.setEncoding('utf8');
this.client.stdout.on('data', (data) => this._parseClientOutput(String(data)));
this.client.once('close', (code) =>
{
if(this.doneInit) this._createClient();
else this.cec.emit('error', new Error(`App cec-client exited with code: ${code}`));
Expand All @@ -136,35 +138,23 @@ module.exports = class Client
if(this.myDevice && line.includes('waiting for input'))
{
this.doneInit = true;
this.cec.emit('ready');
this.cec.emit('ready', this.devices);
}

return;
}

if(line.startsWith('power status:'))
{
var logicalAddress = this.cec[this.controlledDevice].logicalAddress;
var logicalAddress = this.devices[this.controlledDevice].logicalAddress;
var value = this._getLineValue(line);

this.cec[this.controlledDevice].powerStatus = value;
this.devices[this.controlledDevice].powerStatus = value;
this.cec.emit(`${logicalAddress}:powerStatus`, value);
}
else if(line.startsWith('active source:')
|| (line.startsWith('logical address') && line.includes('active')))
{
var logicalAddress = this.cec[this.myDevice].logicalAddress;
var value = null;

if(line.startsWith('logical address')) value = (line.includes('not')) ? 'no' : 'yes';
else value = this._getLineValue(line);

this.cec[this.myDevice].activeSource = value;
this.cec.emit(`${logicalAddress}:activeSource`, value);
}
else if(line.startsWith('TRAFFIC:') && line.includes('>>'))
{
var destAddress = this.cec[this.myDevice].logicalAddress;
var destAddress = this.devices[this.myDevice].logicalAddress;
var value = this._getLineValue(line).toUpperCase();

if(line.includes(`>> 0${destAddress}:44:`))
Expand All @@ -186,6 +176,22 @@ module.exports = class Client
}, 600);
}
}
else if(line.startsWith('TRAFFIC:') && line.includes('<<'))
{
var logicalAddress = this.devices[this.myDevice].logicalAddress;
var srcAddress = this.devices[this.myDevice].logicalAddress;

if(line.includes(`<< ${srcAddress}0:04`))
{
this.devices[this.myDevice].activeSource = 'yes';
this.cec.emit(`${logicalAddress}:activeSource`, 'yes');
}
else if(line.includes(`<< ${srcAddress}0:9d`))
{
this.devices[this.myDevice].activeSource = 'no';
this.cec.emit(`${logicalAddress}:activeSource`, 'no');
}
}
}

_getLineValue(line)
Expand All @@ -201,7 +207,7 @@ module.exports = class Client
turnOff: this.changePower.bind(this, deviceId, 'standby')
};

if(this.cec[deviceId].name === 'TV')
if(this.devices[deviceId].name === 'TV')
{
func.changeSource = (number) =>
{
Expand All @@ -211,8 +217,8 @@ module.exports = class Client
number = this.sourceNumber;
}

var srcAddress = this.cec[this.myDevice].logicalAddress;
var destAddress = (this.broadcast === false) ? this.cec[deviceId].logicalAddress : 'F';
var srcAddress = this.devices[this.myDevice].logicalAddress;
var destAddress = (this.broadcast === false) ? this.devices[deviceId].logicalAddress : 'F';

return this.command(`tx ${srcAddress}${destAddress}:82:${number}0:00`, null);
}
Expand Down Expand Up @@ -240,10 +246,10 @@ module.exports = class Client
if(!action || typeof action !== 'string') resolve(null);
else
{
if(!logicalAddress) this.cecClient.stdin.write(action);
else this.cecClient.stdin.write(`${action} ${logicalAddress}`);
if(!logicalAddress) this.client.stdin.write(action);
else this.client.stdin.write(`${action} ${logicalAddress}`);

this.cecClient.stdout.once('data', () => resolve(true));
this.client.stdout.once('data', () => resolve(true));
}
});
}
Expand All @@ -260,7 +266,7 @@ module.exports = class Client
else if(value === powerStatus) resolve(powerStatus);
else
{
this.command(powerStatus, this.cec[deviceId].logicalAddress);
this.command(powerStatus, this.devices[deviceId].logicalAddress);

var timedOut = false;
var actionTimeout = setTimeout(() => timedOut = true, 40000);
Expand Down Expand Up @@ -289,37 +295,27 @@ module.exports = class Client
{
return new Promise((resolve, reject) =>
{
var logicalAddress = this.devices[this.myDevice].logicalAddress;
var activeSource = (isActiveSource === 'yes' || isActiveSource === true) ? 'yes' : 'no';

this.getActive(this.myDevice).then(value =>
if(this.devices[this.myDevice].activeSource === activeSource) resolve(activeSource);
else
{
if(value === null) resolve(null);
else if(value === activeSource) resolve(activeSource);
else
{
var action = (activeSource === 'yes') ? 'as' : 'is';
this.command(action, null);

var timedOut = false;
var actionTimeout = setTimeout(() => timedOut = true, 15000);

var waitActive = () =>
{
this.getActive(this.myDevice).then(value =>
{
if(value !== activeSource && !timedOut)
return waitActive();

clearTimeout(actionTimeout);
var action = (activeSource === 'yes') ? 'as' : 'is';

if(timedOut) resolve(null);
else resolve(activeSource);
});
}
var statusTimeout = setTimeout(() =>
{
this.devices[this.myDevice].activeSource = 'Unknown';
this.cec.emit(`${logicalAddress}:activeSource`, null);
}, 3000);

waitActive();
}
});
this.command(action, null);
this.cec.once(`${logicalAddress}:activeSource`, (value) =>
{
clearTimeout(statusTimeout);
resolve(value);
});
}
});
}

Expand All @@ -329,13 +325,13 @@ module.exports = class Client

return new Promise((resolve, reject) =>
{
var logicalAddress = this.cec[deviceId].logicalAddress;
var logicalAddress = this.devices[deviceId].logicalAddress;

var statusTimeout = setTimeout(() =>
{
this.cec[deviceId].powerStatus = 'Unknown';
this.devices[deviceId].powerStatus = 'Unknown';
this.cec.emit(`${logicalAddress}:powerStatus`, null);
}, 10000);
}, 3000);

this.command(`pow ${logicalAddress}`);
this.cec.once(`${logicalAddress}:powerStatus`, (value) =>
Expand All @@ -345,27 +341,4 @@ module.exports = class Client
});
});
}

getActive(deviceId)
{
this.controlledDevice = deviceId;

return new Promise((resolve, reject) =>
{
var logicalAddress = this.cec[deviceId].logicalAddress;

var activeTimeout = setTimeout(() =>
{
this.cec[deviceId].activeSource = 'Unknown';
this.cec.emit(`${logicalAddress}:activeSource`, null);
}, 10000);

this.command(`ad ${logicalAddress}`);
this.cec.once(`${logicalAddress}:activeSource`, (value) =>
{
clearTimeout(activeTimeout);
resolve(value);
});
});
}
}
15 changes: 15 additions & 0 deletions test/activate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
Turns on TV (if in standby) and switches active source to current device.
*/

const cecInit = require('./shared/init');
const writeLine = require('./shared/writeLine');
cecInit().then(test);

function test(obj)
{
writeLine('');
console.log('--- TV Active Source Changed ---\n');
console.log('CURRENT STATUS');
console.log(obj.controller);
}
21 changes: 11 additions & 10 deletions test/hdmi-switch.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,26 @@
Toggles between 3 available HDMI ports.
Port number can be set with 'hdmiPorts' option when creating new cec-controller object.
Desired port number can also be passed to 'changeSource()' function
(e.g. cec.dev0.changeSource(2) should switch to input 2).
(e.g. ctl.dev0.changeSource(2) should switch to input 2).
*/

const cecInit = require('./shared/init');
const writeLine = require('./shared/writeLine');
cecInit().then(test);

function test()
function test(obj)
{
writeLine();
var ctl = obj.controller;

writeLine('');
console.log('--- TV HDMI Switch Test ---');
changeSource();

writeLine(`Switching port every 5 sec...`);
changeSource(ctl);
}

async function changeSource()
async function changeSource(ctl)
{
writeLine(`Switching HDMI input...`);
await cec.dev0.changeSource();

writeLine(`Switching to next port in 5 sec...`);
setTimeout(changeSource, 5000);
await ctl.dev0.changeSource();
setTimeout(() => changeSource(ctl), 5000);
}
14 changes: 8 additions & 6 deletions test/power.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,19 @@ const cecInit = require('./shared/init');
const writeLine = require('./shared/writeLine');
cecInit().then(test);

function test()
function test(obj)
{
writeLine();
var ctl = obj.controller;

writeLine('');
console.log('--- TV Power Test ---');
writeLine(`Turning OFF in 10 sec...`);
setTimeout(powerOff, 10000);
writeLine('Turning OFF in 15 sec...');
setTimeout(() => powerOff(ctl), 15000);
}

async function powerOff()
async function powerOff(ctl)
{
writeLine('Turning OFF TV...');
await cec.dev0.turnOff();
await ctl.dev0.turnOff();
writeLine('TV should be in standby');
}
6 changes: 4 additions & 2 deletions test/remote.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ const cecInit = require('./shared/init');
const writeLine = require('./shared/writeLine');
cecInit().then(test);

function test()
function test(obj)
{
writeLine();
var cec = obj.cec;

writeLine('');
console.log('--- TV Remote Test ---');
writeLine('Press any button on TV remote');

Expand Down
10 changes: 5 additions & 5 deletions test/shared/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@ module.exports = () =>
writeLine('CEC Controller initializing...');
var cec = new cecController();

cec.on('ready', async() =>
cec.on('ready', async(controller) =>
{
if(cec.dev0.powerStatus !== 'on')
if(controller.dev0.powerStatus === 'standby')
{
writeLine('Turning ON TV...');
await cec.dev0.turnOn();
await controller.dev0.turnOn();
}

writeLine('Setting this device as active source...');
await cec.setActive();
await controller.setActive();

resolve();
resolve({ controller, cec });
});

cec.on('error', (err) => writeLine(err.message));
Expand Down

0 comments on commit 9dec1cd

Please sign in to comment.