powersync-energy-plugin-etm/extension/heatpumpmanager.cpp

296 lines
12 KiB
C++

// SPDX-License-Identifier: GPL-3.0-or-later
// Extension : Gestionnaire Pompe à chaleur + ECS — implémentation
#include "heatpumpmanager.h"
#include <QLoggingCategory>
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<HeatPumpDevice *> HeatPumpManager::heatPumps() const
{
return m_heatPumps.values();
}
QList<DomesticHotWaterDevice *> 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<Thing *>(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<Thing *>(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();
}