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
254 lines • 11.4 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = default_1;
const config_1 = require("./config");
const logger_1 = require("./logger");
const api_1 = require("./api");
const hiloApi_1 = require("./hiloApi");
const devices_1 = require("./devices");
const subscription_1 = require("./subscription");
const location_1 = require("./location");
const types_1 = require("./devices/types");
const HiloChallengeSensor_1 = require("./devices/HiloChallengeSensor");
const axios_1 = __importDefault(require("axios"));
const PLUGIN_NAME = "homebridge-hilo";
const PLATFORM_NAME = "Hilo";
function default_1(api) {
api.registerPlatform(PLATFORM_NAME, Hilo);
}
class Hilo {
constructor(log, config, api, accessories = {}) {
this.log = log;
this.config = config;
this.api = api;
this.accessories = accessories;
this.pluginAccessories = {};
this.locations = [];
this.subscriptions = {};
this.oldApiDevices = [];
this.staleAccessories = [];
(0, config_1.setConfig)(config);
this.config = (0, config_1.getConfig)();
if (!this.config.refreshToken) {
this.log.error("Please login with hilo in the plugin configuration page");
return;
}
(0, logger_1.setLogger)(log);
(0, api_1.setApi)(api);
log.info("Initializing Hilo platform");
api.on("didFinishLaunching" /* APIEvent.DID_FINISH_LAUNCHING */, async () => {
this.locations = await fetchLocations();
if (this.locations.length === 0) {
log.error("No locations found");
return;
}
const devices = (await Promise.all(this.locations.map((location) => (0, location_1.fetchDevicesForLocation)(location.locationHiloId))))
.flatMap((response) => response)
.filter((device) => types_1.SUPPORTED_DEVICES.includes(device.__typename));
this.oldApiDevices = (await Promise.all(this.locations.map((location) => fetchDevices(location)))).flatMap((response) => response);
if (devices.length === 0) {
log.error("No devices found");
return;
}
devices.forEach((device) => {
this.log.debug("Initializing device", device);
const oldDevice = this.oldApiDevices.find((d) => d.hiloId === device.hiloId);
if (!oldDevice) {
this.log.error("No old device found for", device);
return;
}
let accessory = this.accessories[device.hiloId];
if (!accessory) {
this.log.debug(`Setting up new accessory for device ${device.hiloId}`);
accessory = this.setupNewAccessory(device, oldDevice);
}
else if (accessory.context.device.type !== "Challenge") {
this.log.debug(`Setting up cached accessory for device ${device.hiloId}`);
accessory.context = {
device: oldDevice,
graphqlDevice: device,
};
}
const pluginAccessory = devices_1.initializeHiloDevice[device.__typename](accessory, this.api);
this.pluginAccessories[device.hiloId] = pluginAccessory;
});
this.setupSubscriptions();
const currentDeviceHiloIds = this.oldApiDevices.map((device) => device.hiloId);
this.staleAccessories.concat(Object.values(this.accessories).filter((accessory) => {
if (accessory.context.device.type === "Challenge") {
return false;
}
else {
return !currentDeviceHiloIds.includes(accessory.context.device.hiloId);
}
}));
this.log.debug(`Found ${this.staleAccessories.length} stale accessories removing...`);
this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, this.staleAccessories);
if (this.config.noChallengeSensor !== true) {
// Add Hilo Challenge sensor for each location
this.log.info("Setting up Hilo Challenge sensors");
this.locations.forEach((location) => {
const challengeDevices = this.setupHiloChallengeDevices(location);
setInterval(async () => {
this.updateChallenges(location, challengeDevices);
},
/* 4 hours */ 4 * 60 * 60 * 1000);
this.updateChallenges(location, challengeDevices);
});
}
log.info("Hilo platform is ready");
});
}
setupHiloChallengeDevices(location) {
return [
"preheat",
"reduction",
"recovery",
"plannedAM",
"plannedPM",
"inProgress",
].map((phase, index) => {
const challengeId = `${phase}-hilo-challenge-${location.id}`;
const challengeName = `${phase.charAt(0).toUpperCase() + phase.slice(1)} Hilo Challenge ${location.name}`;
let challengeAccessory = this.accessories[challengeId];
if (!challengeAccessory) {
const uuid = this.api.hap.uuid.generate(challengeId);
challengeAccessory = new this.api.platformAccessory(challengeName, uuid);
challengeAccessory.context = {
device: {
assetId: challengeId,
id: location.id + index + 100,
name: challengeName,
type: "Challenge",
locationId: location.id,
modelNumber: "Hilo Challenge",
identifier: challengeId,
hiloId: challengeId,
},
v4Device: {
value: false,
phase,
localId: challengeId,
},
};
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [
challengeAccessory,
]);
this.accessories[challengeId] = challengeAccessory;
}
else {
challengeAccessory.context = {
device: {
assetId: challengeId,
id: location.id + index + 100,
name: challengeName,
type: "Challenge",
locationId: location.id,
modelNumber: "Hilo Challenge",
identifier: challengeId,
hiloId: challengeId,
},
v4Device: {
value: false,
phase,
localId: challengeId,
},
};
}
return new HiloChallengeSensor_1.HiloChallengeSensor(challengeAccessory, this.api, this.log);
});
}
async setupSubscriptions() {
for (const location of this.locations) {
try {
const subscription = await (0, subscription_1.setupSubscription)(location.locationHiloId, (device) => {
this.log.debug(`Device update received:`, device);
const oldApiDevice = this.oldApiDevices.find((d) => d.hiloId === device.hiloId);
if (!oldApiDevice) {
this.log.error("No old device found for", device);
return;
}
const accessory = this.accessories[device.hiloId];
const pluginAccessory = this.pluginAccessories[device.hiloId];
if (!accessory || !pluginAccessory) {
this.log.debug(`No accessory for device ${device.hiloId}`);
return;
}
pluginAccessory.updateDevice(device);
});
this.subscriptions[location.locationHiloId] = subscription;
this.log.info(`Subscribed to updates for location ${location.locationHiloId}`);
}
catch (error) {
this.log.error(`Failed to subscribe to location ${location.locationHiloId}:`, error instanceof Error ? error.message : String(error));
}
}
}
configureAccessory(accessory) {
this.log.debug(`Configuring accessory from cache ${accessory.displayName}`);
if (accessory.context.device.type !== "Challenge" &&
!accessory.context.device.hiloId) {
this.log.warn(`Could not configure accessory ${accessory.displayName}`);
this.staleAccessories.push(accessory);
return;
}
this.accessories[accessory.context.device.hiloId] = accessory;
}
setupNewAccessory(device, oldApiDevice) {
const uuid = this.api.hap.uuid.generate(oldApiDevice.assetId);
const accessory = new this.api.platformAccessory(oldApiDevice.name.trim(), uuid);
accessory.context = {
device: oldApiDevice,
graphqlDevice: device,
};
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [
accessory,
]);
this.accessories[device.hiloId] = accessory;
return accessory;
}
async updateChallenges(location, challengeDevices) {
if (this.config.noChallengeSensor === true) {
return;
}
try {
const response = await hiloApi_1.hiloApi.get(`/GDService/v1/api/Locations/${location.id}/Events`, { params: { active: true } });
const challenges = response.data;
challengeDevices.forEach((device) => device.updateChallengeStatus(challenges));
}
catch (error) {
this.log.error("Could not retrieve Hilo Challenges", error);
}
}
}
async function fetchLocations() {
(0, logger_1.getLogger)().debug("Fetching locations");
try {
const response = await hiloApi_1.hiloApi.get("/Automation/v1/api/Locations", {
params: { force: true },
});
return response.data;
}
catch (error) {
(0, logger_1.getLogger)().error("Error while fetching locations", error instanceof Error ? error.message : String(error));
return [];
}
}
async function fetchDevices(location) {
var _a;
(0, logger_1.getLogger)().debug("Fetching devices for location", location.name);
try {
const response = await hiloApi_1.hiloApi.get(`/Automation/v1/api/Locations/${location.id}/Devices`, {
params: { force: true },
});
return response.data;
}
catch (error) {
(0, logger_1.getLogger)().error("Error while fetching devices", axios_1.default.isAxiosError(error) ? (_a = error.response) === null || _a === void 0 ? void 0 : _a.data : error);
return [];
}
}
//# sourceMappingURL=hilo.js.map