Skip to content

Commit 9bd99cc

Browse files
committed
2 parents 7746cd8 + 0f60e57 commit 9bd99cc

4 files changed

Lines changed: 59 additions & 155 deletions

File tree

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "homebridge-otodo-vav",
3-
"version": "1.3.4",
3+
"version": "1.4.1",
44
"description": "Homebridge plugin for Otodo VAV thermostats",
55
"keywords": [
66
"homebridge-plugin",

src/otodoTempAccessory.ts

Lines changed: 0 additions & 66 deletions
This file was deleted.

src/platform.ts

Lines changed: 54 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// platform.ts
12
import type {
23
API,
34
DynamicPlatformPlugin,
@@ -18,15 +19,19 @@ import { ThermostatClient } from './thermostatClient';
1819
import type { ThermostatService, Room, Hub, DeviceCapability } from './types';
1920
import { ThermostatAccessory } from './thermostatAccessory';
2021
import { OtodoModeSliderAccessory } from './otodoModeSliderAccessory';
21-
import { OtodoTempSensorAccessory } from './otodoTempAccessory';
2222

2323
export class OtodoVavPlatform implements DynamicPlatformPlugin {
2424
public readonly accessories: PlatformAccessory[] = [];
2525

2626
private auth!: AuthClient;
2727
private client!: OtodoClient;
2828
private tClient!: ThermostatClient;
29-
private tempSensors: Map<number, OtodoTempSensorAccessory> = new Map();
29+
30+
/**
31+
* 🔥 NOUVEAU :
32+
* deviceId → ThermostatAccessory
33+
*/
34+
private thermostatByDeviceId: Map<number, ThermostatAccessory> = new Map();
3035

3136
private roomsById: Map<string, Room> = new Map();
3237
private hubsById: Map<string, Hub> = new Map();
@@ -270,8 +275,6 @@ export class OtodoVavPlatform implements DynamicPlatformPlugin {
270275

271276
this.log.debug('📦 Création du TokenStore...');
272277
const store = new TokenStore(this.api.user.storagePath());
273-
274-
this.log.debug("🔐 Initialisation de l'authentification...");
275278
this.auth = new AuthClient(this.log, store, {
276279
email: String(cfg.email || '').trim(),
277280
password: String(cfg.password || ''),
@@ -329,118 +332,88 @@ export class OtodoVavPlatform implements DynamicPlatformPlugin {
329332

330333
private async loadRooms(): Promise<void> {
331334
try {
332-
this.log.debug('📂 Récupération des rooms...');
333335
const rooms = await this.tClient.getRooms();
334336
this.roomsById = new Map(rooms.map(r => [r._id, r]));
335-
this.log.debug(`📂 ${rooms.length} rooms chargées`);
336337
} catch (e) {
337-
this.log.warn(
338-
'⚠️ Impossible de récupérer les rooms (optionnel) : ' + String(e),
339-
);
338+
this.log.warn('⚠️ Impossible de récupérer les rooms : ' + String(e));
340339
}
341340
}
342341

343342
private async loadHubs(): Promise<void> {
344343
try {
345-
this.log.debug('📂 Récupération des hubs...');
346344
const hubs = await this.tClient.getHubs();
347345
this.hubsById = new Map(hubs.map(r => [r._id, r]));
348-
this.log.debug(`📂 ${hubs.length} hubs chargés`);
349346
} catch (e) {
350347
this.log.warn('⚠️ Impossible de récupérer les hubs : ' + String(e));
351348
}
352349
}
353350

354351
configureAccessory(accessory: PlatformAccessory): void {
355-
this.log.debug("🔄 Restauration de l'accessoire:", accessory.displayName);
356352
this.accessories.push(accessory);
357353
}
358354

355+
/**
356+
* 🔥 THERMOSTAT UNIQUEMENT
357+
* ET enregistrement deviceId → ThermostatAccessory
358+
*/
359359
private upsertThermostat(t: ThermostatService): void {
360-
const uuidThermo = this.api.hap.uuid.generate(`thermo:${t.hubId}:${t._id}`);
360+
const uuid = this.api.hap.uuid.generate(`thermo:${t.hubId}:${t._id}`);
361361
const uuidSlider = this.api.hap.uuid.generate(`slider:${t.hubId}:${t._id}`);
362-
const uuidTemp = this.api.hap.uuid.generate(`temp:${t.hubId}:${t._id}`);
363362

364363
const roomName = this.roomsById.get(t.roomId)?.name;
365364
const thermoName = roomName
366365
? `Thermostat ${roomName}`
367366
: `Thermostat ${t._id}`;
368367
const sliderName = roomName ? `Mode ${roomName}` : `Mode ${t._id}`;
369368

370-
// ========== THERMOSTAT ACCESSORY ==========
371-
const existingThermo = this.accessories.find(a => a.UUID === uuidThermo);
372-
if (existingThermo) {
373-
new ThermostatAccessory(this, existingThermo, t, this.tClient);
369+
// --- THERMOSTAT ---
370+
let acc = this.accessories.find(a => a.UUID === uuid);
371+
372+
if (acc) {
373+
this.log.info(`♻️ Restauration thermostat: ${thermoName}`);
374374
} else {
375-
const acc = new this.api.platformAccessory(thermoName, uuidThermo);
376-
new ThermostatAccessory(this, acc, t, this.tClient);
375+
acc = new this.api.platformAccessory(thermoName, uuid);
377376
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [acc]);
378377
this.accessories.push(acc);
379378
}
380379

381-
// ========== MODE SLIDER ACCESSORY ==========
382-
const existingSlider = this.accessories.find(a => a.UUID === uuidSlider);
380+
const thermoCtrl = new ThermostatAccessory(this, acc, t, this.tClient);
383381

384-
if (this.displayModeSliders) {
385-
// Création / restauration
386-
if (existingSlider) {
387-
this.log.info(`♻️ Restauration du mode slider: ${sliderName}`);
388-
new OtodoModeSliderAccessory(this, existingSlider, t, this.tClient);
389-
} else {
390-
this.log.info(`➕ Ajout du mode slider: ${sliderName}`);
391-
const acc = new this.api.platformAccessory(sliderName, uuidSlider);
392-
new OtodoModeSliderAccessory(this, acc, t, this.tClient);
393-
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [acc]);
394-
this.accessories.push(acc);
395-
}
396-
} else {
397-
// 🔥 SUPPRESSION AUTOMATIQUE SI désactivé
398-
if (existingSlider) {
399-
this.log.info(`🗑️ Suppression du mode slider désactivé: ${sliderName}`);
400-
this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [
401-
existingSlider,
402-
]);
403-
this.accessories.splice(this.accessories.indexOf(existingSlider), 1);
404-
}
382+
// 🔥 ENREGISTREMENT deviceId → thermostat
383+
const deviceId = t.modules?.[0]?.deviceId;
384+
if (deviceId) {
385+
this.thermostatByDeviceId.set(deviceId, thermoCtrl);
386+
acc.context.deviceId = deviceId;
405387
}
406388

407-
// ========= TEMP SENSOR ACCESSORY =========
408-
const tempName = roomName
409-
? `Température ${roomName}`
410-
: `Température ${t._id}`;
411-
const existingTemp = this.accessories.find(a => a.UUID === uuidTemp);
412-
413-
let tempAccessory: OtodoTempSensorAccessory;
389+
// --- MODE SLIDER ---
390+
let accSlider = this.accessories.find(a => a.UUID === uuidSlider);
414391

415-
if (existingTemp) {
416-
tempAccessory = new OtodoTempSensorAccessory(this, existingTemp, t);
417-
} else {
418-
const acc = new this.api.platformAccessory(tempName, uuidTemp);
419-
tempAccessory = new OtodoTempSensorAccessory(this, acc, t);
420-
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [acc]);
421-
this.accessories.push(acc);
392+
if (this.displayModeSliders) {
393+
if (!accSlider) {
394+
accSlider = new this.api.platformAccessory(sliderName, uuidSlider);
395+
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [
396+
accSlider,
397+
]);
398+
this.accessories.push(accSlider);
399+
}
400+
new OtodoModeSliderAccessory(this, accSlider, t, this.tClient);
401+
} else if (accSlider) {
402+
this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [
403+
accSlider,
404+
]);
405+
this.accessories.splice(this.accessories.indexOf(accSlider), 1);
422406
}
423-
424-
// Stockage (deviceId → sensorInstance)
425-
this.tempSensors.set(tempAccessory.deviceId, tempAccessory);
426407
}
427408

428409
private async discoverDevices(hubId: string): Promise<void> {
429-
this.log.info('🔍 Recherche des thermostats Otodo VAV...');
430-
try {
431-
const thermostats = await this.tClient.getAllThermostats(hubId);
432-
this.log.info(` ${thermostats.length} thermostat(s) trouvé(s)`);
433-
434-
for (const t of thermostats) {
435-
this.upsertThermostat(t);
436-
}
437-
} catch (e) {
438-
this.log.error(
439-
'❌ Erreur lors de la découverte des thermostats : ' + String(e),
440-
);
410+
const thermostats = await this.tClient.getAllThermostats(hubId);
411+
for (const t of thermostats) {
412+
this.upsertThermostat(t);
441413
}
442414
}
443415

416+
// 🔥 Poller TRV → mise à jour du thermostat associé
444417
private async startDevicesPolling(): Promise<void> {
445418
this.log.info(
446419
`📡 Mise en place du poller global /devices (intervalle: ${
@@ -457,9 +430,6 @@ export class OtodoVavPlatform implements DynamicPlatformPlugin {
457430
}, this.pollIntervalMs);
458431
}
459432

460-
/**
461-
* Fonction interne : récupère /devices et met à jour les capteurs
462-
*/
463433
private async refreshDevicesOnce(): Promise<void> {
464434
try {
465435
const devices = await this.tClient.getDevices();
@@ -477,19 +447,19 @@ export class OtodoVavPlatform implements DynamicPlatformPlugin {
477447
continue;
478448
}
479449

480-
const deviceId = dev._id;
481-
const sensor = this.tempSensors.get(deviceId);
482-
if (!sensor) {
483-
continue;
484-
}
485-
486450
const kelvinX10 = tempCap.value;
487451
const celsius = Number(((kelvinX10 - 2731) / 10).toFixed(1));
488452

489-
sensor.updateTemperature(celsius);
453+
// Trouver le ThermostatAccessory correspondant
454+
const ctrl = this.thermostatByDeviceId.get(dev._id);
455+
if (!ctrl) {
456+
continue;
457+
}
458+
459+
ctrl.updateCurrentTemperature(celsius);
490460
}
491-
} catch (err) {
492-
this.log.warn(`⚠️ Poller devices: ${String(err)}`);
461+
} catch (e) {
462+
this.log.warn(`⚠️ Erreur polling /devices : ${e}`);
493463
}
494464
}
495465
}

0 commit comments

Comments
 (0)