homebridge-roon-outputs
Advanced tools
Comparing version 0.1.3 to 0.1.4
@@ -1,3 +0,4 @@ | ||
import { PlatformAccessory, CharacteristicGetCallback } from 'homebridge'; | ||
import { PlatformAccessory, CharacteristicValue, CharacteristicGetCallback } from 'homebridge'; | ||
import { RoonOutputsPlatform } from './platform'; | ||
declare type RoonApiControlMethod = 'play' | 'pause' | 'playpause' | 'stop' | 'previous' | 'next'; | ||
/** | ||
@@ -16,3 +17,4 @@ * Roon Outputs Platform Accessory. | ||
*/ | ||
getRoonZoneState(): number; | ||
getRoonZoneState(): 1 | 0 | 2; | ||
getRoonZoneMethod(state: CharacteristicValue): RoonApiControlMethod; | ||
/** | ||
@@ -23,8 +25,5 @@ * Get the currentMediaState. | ||
/** | ||
* Set the targetMediaState. | ||
* We aren't allowing Homekit to set the value for us, instead we call the RoonApiTransport.control method | ||
* with 'playpause' which does a great job of stopping and starting the output. | ||
* Combined with the setInterval in the constructor the output status should generally be good. | ||
* Set the targetMediaState and control the Roon Zone playback status | ||
*/ | ||
setTargetMediaState(value: any, callback: CharacteristicGetCallback): void; | ||
setTargetMediaState(value: any, callback: any): void; | ||
/** | ||
@@ -36,2 +35,3 @@ * Get the targetMediaState. | ||
} | ||
export {}; | ||
//# sourceMappingURL=platformAccessory.d.ts.map |
@@ -13,3 +13,4 @@ "use strict"; | ||
this.targetMediaState = this.platform.Characteristic.CurrentMediaState.PAUSE; | ||
this.accessory.getService(this.platform.Service.AccessoryInformation) | ||
this.accessory | ||
.getService(this.platform.Service.AccessoryInformation) | ||
.setCharacteristic(this.platform.Characteristic.Manufacturer, 'Roon') | ||
@@ -19,4 +20,4 @@ .setCharacteristic(this.platform.Characteristic.Model, 'Output') | ||
this.service = | ||
this.accessory.getService(this.platform.Service.SmartSpeaker) | ||
|| this.accessory.addService(this.platform.Service.SmartSpeaker); | ||
this.accessory.getService(this.platform.Service.SmartSpeaker) || | ||
this.accessory.addService(this.platform.Service.SmartSpeaker); | ||
// Allows name to show when adding speaker. | ||
@@ -26,5 +27,7 @@ // This has the added benefit of keeping the speaker name in sync with Roon and your config. | ||
// Event handlers for CurrentMediaState and TargetMediaState Characteristics. | ||
this.service.getCharacteristic(this.platform.Characteristic.CurrentMediaState) | ||
this.service | ||
.getCharacteristic(this.platform.Characteristic.CurrentMediaState) | ||
.on("get" /* GET */, this.getCurrentMediaState.bind(this)); | ||
this.service.getCharacteristic(this.platform.Characteristic.TargetMediaState) | ||
this.service | ||
.getCharacteristic(this.platform.Characteristic.TargetMediaState) | ||
.on("set" /* SET */, this.setTargetMediaState.bind(this)) | ||
@@ -35,3 +38,5 @@ .on("get" /* GET */, this.getTargetMediaState.bind(this)); | ||
this.currentMediaState = this.getRoonZoneState(); | ||
this.service.getCharacteristic(this.platform.Characteristic.CurrentMediaState).updateValue(this.currentMediaState); | ||
this.service | ||
.getCharacteristic(this.platform.Characteristic.CurrentMediaState) | ||
.updateValue(this.currentMediaState); | ||
}, 3000); | ||
@@ -48,14 +53,37 @@ } | ||
} | ||
let state = 0; | ||
// These are the state strings returned by zone_by_zone_id. | ||
if (zone.state === 'playing') { | ||
state = this.platform.Characteristic.CurrentMediaState.PLAY; | ||
switch (zone.state) { | ||
case 'playing': { | ||
return this.platform.Characteristic.CurrentMediaState.PLAY; | ||
} | ||
case 'paused': | ||
case 'loading': { | ||
return this.platform.Characteristic.CurrentMediaState.PAUSE; | ||
} | ||
case 'stopped': { | ||
return this.platform.Characteristic.CurrentMediaState.STOP; | ||
} | ||
default: { | ||
return this.platform.Characteristic.CurrentMediaState.STOP; | ||
} | ||
} | ||
if (zone.state === 'paused' || zone.state === 'loading') { | ||
state = this.platform.Characteristic.CurrentMediaState.PAUSE; | ||
} | ||
/* | ||
* Utility to convert HomeKit State to Roon control API method | ||
* @see https://roonlabs.github.io/node-roon-api/other_node-roon-api-transport_lib.js.html | ||
*/ | ||
getRoonZoneMethod(state) { | ||
switch (state) { | ||
case this.platform.Characteristic.TargetMediaState.PLAY: { | ||
return 'play'; | ||
} | ||
case this.platform.Characteristic.TargetMediaState.PAUSE: { | ||
return 'pause'; | ||
} | ||
case this.platform.Characteristic.TargetMediaState.STOP: { | ||
return 'stop'; | ||
} | ||
default: { | ||
return 'stop'; | ||
} | ||
} | ||
if (zone.state === 'stopped') { | ||
state = this.platform.Characteristic.CurrentMediaState.STOP; | ||
} | ||
return state; | ||
} | ||
@@ -71,6 +99,3 @@ /** | ||
/** | ||
* Set the targetMediaState. | ||
* We aren't allowing Homekit to set the value for us, instead we call the RoonApiTransport.control method | ||
* with 'playpause' which does a great job of stopping and starting the output. | ||
* Combined with the setInterval in the constructor the output status should generally be good. | ||
* Set the targetMediaState and control the Roon Zone playback status | ||
*/ | ||
@@ -80,7 +105,21 @@ setTargetMediaState(value, callback) { | ||
this.platform.log.debug('Triggered SET TargetMediaState:', value); | ||
// Use playpause here as it's more versatile. | ||
// @see https://roonlabs.github.io/node-roon-api/other_node-roon-api-transport_lib.js.html | ||
this.platform.core.services.RoonApiTransport.control(this.accessory.context.output.zone_id, 'playpause', () => { | ||
callback(null); | ||
}); | ||
if (this.targetMediaState !== this.currentMediaState) { | ||
// Only trigger state change if current and target states differ | ||
// This makes automations and scenes work properly | ||
const method = this.getRoonZoneMethod(this.targetMediaState); | ||
this.platform.log.debug('Invoking RoonApiTransport.control with:', method); | ||
// @see https://roonlabs.github.io/node-roon-api/other_node-roon-api-transport_lib.js.html | ||
this.platform.core.services.RoonApiTransport.control(this.accessory.context.output.zone_id, method, (error) => { | ||
if (error) { | ||
this.platform.log.debug('RoonApiTransport.control Error:', error); | ||
callback(error); | ||
} | ||
else { | ||
this.platform.log.debug('RoonApiTransport.control Complete'); | ||
} | ||
}); | ||
} | ||
// Update the HomeKit state right away to prevent delays and warnings | ||
// @see https://github.com/homebridge/homebridge/wiki/Characteristic-Warnings | ||
callback(null, value); | ||
} | ||
@@ -94,3 +133,3 @@ /** | ||
this.platform.log.debug('Triggered GET CurrentMediaState:', state); | ||
callback(undefined, state); | ||
callback(null, state); | ||
} | ||
@@ -97,0 +136,0 @@ } |
{ | ||
"displayName": "Homebridge Roon Outputs", | ||
"name": "homebridge-roon-outputs", | ||
"version": "0.1.3", | ||
"version": "0.1.4", | ||
"description": "Roon Ouputs (Endpoint) integration with Homekit using Homebridge", | ||
@@ -23,3 +23,6 @@ "license": "Apache-2.0", | ||
"build": "rimraf ./dist && tsc", | ||
"prepublishOnly": "npm run lint && npm run build" | ||
"prepublishOnly": "npm run lint && npm run build", | ||
"format": "prettier --loglevel warn --write \"src/*.{ts,md}\"", | ||
"posttest": "npm run format", | ||
"prepare": "husky install" | ||
}, | ||
@@ -40,7 +43,16 @@ "keywords": [ | ||
"homebridge": "^1.1.1", | ||
"husky": "^6.0.0", | ||
"lint-staged": "^10.5.4", | ||
"nodemon": "^2.0.4", | ||
"prettier": "^2.2.1", | ||
"rimraf": "^3.0.2", | ||
"ts-node": "^8.10.2", | ||
"typescript": "^3.9.5" | ||
}, | ||
"lint-staged": { | ||
"*.ts": [ | ||
"eslint --cache --fix", | ||
"prettier --write" | ||
] | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
42114
25
378
12