// SPDX-License-Identifier: GPL-3.0-or-later /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright (C) 2013 - 2024, nymea GmbH * Copyright (C) 2024 - 2025, chargebyte austria GmbH * * This file is part of nymea-energy-plugin-nymea. * * nymea-energy-plugin-nymea.s free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * nymea-energy-plugin-nymea.s distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with nymea-energy-plugin-nymea. If not, see . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "relayadapter.h" #include "types/action.h" #include "integrations/thingmanager.h" #include "integrations/thingactioninfo.h" #include #include Q_DECLARE_LOGGING_CATEGORY(dcNymeaEnergy) RelayAdapter::RelayAdapter(ThingManager *thingManager, const ThingId &thingId, LoadRole role, double nominalPowerW, QObject *parent) : ILoadAdapter(parent), m_thingManager(thingManager), m_role(role), m_nominalPowerW(nominalPowerW) { m_thing = thingManager->findConfiguredThing(thingId); if (!m_thing) qCWarning(dcNymeaEnergy()) << "RelayAdapter: thing not found:" << thingId; } QString RelayAdapter::adapterId() const { return QStringLiteral("relay"); } LoadRole RelayAdapter::role() const { return m_role; } ThingId RelayAdapter::thingId() const { return m_thing ? m_thing->id() : ThingId(); } void RelayAdapter::applyPower(double targetPowerW) { if (!m_thing) { qCWarning(dcNymeaEnergy()) << "RelayAdapter::applyPower: no thing available"; emit powerApplied(0, false); return; } setPower(targetPowerW > 0); } void RelayAdapter::testConnection() { if (!m_thing) { emit testResult(false, QStringLiteral("Thing not found")); return; } // Toggle on → wait 2s → toggle off → report success setPower(true); QTimer::singleShot(2000, this, [this]() { setPower(false); emit testResult(true, QStringLiteral("Connection test OK")); }); } double RelayAdapter::currentPowerW() const { return m_relayOn ? m_nominalPowerW : 0.0; } bool RelayAdapter::isReachable() const { if (!m_thing) return false; // If the ThingClass has a "connected" state, use it; otherwise assume reachable. foreach (const StateType &st, m_thing->thingClass().stateTypes()) { if (st.name() == QLatin1String("connected")) return m_thing->stateValue(st.id()).toBool(); } return true; } void RelayAdapter::setPower(bool on) { if (!m_thing) return; // Find the "power" action type (relay interface) ActionType powerActionType; foreach (const ActionType &at, m_thing->thingClass().actionTypes()) { if (at.name() == QLatin1String("power")) { powerActionType = at; break; } } if (powerActionType.id().isNull()) { qCWarning(dcNymeaEnergy()) << "RelayAdapter: no 'power' action type on thing" << m_thing->name(); emit powerApplied(on ? m_nominalPowerW : 0, false); return; } // Find the "power" param type ParamTypeId powerParamTypeId; foreach (const ParamType &pt, powerActionType.paramTypes()) { if (pt.name() == QLatin1String("power")) { powerParamTypeId = pt.id(); break; } } Action action(powerActionType.id(), m_thing->id(), Action::TriggeredByRule); action.setParams(ParamList() << Param(powerParamTypeId, on)); ThingActionInfo *info = m_thingManager->executeAction(action); connect(info, &ThingActionInfo::finished, this, [this, on, info]() { bool ok = (info->status() == Thing::ThingErrorNoError); if (ok) m_relayOn = on; emit powerApplied(on ? m_nominalPowerW : 0, ok); if (!ok) qCWarning(dcNymeaEnergy()) << "RelayAdapter: action failed on" << m_thing->name(); }); }