From aef9cba99e56a3dc2f202f6ec7ac661ed238c6f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Tue, 12 Oct 2021 14:09:58 +0200 Subject: [PATCH 1/3] New Plugin: SG-Ready heat pump based on GPIOs --- debian/control | 17 +++ debian/nymea-plugin-sgready.install.in | 1 + nymea-plugins.pro | 1 + sgready/README.md | 14 ++ sgready/integrationpluginsgready.cpp | 157 +++++++++++++++++++++ sgready/integrationpluginsgready.h | 59 ++++++++ sgready/integrationpluginsgready.json | 77 +++++++++++ sgready/meta.json | 13 ++ sgready/sgready.pro | 13 ++ sgready/sgreadyinterface.cpp | 181 +++++++++++++++++++++++++ sgready/sgreadyinterface.h | 75 ++++++++++ sgready/smart-grid-logo.png | Bin 0 -> 30302 bytes 12 files changed, 608 insertions(+) create mode 100644 debian/nymea-plugin-sgready.install.in create mode 100644 sgready/README.md create mode 100644 sgready/integrationpluginsgready.cpp create mode 100644 sgready/integrationpluginsgready.h create mode 100644 sgready/integrationpluginsgready.json create mode 100644 sgready/meta.json create mode 100644 sgready/sgready.pro create mode 100644 sgready/sgreadyinterface.cpp create mode 100644 sgready/sgreadyinterface.h create mode 100644 sgready/smart-grid-logo.png diff --git a/debian/control b/debian/control index 0bfec247..d40ff91c 100644 --- a/debian/control +++ b/debian/control @@ -930,6 +930,22 @@ Description: nymea.io plugin for senic This package will install the nymea.io plugin for senic +Package: nymea-plugin-sgready +Architecture: any +Depends: ${shlibs:Depends}, + ${misc:Depends}, + libnymea-gpio, + nymea-plugins-translations, +Description: nymea.io plugin for SG-Ready heat pump interface based on GPIOs + The nymea daemon is a plugin based IoT (Internet of Things) server. The + server works like a translator for devices, things and services and + allows them to interact. + With the powerful rule engine you are able to connect any device available + in the system and create individual scenes and behaviors for your environment. + . + This package will install the nymea.io plugin for SG-Ready heat pump interface based on GPIOs + + Package: nymea-plugin-shelly Architecture: any Depends: ${shlibs:Depends}, @@ -1333,6 +1349,7 @@ Depends: nymea-plugin-boblight, nymea-plugin-avahimonitor, nymea-plugin-anel, nymea-plugin-gpio, + nymea-plugin-sgready, nymea-plugin-i2cdevices, nymea-plugin-mqttclient, nymea-plugin-mcp3008, diff --git a/debian/nymea-plugin-sgready.install.in b/debian/nymea-plugin-sgready.install.in new file mode 100644 index 00000000..1832546e --- /dev/null +++ b/debian/nymea-plugin-sgready.install.in @@ -0,0 +1 @@ +usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationpluginsgready.so diff --git a/nymea-plugins.pro b/nymea-plugins.pro index a8f3990e..044bb527 100644 --- a/nymea-plugins.pro +++ b/nymea-plugins.pro @@ -54,6 +54,7 @@ PLUGIN_DIRS = \ reversessh \ senic \ serialportcommander \ + sgready \ simulation \ sma \ somfytahoma \ diff --git a/sgready/README.md b/sgready/README.md new file mode 100644 index 00000000..a4517d44 --- /dev/null +++ b/sgready/README.md @@ -0,0 +1,14 @@ +# SG-Ready + +Theis plugin allowes to create an SG ready interface based on 2 GPIO pins connected to a SG-Ready heat pump. + +The GPIO need to be connected to the SG ready interface of the heat pump. + +> Note: take care to configure the correct pins for relay 1 and 2. Connecting them over cross will lead to missbehaviour of your heat pump. + +More information about the SG ready interface can be found on following website: + +https://www.waermepumpe.de/normen-technik/sg-ready/ + + + diff --git a/sgready/integrationpluginsgready.cpp b/sgready/integrationpluginsgready.cpp new file mode 100644 index 00000000..713f577d --- /dev/null +++ b/sgready/integrationpluginsgready.cpp @@ -0,0 +1,157 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "integrationpluginsgready.h" +#include "plugininfo.h" + +IntegrationPluginSgReady::IntegrationPluginSgReady() +{ + +} + +void IntegrationPluginSgReady::init() +{ + // Load possible system configurations for gpio pairs depending on well knwon platforms + + +} + +void IntegrationPluginSgReady::discoverThings(ThingDiscoveryInfo *info) +{ + // Check if GPIOs are available on this platform + if (!Gpio::isAvailable()) { + qCWarning(dcSgReady()) << "There are no GPIOs available on this plattform"; + //: Error discovering SG ready GPIOs + return info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("No GPIOs available on this system.")); + } + + // FIXME: provide once system configurations are loaded + + info->finish(Thing::ThingErrorNoError); +} + +void IntegrationPluginSgReady::setupThing(ThingSetupInfo *info) +{ + Thing *thing = info->thing(); + qCDebug(dcSgReady()) << "Setup" << thing->name() << thing->params(); + + // Check if GPIOs are available on this platform + if (!Gpio::isAvailable()) { + qCWarning(dcSgReady()) << "There are no GPIOs available on this plattform"; + //: Error discovering SG ready GPIOs + return info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("No GPIOs found on this system.")); + } + + if (thing->thingClassId() == sgReadyInterfaceThingClassId) { + if (m_sgReadyInterfaces.contains(thing)) { + // Rreconfigure... + SgReadyInterface *interface = m_sgReadyInterfaces.take(thing); + delete interface; + // Continue with normal setup... + } + + int gpioNumber1 = thing->paramValue(sgReadyInterfaceThingGpioNumber1ParamTypeId).toUInt(); + int gpioNumber2 = thing->paramValue(sgReadyInterfaceThingGpioNumber2ParamTypeId).toUInt(); + bool gpioEnabled1 = thing->stateValue(sgReadyInterfaceGpio1StateStateTypeId).toBool(); + bool gpioEnabled2 = thing->stateValue(sgReadyInterfaceGpio2StateStateTypeId).toBool(); + + SgReadyInterface *sgReadyInterface = new SgReadyInterface(gpioNumber1, gpioNumber2, this); + if (!sgReadyInterface->setup(gpioEnabled1, gpioEnabled2)) { + qCWarning(dcSgReady()) << "Setup" << thing << "failed because the GPIO could not be set up correctly."; + //: Error message if SG ready GPIOs setup failed + info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Failed to set up the GPIO hardware interface.")); + return; + } + + // Reflect the SG states + connect(sgReadyInterface, &SgReadyInterface::sgReadyModeChanged, this, [thing, sgReadyInterface](SgReadyInterface::SgReadyMode mode){ + Q_UNUSED(mode) + thing->setSettingValue(sgReadyInterfaceGpio1StateStateTypeId, sgReadyInterface->gpio1()->value() == Gpio::ValueHigh); + thing->setSettingValue(sgReadyInterfaceGpio2StateStateTypeId, sgReadyInterface->gpio2()->value() == Gpio::ValueHigh); + }); + + m_sgReadyInterfaces.insert(thing, sgReadyInterface); + info->finish(Thing::ThingErrorNoError); + return; + } +} + +void IntegrationPluginSgReady::postSetupThing(Thing *thing) +{ + Q_UNUSED(thing) +} + +void IntegrationPluginSgReady::thingRemoved(Thing *thing) +{ + if (m_sgReadyInterfaces.contains(thing)) { + SgReadyInterface *sgReadyInterface = m_sgReadyInterfaces.take(thing); + delete sgReadyInterface; + } +} + +void IntegrationPluginSgReady::executeAction(ThingActionInfo *info) +{ + Thing *thing = info->thing(); + if (thing->thingClassId() == sgReadyInterfaceThingClassId) { + + SgReadyInterface *sgReadyInterface = m_sgReadyInterfaces.value(thing); + if (!sgReadyInterface || !sgReadyInterface->isValid()) { + qCWarning(dcSgReady()) << "Failed to execute action. There is no interface available for" << thing; + info->finish(Thing::ThingErrorHardwareNotAvailable); + return; + } + + // FIXME: the modes have timeing constrains we need to take care off. + + if (info->action().actionTypeId() == sgReadyInterfaceSgReadyModeActionTypeId) { + QString sgReadyModeString = info->action().paramValue(sgReadyInterfaceSgReadyModeActionSgReadyModeParamTypeId).toString(); + qCDebug(dcSgReady()) << "Set SG ready mode from" << thing << "to" << sgReadyModeString; + SgReadyInterface::SgReadyMode mode; + if (sgReadyModeString == "Off") { + mode = SgReadyInterface::SgReadyModeOff; + } else if (sgReadyModeString == "Low") { + mode = SgReadyInterface::SgReadyModeLow; + } else if (sgReadyModeString == "High") { + mode = SgReadyInterface::SgReadyModeHigh; + } else { + mode = SgReadyInterface::SgReadyModeStandard; + } + + if (!sgReadyInterface->setSgReadyMode(mode)) { + qCWarning(dcSgReady()) << "Failed to set the sg ready mode on" << thing << "to" << sgReadyModeString; + info->finish(Thing::ThingErrorHardwareFailure); + return; + } + + info->finish(Thing::ThingErrorNoError); + } + } +} + diff --git a/sgready/integrationpluginsgready.h b/sgready/integrationpluginsgready.h new file mode 100644 index 00000000..4c72b137 --- /dev/null +++ b/sgready/integrationpluginsgready.h @@ -0,0 +1,59 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef INTEGRATIONPLUGINSGREADY_H +#define INTEGRATIONPLUGINSGREADY_H + +#include "integrations/integrationplugin.h" +#include "sgreadyinterface.h" + +class IntegrationPluginSgReady : public IntegrationPlugin +{ + Q_OBJECT + + Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationpluginsgready.json") + Q_INTERFACES(IntegrationPlugin) + +public: + explicit IntegrationPluginSgReady(); + + void init() override; + void discoverThings(ThingDiscoveryInfo *info) override; + void setupThing(ThingSetupInfo *info) override; + void postSetupThing(Thing *thing) override; + void thingRemoved(Thing *thing) override; + void executeAction(ThingActionInfo *info) override; + +private: + QHash m_sgReadyInterfaces; + +}; + +#endif // INTEGRATIONPLUGINSGREADY_H diff --git a/sgready/integrationpluginsgready.json b/sgready/integrationpluginsgready.json new file mode 100644 index 00000000..f9ca0115 --- /dev/null +++ b/sgready/integrationpluginsgready.json @@ -0,0 +1,77 @@ +{ + "name": "SgReady", + "displayName": "SG-Ready", + "id": "7923e2f3-b2f7-445d-ab14-033000485bd8", + "vendors": [ + { + "name": "nymea", + "displayName": "nymea", + "id": "2062d64d-3232-433c-88bc-0d33c0ba2ba6", + "thingClasses": [ + { + "id": "5a5f3aca-a958-4bca-b8fc-1168fe3371ec", + "name": "sgReadyInterface", + "displayName": "SG Ready interface", + "createMethods": ["user"], + "interfaces": [ "smartgridheatpump" ], + "settingsTypes": [ + ], + "paramTypes": [ + { + "id": "8de25aef-d868-4410-abd3-3bec9c46aba3", + "name": "gpioNumber1", + "displayName": "GPIO number 1", + "type": "int", + "defaultValue": -1 + }, + { + "id": "113ba124-a392-4bc3-861a-f7feaab82fc4", + "name": "gpioNumber2", + "displayName": "GPIO number 2", + "type": "int", + "defaultValue": -1 + } + ], + "stateTypes": [ + { + "id": "91008e09-2702-4bd5-942e-398513ae3d15", + "name": "sgReadyMode", + "displayName": "Smart grid mode", + "displayNameEvent": "Smart grid mode changed", + "displayNameAction": "Set smart grid mode", + "type": "QString", + "possibleValues": [ + "Off", + "Low", + "Standard", + "High" + ], + "writable": true, + "defaultValue": "Standard", + "cached": true, + "suggestLogging": true + }, + { + "id": "d2c83778-693f-4146-a656-a8ed901c1a7f", + "name": "gpio1State", + "displayName": "Relay 1 enabled", + "displayNameEvent": "Relay 1 enabled changed", + "type": "bool", + "cached": true, + "defaultValue": false + }, + { + "id": "15608d58-b1d4-4696-ac1a-62aec5ec44ab", + "name": "gpio2State", + "displayName": "Relay 2 enabled", + "displayNameEvent": "Relay 2 enabled changed", + "type": "bool", + "cached": true, + "defaultValue": false + } + ] + } + ] + } + ] +} diff --git a/sgready/meta.json b/sgready/meta.json new file mode 100644 index 00000000..a7d13baf --- /dev/null +++ b/sgready/meta.json @@ -0,0 +1,13 @@ +{ + "title": "SG-Ready", + "tagline": "Control heat pumps offering the SG-Ready interface using GPIOs.", + "icon": "smart-grid-logo.png", + "stability": "community", + "offline": true, + "technologies": [ + ], + "categories": [ + "heating" + ] +} + diff --git a/sgready/sgready.pro b/sgready/sgready.pro new file mode 100644 index 00000000..a2c1b4a4 --- /dev/null +++ b/sgready/sgready.pro @@ -0,0 +1,13 @@ +include(../plugins.pri) + +PKGCONFIG += nymea-gpio + +SOURCES += \ + integrationpluginsgready.cpp \ + sgreadyinterface.cpp + +HEADERS += \ + integrationpluginsgready.h \ + sgreadyinterface.h + + diff --git a/sgready/sgreadyinterface.cpp b/sgready/sgreadyinterface.cpp new file mode 100644 index 00000000..f6b7e2ee --- /dev/null +++ b/sgready/sgreadyinterface.cpp @@ -0,0 +1,181 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "sgreadyinterface.h" +#include "extern-plugininfo.h" + +SgReadyInterface::SgReadyInterface(int gpioNumber1, int gpioNumber2, QObject *parent) : + QObject(parent), + m_gpioNumber1(gpioNumber1), + m_gpioNumber2(gpioNumber2) +{ + +} + +SgReadyInterface::SgReadyMode SgReadyInterface::sgReadyMode() const +{ + return m_sgReadyMode; +} + +bool SgReadyInterface::setSgReadyMode(SgReadyMode sgReadyMode) +{ + if (!isValid()) + return false; + + /* https://www.waermepumpe.de/normen-technik/sg-ready/ + * + * Off: 1,0 + * Low: 0,0 + * Standard: 0,1 + * High: 1,1 + */ + + QPair gpioSettings; + switch (sgReadyMode) { + case SgReadyModeOff: + gpioSettings.first = true; + gpioSettings.second = false; + break; + case SgReadyModeLow: + gpioSettings.first = false; + gpioSettings.second = false; + break; + case SgReadyModeStandard: + gpioSettings.first = false; + gpioSettings.second = true; + break; + case SgReadyModeHigh: + gpioSettings.first = true; + gpioSettings.second = true; + break; + } + + if (!m_gpio1->setValue(gpioSettings.first ? Gpio::ValueHigh : Gpio::ValueLow)) { + qCWarning(dcSgReady()) << "Could not switch GPIO 1 for setting" << sgReadyMode; + return false; + } + + if (!m_gpio2->setValue(gpioSettings.second ? Gpio::ValueHigh : Gpio::ValueLow)) { + qCWarning(dcSgReady()) << "Could not switch GPIO 2 for setting" << sgReadyMode; + return false; + } + + if (m_sgReadyMode != sgReadyMode) { + m_sgReadyMode = sgReadyMode; + emit sgReadyModeChanged(m_sgReadyMode); + } + + return true; +} + +bool SgReadyInterface::setup(bool gpio1Enabled, bool gpio2Enabled) +{ + m_gpio1 = setupGpio(m_gpioNumber1, gpio1Enabled); + if (!m_gpio1) { + qCWarning(dcSgReady()) << "Failed to set up SG ready interface gpio 1" << m_gpioNumber1; + return false; + } + + m_gpio2 = setupGpio(m_gpioNumber2, gpio2Enabled); + if (!m_gpio2) { + delete m_gpio1; + m_gpio1 = nullptr; + qCWarning(dcSgReady()) << "Failed to set up SG ready interface gpio 2" << m_gpioNumber1; + return false; + } + + /* https://www.waermepumpe.de/normen-technik/sg-ready/ + * + * Off: 1,0 + * Low: 0,0 + * Standard: 0,1 + * High: 1,1 + */ + + if (gpio1Enabled && !gpio2Enabled) { + m_sgReadyMode = SgReadyModeOff; + } else if (!gpio1Enabled && !gpio2Enabled) { + m_sgReadyMode = SgReadyModeLow; + } else if (!gpio1Enabled && gpio2Enabled) { + m_sgReadyMode = SgReadyModeStandard; + } else { + m_sgReadyMode = SgReadyModeHigh; + } + + emit sgReadyModeChanged(m_sgReadyMode); + + return true; +} + +bool SgReadyInterface::isValid() const +{ + return m_gpioNumber1 >= 0 && m_gpioNumber2 >= 0 && m_gpio1 && m_gpio2; +} + +Gpio *SgReadyInterface::gpio1() const +{ + return m_gpio1; +} + +Gpio *SgReadyInterface::gpio2() const +{ + return m_gpio2; +} + +Gpio *SgReadyInterface::setupGpio(int gpioNumber, bool initialValue) +{ + if (gpioNumber < 0) { + qCWarning(dcSgReady()) << "Invalid gpio number for setting up gpio" << gpioNumber; + return nullptr; + } + + // Create and configure gpio + Gpio *gpio = new Gpio(gpioNumber, this); + if (!gpio->exportGpio()) { + qCWarning(dcSgReady()) << "Could not export gpio" << gpioNumber; + gpio->deleteLater(); + return nullptr; + } + + if (!gpio->setDirection(Gpio::DirectionOutput)) { + qCWarning(dcSgReady()) << "Failed to configure gpio" << gpioNumber << "as output"; + gpio->deleteLater(); + return nullptr; + } + + // Set the pin to the initial value + if (!gpio->setValue(initialValue ? Gpio::ValueHigh : Gpio::ValueLow)) { + qCWarning(dcSgReady()) << "Failed to set initially value" << initialValue << "for gpio" << gpioNumber; + gpio->deleteLater(); + return nullptr; + } + + return gpio; +} diff --git a/sgready/sgreadyinterface.h b/sgready/sgreadyinterface.h new file mode 100644 index 00000000..5c1f9869 --- /dev/null +++ b/sgready/sgreadyinterface.h @@ -0,0 +1,75 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef SGREADYINTERFACE_H +#define SGREADYINTERFACE_H + +#include + +#include "gpio.h" + +class SgReadyInterface : public QObject +{ + Q_OBJECT +public: + enum SgReadyMode { + SgReadyModeOff, + SgReadyModeLow, + SgReadyModeStandard, + SgReadyModeHigh + }; + Q_ENUM(SgReadyMode) + + explicit SgReadyInterface(int gpioNumber1, int gpioNumber2, QObject *parent = nullptr); + + SgReadyMode sgReadyMode() const; + bool setSgReadyMode(SgReadyMode sgReadyMode); + + bool setup(bool gpio1Enabled, bool gpio2Enabled); + bool isValid() const; + + Gpio *gpio1() const; + Gpio *gpio2() const; + +signals: + void sgReadyModeChanged(SgReadyMode sgReadyMode); + +private: + SgReadyMode m_sgReadyMode = SgReadyModeStandard; + int m_gpioNumber1 = -1; + int m_gpioNumber2 = -1; + + Gpio *m_gpio1 = nullptr; + Gpio *m_gpio2 = nullptr; + + Gpio *setupGpio(int gpioNumber, bool initialValue); +}; + +#endif // SGREADYINTERFACE_H diff --git a/sgready/smart-grid-logo.png b/sgready/smart-grid-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..023ee6ecd8dd67a443f8fde07d73fb0755229840 GIT binary patch literal 30302 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 literal 0 HcmV?d00001 From b4daf5a693e49cc78cb9d06a70bc98aeb9fb68a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Tue, 12 Oct 2021 14:56:52 +0200 Subject: [PATCH 2/3] Add translations --- ...3e2f3-b2f7-445d-ab14-033000485bd8-en_US.ts | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 sgready/translations/7923e2f3-b2f7-445d-ab14-033000485bd8-en_US.ts diff --git a/sgready/translations/7923e2f3-b2f7-445d-ab14-033000485bd8-en_US.ts b/sgready/translations/7923e2f3-b2f7-445d-ab14-033000485bd8-en_US.ts new file mode 100644 index 00000000..08785c4d --- /dev/null +++ b/sgready/translations/7923e2f3-b2f7-445d-ab14-033000485bd8-en_US.ts @@ -0,0 +1,112 @@ + + + + + IntegrationPluginSgReady + + + No GPIOs available on this system. + Error discovering SG ready GPIOs + + + + + No GPIOs found on this system. + Error discovering SG ready GPIOs + + + + + Failed to set up the GPIO hardware interface. + Error message if SG ready GPIOs setup failed + + + + + SgReady + + + GPIO number 1 + The name of the ParamType (ThingClass: sgReadyInterface, Type: thing, ID: {8de25aef-d868-4410-abd3-3bec9c46aba3}) + + + + + GPIO number 2 + The name of the ParamType (ThingClass: sgReadyInterface, Type: thing, ID: {113ba124-a392-4bc3-861a-f7feaab82fc4}) + + + + + + Relay 1 enabled + The name of the ParamType (ThingClass: sgReadyInterface, EventType: gpio1State, ID: {d2c83778-693f-4146-a656-a8ed901c1a7f}) +---------- +The name of the StateType ({d2c83778-693f-4146-a656-a8ed901c1a7f}) of ThingClass sgReadyInterface + + + + + Relay 1 enabled changed + The name of the EventType ({d2c83778-693f-4146-a656-a8ed901c1a7f}) of ThingClass sgReadyInterface + + + + + + Relay 2 enabled + The name of the ParamType (ThingClass: sgReadyInterface, EventType: gpio2State, ID: {15608d58-b1d4-4696-ac1a-62aec5ec44ab}) +---------- +The name of the StateType ({15608d58-b1d4-4696-ac1a-62aec5ec44ab}) of ThingClass sgReadyInterface + + + + + Relay 2 enabled changed + The name of the EventType ({15608d58-b1d4-4696-ac1a-62aec5ec44ab}) of ThingClass sgReadyInterface + + + + + SG Ready interface + The name of the ThingClass ({5a5f3aca-a958-4bca-b8fc-1168fe3371ec}) + + + + + SG-Ready + The name of the plugin SgReady ({7923e2f3-b2f7-445d-ab14-033000485bd8}) + + + + + Set smart grid mode + The name of the ActionType ({91008e09-2702-4bd5-942e-398513ae3d15}) of ThingClass sgReadyInterface + + + + + + + Smart grid mode + The name of the ParamType (ThingClass: sgReadyInterface, ActionType: sgReadyMode, ID: {91008e09-2702-4bd5-942e-398513ae3d15}) +---------- +The name of the ParamType (ThingClass: sgReadyInterface, EventType: sgReadyMode, ID: {91008e09-2702-4bd5-942e-398513ae3d15}) +---------- +The name of the StateType ({91008e09-2702-4bd5-942e-398513ae3d15}) of ThingClass sgReadyInterface + + + + + Smart grid mode changed + The name of the EventType ({91008e09-2702-4bd5-942e-398513ae3d15}) of ThingClass sgReadyInterface + + + + + nymea + The name of the vendor ({2062d64d-3232-433c-88bc-0d33c0ba2ba6}) + + + + From 055a535a8d9cb12916f3e02b8dfed1528e4ad2e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 10 Dec 2021 10:48:56 +0100 Subject: [PATCH 3/3] Fix typo --- sgready/integrationpluginsgready.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sgready/integrationpluginsgready.cpp b/sgready/integrationpluginsgready.cpp index 713f577d..4dc6a92c 100644 --- a/sgready/integrationpluginsgready.cpp +++ b/sgready/integrationpluginsgready.cpp @@ -38,9 +38,7 @@ IntegrationPluginSgReady::IntegrationPluginSgReady() void IntegrationPluginSgReady::init() { - // Load possible system configurations for gpio pairs depending on well knwon platforms - - + // TODO: Load possible system configurations for gpio pairs depending on well knwon platforms } void IntegrationPluginSgReady::discoverThings(ThingDiscoveryInfo *info) @@ -128,7 +126,7 @@ void IntegrationPluginSgReady::executeAction(ThingActionInfo *info) return; } - // FIXME: the modes have timeing constrains we need to take care off. + // FIXME: the modes have timing constrains we need to take care off. if (info->action().actionTypeId() == sgReadyInterfaceSgReadyModeActionTypeId) { QString sgReadyModeString = info->action().paramValue(sgReadyInterfaceSgReadyModeActionSgReadyModeParamTypeId).toString();