Skip to content

Commit

Permalink
added validation config, added reconnect function if fail on first run
Browse files Browse the repository at this point in the history
  • Loading branch information
grzegorz914 committed Oct 26, 2024
1 parent 5f1a8d8 commit 877f2af
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 113 deletions.
1 change: 1 addition & 0 deletions config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"pluginType": "platform",
"singular": true,
"fixArrays": true,
"strictValidation": true,
"customUi": true,
"headerDisplay": "This plugin works with Xbox Game Consoles. Devices are exposed to HomeKit as separate accessories and each needs to be manually paired.",
"footerDisplay": "For documentation please see [GitHub repository](https://github.com/grzegorz914/homebridge-xbox-tv).",
Expand Down
47 changes: 31 additions & 16 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
const path = require('path');
const fs = require('fs');
const XboxDevice = require('./src/xboxdevice.js');
const ImpulseGenerator = require('./src/impulsegenerator.js');
const CONSTANTS = require('./src/constants.json');

class XboxPlatform {
Expand All @@ -25,17 +26,17 @@ class XboxPlatform {
api.on('didFinishLaunching', async () => {
for (const device of config.devices) {
const deviceName = device.name ?? false;
const deviceHost = device.host ?? false;
const host = device.host ?? false;
const xboxLiveId = device.xboxLiveId ?? false;

if (!deviceName || !deviceHost || !xboxLiveId) {
log.warn(`Name: ${deviceName ? 'OK' : deviceName}, Host: ${deviceHost ? 'OK' : deviceHost}, Xbox Live ID: ${xboxLiveId ? 'OK' : xboxLiveId}, wrong or missing.`);
if (!deviceName || !host || !xboxLiveId) {
log.warn(`Name: ${deviceName ? 'OK' : deviceName}, Host: ${host ? 'OK' : host}, Xbox Live ID: ${xboxLiveId ? 'OK' : xboxLiveId}, wrong or missing.`);
return;
}

//debug config
const debugMode = device.enableDebugMode;
const debug = debugMode ? log.info(`Device: ${deviceHost} ${deviceName}, did finish launching.`) : false;
const enableDebugMode = device.enableDebugMode;
const debug = enableDebugMode ? log.info(`Device: ${host} ${deviceName}, Did finish launching.`) : false;
const config = {
...device,
xboxLiveId: 'removed',
Expand All @@ -46,10 +47,10 @@ class XboxPlatform {
passwd: 'removed'
}
};
const debug1 = debugMode ? log.info(`Device: ${deviceHost} ${deviceName}, Config: ${JSON.stringify(config, null, 2)}`) : false;
const debug1 = enableDebugMode ? log.info(`Device: ${host} ${deviceName}, Config: ${JSON.stringify(config, null, 2)}`) : false;

//check files exists, if not then create it
const postFix = deviceHost.split('.').join('');
const postFix = host.split('.').join('');
const authTokenFile = `${prefDir}/authToken_${postFix}`;
const devInfoFile = `${prefDir}/devInfo_${postFix}`;
const inputsFile = `${prefDir}/inputs_${postFix}`;
Expand All @@ -72,7 +73,7 @@ class XboxPlatform {
}
});
} catch (error) {
log.error(`Device: ${deviceHost} ${deviceName}, prepare files error: ${error}`);
log.error(`Device: ${host} ${deviceName}, Prepare files error: ${error}`);
return;
}

Expand All @@ -81,30 +82,44 @@ class XboxPlatform {
const xboxDevice = new XboxDevice(api, device, authTokenFile, devInfoFile, inputsFile, inputsNamesFile, inputsTargetVisibilityFile);
xboxDevice.on('publishAccessory', (accessory) => {
api.publishExternalAccessories(CONSTANTS.PluginName, [accessory]);
log.success(`Device: ${deviceHost} ${deviceName}, published as external accessory.`);
log.success(`Device: ${host} ${deviceName}, Published as external accessory.`);
})
.on('devInfo', (devInfo) => {
log.info(devInfo);
})
.on('success', (message) => {
log.success(`Device: ${deviceHost} ${deviceName}, ${message}`);
log.success(`Device: ${host} ${deviceName}, ${message}`);
})
.on('message', (message) => {
log.info(`Device: ${deviceHost} ${deviceName}, ${message}`);
log.info(`Device: ${host} ${deviceName}, ${message}`);
})
.on('debug', (debug) => {
log.info(`Device: ${deviceHost} ${deviceName}, debug: ${debug}`);
log.info(`Device: ${host} ${deviceName}, debug: ${debug}`);
})
.on('warn', (warn) => {
log.warn(`warn: ${deviceHost} ${deviceName}, ${warn}`);
log.warn(`warn: ${host} ${deviceName}, ${warn}`);
})
.on('error', (error) => {
log.error(`Device: ${deviceHost} ${deviceName}, ${error}`);
log.error(`Device: ${host} ${deviceName}, ${error}`);
});

await xboxDevice.start();
//create impulse generator
const impulseGenerator = new ImpulseGenerator();
impulseGenerator.on('start', async () => {
try {
await xboxDevice.start();
impulseGenerator.stop();
} catch (error) {
const logError = disableLogConnectError ? false : log.error(`Device: ${host} ${deviceName}, ${error}, trying again.`);
};
}).on('state', (state) => {
const debug = enableDebugMode ? state ? log.info(`Device: ${host} ${deviceName}, Start impulse generator started.`) : log.info(`Device: ${host} ${deviceName}, Start impulse generator stopped.`) : false;
});

//start impulse generator
impulseGenerator.start([{ name: 'start', sampling: 45000 }]);
} catch (error) {
log.error(`Device: ${deviceHost} ${deviceName}, did finish launching error: ${error}`);
log.error(`Device: ${host} ${deviceName}, Did finish launching error: ${error}`);
}
}
});
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"displayName": "Xbox TV",
"name": "homebridge-xbox-tv",
"version": "3.1.17",
"version": "3.1.18-beta.0",
"description": "Homebridge plugin to control Xbox game consoles.",
"license": "MIT",
"author": "grzegorz914",
Expand Down
2 changes: 2 additions & 0 deletions src/impulsegenerator.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ class ImpulseGenerator extends EventEmitter {

this.timers = [];
for (const timer of timers) {
this.emit(timer.name);

const newTimer = setInterval(() => {
this.emit(timer.name);
}, timer.sampling);
Expand Down
4 changes: 3 additions & 1 deletion src/webApi/xboxwebapi.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ class XBOXWEBAPI extends EventEmitter {
} catch (error) {
this.emit('error', error);
};
}).on('state', (state) => { });
}).on('state', (state) => {
const emitState = state ? this.emit('success', `Web Api monitoring started.`) : this.emit('warn', `Web Api monitoring stopped.`);
});
}

