// SPDX-License-Identifier: GPL-3.0-or-later // Extension : Gestionnaire Pompe à chaleur + ECS — implémentation #include "heatpumpmanager.h" #include Q_DECLARE_LOGGING_CATEGORY(dcNymeaEnergy) // ───────────────────────────────────────────────────────────── // HeatPumpManager // ───────────────────────────────────────────────────────────── HeatPumpManager::HeatPumpManager(EnergyManager *energyManager, ThingManager *thingManager, QObject *parent) : QObject(parent), m_energyManager(energyManager), m_thingManager(thingManager) { // Détecter les Things déjà présents au démarrage for (Thing *thing : m_thingManager->configuredThings()) { onThingAdded(thing); } // S'abonner aux nouveaux appareils connect(m_thingManager, &ThingManager::thingAdded, this, &HeatPumpManager::onThingAdded); connect(m_thingManager, &ThingManager::thingRemoved, this, &HeatPumpManager::onThingRemoved); } // ─── Accesseurs ────────────────────────────────────────────── QList HeatPumpManager::heatPumps() const { return m_heatPumps.values(); } QList HeatPumpManager::dhwDevices() const { return m_dhwDevices.values(); } double HeatPumpManager::totalThermalPower() const { double total = 0; for (const HeatPumpDevice *hp : m_heatPumps) total += hp->currentPower(); for (const DomesticHotWaterDevice *dhw : m_dhwDevices) total += dhw->currentPower(); return total; } // ─── Contrôle PAC ──────────────────────────────────────────── EnergyManager::EnergyError HeatPumpManager::setPower(const ThingId &thingId, bool on) { HeatPumpDevice *hp = m_heatPumps.value(thingId); if (!hp) return EnergyManager::EnergyErrorThingNotFound; qCDebug(dcNymeaEnergy()) << "HeatPumpManager: setPower" << on << "on" << hp->name(); Action action(kHPStatePower, thingId); action.setParams(ParamList() << Param(kHPStatePower, on)); m_thingManager->executeAction(action); return EnergyManager::EnergyErrorNoError; } EnergyManager::EnergyError HeatPumpManager::setMode(const ThingId &thingId, const QString &mode) { HeatPumpDevice *hp = m_heatPumps.value(thingId); if (!hp) return EnergyManager::EnergyErrorThingNotFound; const QStringList validModes = {"heating", "cooling", "auto", "standby"}; if (!validModes.contains(mode)) return EnergyManager::EnergyErrorInvalidParameter; qCDebug(dcNymeaEnergy()) << "HeatPumpManager: setMode" << mode << "on" << hp->name(); Action action(kHPActionSetMode, thingId); action.setParams(ParamList() << Param(kHPActionParamMode, mode)); m_thingManager->executeAction(action); return EnergyManager::EnergyErrorNoError; } EnergyManager::EnergyError HeatPumpManager::setTargetTemperature(const ThingId &thingId, double temperature) { HeatPumpDevice *hp = m_heatPumps.value(thingId); if (!hp) return EnergyManager::EnergyErrorThingNotFound; if (temperature < 15 || temperature > 65) return EnergyManager::EnergyErrorInvalidParameter; qCDebug(dcNymeaEnergy()) << "HeatPumpManager: setTargetTemperature" << temperature << "°C on" << hp->name(); Action action(kHPActionSetTargetTemperature, thingId); action.setParams(ParamList() << Param(kHPActionParamTargetTemp, temperature)); m_thingManager->executeAction(action); return EnergyManager::EnergyErrorNoError; } // ─── Contrôle ECS ──────────────────────────────────────────── EnergyManager::EnergyError HeatPumpManager::setDHWPower(const ThingId &thingId, bool on) { DomesticHotWaterDevice *dhw = m_dhwDevices.value(thingId); if (!dhw) return EnergyManager::EnergyErrorThingNotFound; qCDebug(dcNymeaEnergy()) << "HeatPumpManager: DHW setPower" << on << "on" << dhw->name(); Action action(kDHWStatePower, thingId); action.setParams(ParamList() << Param(kDHWStatePower, on)); m_thingManager->executeAction(action); return EnergyManager::EnergyErrorNoError; } EnergyManager::EnergyError HeatPumpManager::setDHWTargetTemperature(const ThingId &thingId, double temperature) { DomesticHotWaterDevice *dhw = m_dhwDevices.value(thingId); if (!dhw) return EnergyManager::EnergyErrorThingNotFound; if (temperature < 40 || temperature > 75) return EnergyManager::EnergyErrorInvalidParameter; Action action(kDHWStateTargetTemperature, thingId); action.setParams(ParamList() << Param(kDHWStateTargetTemperature, temperature)); m_thingManager->executeAction(action); return EnergyManager::EnergyErrorNoError; } EnergyManager::EnergyError HeatPumpManager::triggerDHWBoost(const ThingId &thingId, uint durationMinutes) { DomesticHotWaterDevice *dhw = m_dhwDevices.value(thingId); if (!dhw) return EnergyManager::EnergyErrorThingNotFound; if (durationMinutes < 15 || durationMinutes > 120) return EnergyManager::EnergyErrorInvalidParameter; qCDebug(dcNymeaEnergy()) << "HeatPumpManager: DHW triggerBoost" << durationMinutes << "min on" << dhw->name(); Action action(kDHWActionTriggerBoost, thingId); action.setParams(ParamList() << Param(kDHWActionParamDuration, durationMinutes)); m_thingManager->executeAction(action); return EnergyManager::EnergyErrorNoError; } // ─── Slots privés ──────────────────────────────────────────── void HeatPumpManager::onThingAdded(Thing *thing) { if (thing->thingClassId() == kHeatPumpThingClassId) { setupHeatPump(thing); } else if (thing->thingClassId() == kDomesticHotWaterClassId) { setupDHWDevice(thing); } } void HeatPumpManager::onThingRemoved(const ThingId &thingId) { if (m_heatPumps.contains(thingId)) { qCDebug(dcNymeaEnergy()) << "HeatPumpManager: PAC supprimée:" << thingId; delete m_heatPumps.take(thingId); emit heatPumpRemoved(thingId); } if (m_dhwDevices.contains(thingId)) { qCDebug(dcNymeaEnergy()) << "HeatPumpManager: ECS supprimée:" << thingId; delete m_dhwDevices.take(thingId); emit dhwDeviceRemoved(thingId); } } void HeatPumpManager::onThingStateChanged(Thing *thing, const StateType &stateType, const QVariant &value, const QVariant & /*minValue*/, const QVariant & /*maxValue*/) { if (m_heatPumps.contains(thing->id())) { emit heatPumpStateChanged(thing->id(), stateType.name(), value); } else if (m_dhwDevices.contains(thing->id())) { emit dhwStateChanged(thing->id(), stateType.name(), value); } } void HeatPumpManager::setupHeatPump(Thing *thing) { qCDebug(dcNymeaEnergy()) << "HeatPumpManager: Nouvelle PAC:" << thing->name() << thing->id(); HeatPumpDevice *hp = new HeatPumpDevice(thing, this); m_heatPumps.insert(thing->id(), hp); // Écouter les changements d'état connect(thing, &Thing::stateValueChanged, this, [this, thing](const StateTypeId &stateTypeId, const QVariant &value) { Thing *t = qobject_cast(sender()); if (t) emit heatPumpStateChanged(t->id(), stateTypeId.toString(), value); }); emit heatPumpAdded(thing->id()); } void HeatPumpManager::setupDHWDevice(Thing *thing) { qCDebug(dcNymeaEnergy()) << "HeatPumpManager: Nouvelle ECS:" << thing->name() << thing->id(); DomesticHotWaterDevice *dhw = new DomesticHotWaterDevice(thing, this); m_dhwDevices.insert(thing->id(), dhw); connect(thing, &Thing::stateValueChanged, this, [this, thing](const StateTypeId &stateTypeId, const QVariant &value) { Thing *t = qobject_cast(sender()); if (t) emit dhwStateChanged(t->id(), stateTypeId.toString(), value); }); emit dhwDeviceAdded(thing->id()); } // ───────────────────────────────────────────────────────────── // HeatPumpDevice // ───────────────────────────────────────────────────────────── HeatPumpDevice::HeatPumpDevice(Thing *thing, QObject *parent) : QObject(parent), m_thing(thing) {} ThingId HeatPumpDevice::id() const { return m_thing->id(); } QString HeatPumpDevice::name() const { return m_thing->name(); } Thing *HeatPumpDevice::thing() const { return m_thing; } bool HeatPumpDevice::power() const { return m_thing->stateValue(kHPStatePower).toBool(); } QString HeatPumpDevice::mode() const { return m_thing->stateValue(kHPStateMode).toString(); } double HeatPumpDevice::targetTemperature() const { return m_thing->stateValue(kHPStateTargetTemperature).toDouble(); } double HeatPumpDevice::currentTemperature() const { return m_thing->stateValue(kHPStateCurrentTemp).toDouble(); } double HeatPumpDevice::currentPower() const { return m_thing->stateValue(kHPStateCurrentPower).toDouble(); } double HeatPumpDevice::cop() const { return m_thing->stateValue(kHPStateCop).toDouble(); } bool HeatPumpDevice::defrostActive() const { return m_thing->stateValue(kHPStateDefrostActive).toBool(); } // ───────────────────────────────────────────────────────────── // DomesticHotWaterDevice // ───────────────────────────────────────────────────────────── DomesticHotWaterDevice::DomesticHotWaterDevice(Thing *thing, QObject *parent) : QObject(parent), m_thing(thing) {} ThingId DomesticHotWaterDevice::id() const { return m_thing->id(); } QString DomesticHotWaterDevice::name() const { return m_thing->name(); } Thing *DomesticHotWaterDevice::thing() const { return m_thing; } bool DomesticHotWaterDevice::power() const { return m_thing->stateValue(kDHWStatePower).toBool(); } double DomesticHotWaterDevice::targetTemperature() const { return m_thing->stateValue(kDHWStateTargetTemperature).toDouble(); } double DomesticHotWaterDevice::currentTemperature() const { return m_thing->stateValue(kDHWStateCurrentTemp).toDouble(); } bool DomesticHotWaterDevice::boostMode() const { return m_thing->stateValue(kDHWStateBoostMode).toBool(); } double DomesticHotWaterDevice::currentPower() const { return m_thing->stateValue(kDHWStateCurrentPower).toDouble(); }