homebridge-denon-speaker
Version:
Denon and Marantz AVR support as Speaker for Homebridge: https://github.com/nfarina/homebridge
179 lines • 7.19 kB
JavaScript
"use strict";
const node_util_1 = require("node:util");
const denon_lib_1 = require("./lib/denon-lib");
let hap;
class DenonSpeakerAccessory {
log;
name;
pollingInterval;
doPolling;
/* Characteristic States */
speakerState = {
active: false,
volume: 0,
mute: false,
};
speakerService;
informationService;
denonLib;
cacheTimeout = 5; // durée de validité du cache en secondes
lastUpdate = 0;
constructor(log, config) {
this.log = log;
this.name = config.name;
this.speakerState.volume = config.defaultVolume;
this.pollingInterval = config.pollingInterval || 30;
this.doPolling = config.doPolling || true;
this.denonLib = new denon_lib_1.DenonLib(config.ip);
// Set AccessoryInformation
this.informationService = new hap.Service.AccessoryInformation()
.setCharacteristic(hap.Characteristic.Manufacturer, 'Denon');
this.informationService.getCharacteristic(hap.Characteristic.Model)
.onGet(this.getModel.bind(this));
// Set Speaker Characteristic
this.speakerService = new hap.Service.Speaker(this.name);
// Configure AccessoryInformation
this.informationService
.setCharacteristic(hap.Characteristic.Manufacturer, 'Denon')
.setCharacteristic(hap.Characteristic.SerialNumber, '123-456-789')
.setCharacteristic(hap.Characteristic.FirmwareRevision, '1.0.0');
// Configure required Speaker characteristics
this.speakerService.getCharacteristic(hap.Characteristic.Mute)
.onGet(this.getMuteState.bind(this))
.onSet(this.setMuteState.bind(this));
this.speakerService.getCharacteristic(hap.Characteristic.Active)
.onGet(this.getActiveState.bind(this))
.onSet(this.setActiveState.bind(this))
.updateValue(false); // État initial
this.speakerService.getCharacteristic(hap.Characteristic.Volume)
.onGet(this.getVolumeState.bind(this))
.onSet(this.setVolumeState.bind(this))
.setProps({
minValue: 0,
maxValue: 98,
minStep: 2,
});
if (this.doPolling) {
this.log.debug(`Refresh every ${this.pollingInterval} sec`);
setInterval(async () => {
this.log.debug('Triggering updateSpeakerState');
const updated = await this.updateAllStates();
if (updated) {
// Ne mettre à jour HomeKit que si les valeurs ont changé
this.speakerService.updateCharacteristic(hap.Characteristic.Mute, this.speakerState.mute);
this.speakerService.updateCharacteristic(hap.Characteristic.Active, this.speakerState.active);
this.speakerService.updateCharacteristic(hap.Characteristic.Volume, this.speakerState.volume);
this.log.debug('États mis à jour dans HomeKit');
}
}, this.pollingInterval * 1000);
// Mise à jour initiale des états
this.updateAllStates().catch(error => {
this.log.error('Erreur lors de la mise à jour initiale:', error);
});
}
log.info(`${this.name} finished initializing!`);
}
/*
* This method is optional to implement. It is called when HomeKit ask to identify the accessory.
* Typical this only ever happens at the pairing process.
*/
identify() {
this.log('Identify!');
}
/*
* This method is called directly after creation of this instance.
* It should return all services which should be added to the accessory.
*/
getServices() {
return [
this.informationService,
this.speakerService,
];
}
getModel() {
return this.denonLib.getModelInfo().then((modelInfo) => {
return modelInfo.model;
});
}
async getMuteState() {
await this.updateAllStates();
const muteState = this.speakerState.mute;
this.log.info('getMuteState: ' + (muteState ? 'ON' : 'OFF'));
return muteState;
}
async setMuteState(wantedMuteState) {
await this.denonLib.setMuteState(wantedMuteState)
.then((muteState) => {
this.log.debug('setMuteState: ' + (muteState ? 'ON' : 'OFF'));
this.speakerState.mute = muteState;
})
.catch((error) => {
this.log('setMuteState error: ' + error.message);
return Promise.reject(error);
});
}
async getActiveState() {
await this.updateAllStates();
const activeState = this.speakerState.active;
this.log.info('getActiveState: ' + (activeState ? 'ON' : 'OFF'));
return activeState;
}
async setActiveState(wantedActiveState) {
try {
const activeState = await this.denonLib.setPowerState(wantedActiveState);
this.log('setActiveState: ' + (activeState ? 'ON' : 'OFF'));
this.speakerState.active = activeState;
}
catch (error) {
this.log('setActiveState error: ' + error.message);
throw error;
}
}
async getVolumeState() {
// On utilise la valeur en cache si elle est récente
const now = Date.now();
if (now - this.lastUpdate >= this.cacheTimeout * 1000) {
await this.updateAllStates();
}
const volumeState = this.speakerState.volume;
this.log.info('getVolumeState: ' + volumeState);
return volumeState;
}
async setVolumeState(wantedVolumeState) {
try {
const volumeState = await this.denonLib.setVolume(wantedVolumeState);
this.log('setVolumeState: ' + volumeState);
this.speakerState.volume = volumeState;
}
catch (error) {
this.log('setVolumeState error: ' + error.message);
throw error;
}
}
async updateAllStates() {
let updated = false;
const currentTime = Math.floor(Date.now() / 1000);
if (currentTime - this.lastUpdate < this.cacheTimeout) {
this.log.debug('Using cached data for updateAllStates');
return false; // Don’t update if the cached data is still valid
}
await this.denonLib.getStatus()
.then((statusLite) => {
this.log.debug((0, node_util_1.inspect)(statusLite));
this.speakerState.active = statusLite.powerState;
this.speakerState.volume = statusLite.volumeState;
this.speakerState.mute = statusLite.muteState;
updated = true;
this.lastUpdate = currentTime; // Update the lastUpdate time
})
.catch((error) => {
this.log('updateAllStates Error : ' + error.message);
});
return updated;
}
}
module.exports = (api) => {
hap = api.hap;
api.registerAccessory('homebridge-denon-speaker', 'DenonAVRSpeaker', DenonSpeakerAccessory);
};
//# sourceMappingURL=homebridge-denon-speaker.js.map