async checkAuthorization() {
Expand Down
192 changes: 97 additions & 95 deletions src/xboxdevice.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ class XboxDevice extends EventEmitter {
};
this.power = power;
})
.on('success', (message) => {
this.emit('success', message);
})
.on('message', (message) => {
this.emit('message', message);
})
Expand Down Expand Up @@ -214,100 +217,6 @@ class XboxDevice extends EventEmitter {
.setCharacteristic(Characteristic.FirmwareRevision, firmwareRevision);
};
})
.on('stateChanged', (power, volume, mute, mediaState, titleId, reference) => {
const input = this.inputsConfigured.find(input => input.reference === reference || input.titleId === titleId) ?? false;
const inputIdentifier = input ? input.identifier : this.inputIdentifier;

//update characteristics
if (this.televisionService) {
this.televisionService
.updateCharacteristic(Characteristic.Active, power);
};

if (this.televisionService) {
this.televisionService
.updateCharacteristic(Characteristic.ActiveIdentifier, inputIdentifier);
};

if (this.speakerService) {
this.speakerService
.updateCharacteristic(Characteristic.Volume, volume)
.updateCharacteristic(Characteristic.Mute, mute);
if (this.volumeService) {
this.volumeService
.updateCharacteristic(Characteristic.Brightness, volume)
.updateCharacteristic(Characteristic.On, !mute);
};
if (this.volumeServiceFan) {
this.volumeServiceFan
.updateCharacteristic(Characteristic.RotationSpeed, volume)
.updateCharacteristic(Characteristic.On, !mute);
};
};

if (this.sensorPowerService) {
this.sensorPowerService
.updateCharacteristic(Characteristic.ContactSensorState, power);
}

if (this.sensorInputService && reference !== this.reference) {
for (let i = 0; i < 2; i++) {
const state = power ? [true, false][i] : false;
this.sensorInputService
.updateCharacteristic(Characteristic.ContactSensorState, state);
this.sensorInputState = state;
}
}

if (this.sensorScreenSaverService) {
const state = power ? (reference === 'Xbox.IdleScreen_8wekyb3d8bbwe!Xbox.IdleScreen.Application') : false;
this.sensorScreenSaverService
.updateCharacteristic(Characteristic.ContactSensorState, state);
this.sensorScreenSaverState = state;
}

if (this.sensorsInputsServices) {
for (let i = 0; i < this.sensorsInputsConfiguredCount; i++) {
const sensorInput = this.sensorsInputsConfigured[i];
const state = power ? sensorInput.reference === reference : false;
sensorInput.state = state;
const characteristicType = sensorInput.characteristicType;
this.sensorsInputsServices[i]
.updateCharacteristic(characteristicType, state);
}
}

//buttons
if (this.buttonsServices) {
for (let i = 0; i < this.buttonsConfiguredCount; i++) {
const button = this.buttonsConfigured[i];
const state = this.power ? button.reference === reference : false;
button.state = state;
this.buttonsServices[i]
.updateCharacteristic(Characteristic.On, state);
}
}

this.inputIdentifier = inputIdentifier;
this.power = power;
this.reference = reference;
this.volume = volume;
this.mute = mute;
this.mediaState = mediaState;

if (!this.disableLogInfo) {
const name = input ? input.name : reference;
const productId = input ? input.oneStoreProductId : reference;
this.emit('message', `Power: ${power ? 'ON' : 'OFF'}`);
this.emit('message', `Input Name: ${name}`);
this.emit('message', `Reference: ${reference}`);
this.emit('message', `Title Id: ${titleId}`);
this.emit('message', `Product Id: ${productId}`);
this.emit('message', `Volume: ${volume}%`);
this.emit('message', `Mute: ${mute ? 'ON' : 'OFF'}`);
this.emit('message', `Media State: ${['PLAY', 'PAUSE', 'STOPPED', 'LOADING', 'INTERRUPTED'][mediaState]}`);
};
})
.on('externalIntegrations', () => {
try {
//RESTFul server
Expand Down Expand Up @@ -411,13 +320,106 @@ class XboxDevice extends EventEmitter {

//sort inputs list
const sortInputsDisplayOrder = this.televisionService ? await this.displayOrder() : false;

this.startPrepareAccessory = false;
} catch (error) {
throw new Error(`
Prepare accessory error: ${error.message || error}`);
};
})
.on('stateChanged', (power, volume, mute, mediaState, titleId, reference) => {
const input = this.inputsConfigured.find(input => input.reference === reference || input.titleId === titleId) ?? false;
const inputIdentifier = input ? input.identifier : this.inputIdentifier;

//update characteristics
if (this.televisionService) {
this.televisionService
.updateCharacteristic(Characteristic.Active, power);
};

if (this.televisionService) {
this.televisionService
.updateCharacteristic(Characteristic.ActiveIdentifier, inputIdentifier);
};

if (this.speakerService) {
this.speakerService
.updateCharacteristic(Characteristic.Volume, volume)
.updateCharacteristic(Characteristic.Mute, mute);
if (this.volumeService) {
this.volumeService
.updateCharacteristic(Characteristic.Brightness, volume)
.updateCharacteristic(Characteristic.On, !mute);
};
if (this.volumeServiceFan) {
this.volumeServiceFan
.updateCharacteristic(Characteristic.RotationSpeed, volume)
.updateCharacteristic(Characteristic.On, !mute);
};
};

if (this.sensorPowerService) {
this.sensorPowerService
.updateCharacteristic(Characteristic.ContactSensorState, power);
}

if (this.sensorInputService && reference !== this.reference) {
for (let i = 0; i < 2; i++) {
const state = power ? [true, false][i] : false;
this.sensorInputService
.updateCharacteristic(Characteristic.ContactSensorState, state);
this.sensorInputState = state;
}
}

if (this.sensorScreenSaverService) {
const state = power ? (reference === 'Xbox.IdleScreen_8wekyb3d8bbwe!Xbox.IdleScreen.Application') : false;
this.sensorScreenSaverService
.updateCharacteristic(Characteristic.ContactSensorState, state);
this.sensorScreenSaverState = state;
}

if (this.sensorsInputsServices) {
for (let i = 0; i < this.sensorsInputsConfiguredCount; i++) {
const sensorInput = this.sensorsInputsConfigured[i];
const state = power ? sensorInput.reference === reference : false;
sensorInput.state = state;
const characteristicType = sensorInput.characteristicType;
this.sensorsInputsServices[i]
.updateCharacteristic(characteristicType, state);
}
}

//buttons
if (this.buttonsServices) {
for (let i = 0; i < this.buttonsConfiguredCount; i++) {
const button = this.buttonsConfigured[i];
const state = this.power ? button.reference === reference : false;
button.state = state;
this.buttonsServices[i]
.updateCharacteristic(Characteristic.On, state);
}
}

this.inputIdentifier = inputIdentifier;
this.power = power;
this.reference = reference;
this.volume = volume;
this.mute = mute;
this.mediaState = mediaState;

if (!this.disableLogInfo) {
const name = input ? input.name : reference;
const productId = input ? input.oneStoreProductId : reference;
this.emit('message', `Power: ${power ? 'ON' : 'OFF'}`);
this.emit('message', `Input Name: ${name}`);
this.emit('message', `Reference: ${reference}`);
this.emit('message', `Title Id: ${titleId}`);
this.emit('message', `Product Id: ${productId}`);
this.emit('message', `Volume: ${volume}%`);
this.emit('message', `Mute: ${mute ? 'ON' : 'OFF'}`);
this.emit('message', `Media State: ${['PLAY', 'PAUSE', 'STOPPED', 'LOADING', 'INTERRUPTED'][mediaState]}`);
};
})
.on('success', (message) => {
this.emit('success', message);
})
Expand Down

0 comments on commit 877f2af

Please sign in to comment.