UNPKG

homebridge-hilo

Version:

Plugin Homebridge (non officiel) pour la passerelle et les appareils Hilo de Hydro-Québec | Unofficial Homebridge plugin for Hydro-Québec Hilo bridge and devices

165 lines (155 loc) 5.17 kB
import { API, CharacteristicValue, Logging, PlatformAccessory, Service, } from "homebridge"; import { getConfig, HiloConfig } from "../config"; import { Challenge, ChallengeAccessory } from "./types"; import { getLogger } from "../logger"; import { subHours } from "date-fns/subHours"; const phases: ( challenge: Challenge, config: HiloConfig, ) => Record<string, { start: Date; end: Date } | undefined> = ( challenge, config, ) => ({ inProgress: { start: new Date(challenge.phases.preheatStartDateUTC), end: new Date(challenge.phases.recoveryEndDateUTC), }, preheat: { start: new Date(challenge.phases.preheatStartDateUTC), end: new Date(challenge.phases.preheatEndDateUTC), }, reduction: { start: new Date(challenge.phases.reductionStartDateUTC), end: new Date(challenge.phases.reductionEndDateUTC), }, recovery: { start: new Date(challenge.phases.recoveryStartDateUTC), end: new Date(challenge.phases.recoveryEndDateUTC), }, plannedAM: challenge.period === "am" ? { start: subHours( new Date(challenge.phases.preheatStartDateUTC), config.plannedHours, ), end: new Date(challenge.phases.preheatStartDateUTC), } : undefined, plannedPM: challenge.period === "pm" ? { start: subHours( new Date(challenge.phases.preheatStartDateUTC), config.plannedHours, ), end: new Date(challenge.phases.preheatStartDateUTC), } : undefined, }); export class HiloChallengeSensor { private challenges: Record<number, NodeJS.Timeout[]> = {}; protected service: Service | null = null; constructor( protected readonly accessory: PlatformAccessory<ChallengeAccessory>, protected readonly api: API, protected readonly logger: Logging = getLogger(), ) { accessory .getService(this.api.hap.Service.AccessoryInformation)! .setCharacteristic(this.api.hap.Characteristic.Manufacturer, "Hilo") .setCharacteristic(this.api.hap.Characteristic.Model, "Challenge") .setCharacteristic( this.api.hap.Characteristic.SerialNumber, this.accessory.context.v4Device.localId, ); this.service = accessory.getService(this.api.hap.Service.ContactSensor) || accessory.addService(this.api.hap.Service.ContactSensor); this.service.setCharacteristic( this.api.hap.Characteristic.Name, this.accessory.context.v4Device.phase + " Hilo Challenge", ); this.service .getCharacteristic(this.api.hap.Characteristic.ContactSensorState) .onGet(this.getContactSensorState.bind(this)); } updateChallenge(value: boolean) { this.accessory.context.v4Device.value = value; this.service ?.getCharacteristic(this.api.hap.Characteristic.ContactSensorState) ?.updateValue(value); } private async getContactSensorState(): Promise<CharacteristicValue> { const activeChallenge = this.accessory.context.v4Device.value ?? false; this.logger.debug(`Getting active Hilo Challenge: ${activeChallenge}`); return activeChallenge; } async updateChallengeStatus(challenges: Challenge[]) { challenges.forEach((challenge) => { if (challenge.isParticipating) { this.participating(challenge); } else { this.notParticipating(challenge); } }); if ( challenges.filter((challenge) => challenge.isParticipating).length === 0 ) { this.updateChallengeValue(false); } } private updateChallengeValue(active: boolean) { this.updateChallenge(active); } private participating(challenge: Challenge) { if (this.challenges[challenge.id]) { return; } this.challenges[challenge.id] = []; const devicePhase = this.accessory.context.v4Device.phase; const phase = phases(challenge, getConfig())[devicePhase]; const startPhase = phase?.start; const endPhase = phase?.end; if (!startPhase || !endPhase) { this.logger.debug( `Could not find phase or period does not match device for device ${this.accessory.context.v4Device.localId} - ${this.accessory.context.v4Device.phase}`, ); return; } const startsIn = startPhase.getTime() - new Date().getTime(); const endsIn = endPhase.getTime() - new Date().getTime(); if (startsIn >= 0) { this.challenges[challenge.id].push( setTimeout(() => { this.updateChallengeValue(true); }, startsIn), ); } else if (startsIn < 0 && endsIn > 0) { this.updateChallengeValue(true); } if (endsIn >= 0) { this.challenges[challenge.id].push( setTimeout(() => { this.updateChallengeValue(false); delete this.challenges[challenge.id]; }, endsIn), ); } else { this.updateChallengeValue(false); delete this.challenges[challenge.id]; } } private notParticipating(challenge: Challenge) { if (this.challenges[challenge.id]) { this.challenges[challenge.id].forEach((timeout) => clearTimeout(timeout)); delete this.challenges[challenge.id]; } } }