diff --git a/debian/control b/debian/control index 4a3dc3c..bfaa5ac 100644 --- a/debian/control +++ b/debian/control @@ -35,6 +35,7 @@ Section: libs Depends: ${shlibs:Depends}, ${misc:Depends}, nymea-plugins-modbus-translations + nymea-plugins-translations Description: nymea.io plugin to send and receive generic modbus commands The nymea daemon is a plugin based IoT (Internet of Things) server. The server works like a translator for devices, things and services and @@ -50,7 +51,7 @@ Architecture: any Section: libs Depends: ${shlibs:Depends}, ${misc:Depends}, - nymea-plugins-modbus-translations, + nymea-plugins-modbus-translations Description: nymea.io plugin for my-pv heating rods The nymea daemon is a plugin based IoT (Internet of Things) server. The server works like a translator for devices, things and services and @@ -61,6 +62,21 @@ Description: nymea.io plugin for my-pv heating rods This package will install the nymea.io plugin for my-pv +Package: nymea-plugin-sunspec +Architecture: any +Depends: ${shlibs:Depends}, + ${misc:Depends}, + nymea-plugins-modbus-translations +Description: nymea.io plugin for SunSpec Modbus devices. + 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 manufactor independent sunspec devices. + + Package: nymea-plugin-wallbe Architecture: any Section: libs @@ -89,4 +105,3 @@ Description: Translation files for nymea modbus plugins - translations in the system and create individual scenes and behaviors for your environment. . This package provides the translation files for all nymea modbus plugins. - diff --git a/debian/nymea-plugin-sunspec.install.in b/debian/nymea-plugin-sunspec.install.in new file mode 100644 index 0000000..03cc550 --- /dev/null +++ b/debian/nymea-plugin-sunspec.install.in @@ -0,0 +1 @@ +usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_devicepluginsunspec.so diff --git a/mypv/integrationpluginmypv.cpp b/mypv/integrationpluginmypv.cpp index 1dae803..f779210 100644 --- a/mypv/integrationpluginmypv.cpp +++ b/mypv/integrationpluginmypv.cpp @@ -195,7 +195,6 @@ void IntegrationPluginMyPv::executeAction(ThingActionInfo *info) void IntegrationPluginMyPv::onRefreshTimer() { - foreach (Thing *thing, myThings()) { update(thing); } diff --git a/nymea-plugins-modbus.pro b/nymea-plugins-modbus.pro index 7d5b93a..92c6b5c 100644 --- a/nymea-plugins-modbus.pro +++ b/nymea-plugins-modbus.pro @@ -4,6 +4,7 @@ PLUGIN_DIRS = \ drexelundweiss \ modbuscommander \ mypv \ + sunspec \ wallbe \ message(============================================) diff --git a/sunspec/README.md b/sunspec/README.md new file mode 100644 index 0000000..95286d7 --- /dev/null +++ b/sunspec/README.md @@ -0,0 +1,16 @@ +# SunSpec + +## Supported Things + +* SunSpec Inverter +* SunSpec PV Modules +* SunSpec Meter +* SunSpec Tracker +* SunSpec Storage + +## Requirements + +* The package 'nymea-plugin-sunspec' must be installed. + +## More +https://sunspec.org diff --git a/sunspec/integrationpluginsunspec.cpp b/sunspec/integrationpluginsunspec.cpp new file mode 100644 index 0000000..7974f77 --- /dev/null +++ b/sunspec/integrationpluginsunspec.cpp @@ -0,0 +1,119 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, 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 "plugininfo.h" +#include "integrationpluginsunspec.h" + +#include + +IntegrationPluginSunSpec::IntegrationPluginSunSpec() +{ +} + +void IntegrationPluginSunSpec::discoverThings(ThingDiscoveryInfo *info) +{ + // Discovery possible? + Q_ASSERT_X(false, "discoverThing", QString("Unhandled thingClassId: %1").arg(info->thingClassId().toString()).toUtf8()); +} + +void IntegrationPluginSunSpec::setupThing(ThingSetupInfo *info) +{ + if (info->thing()->thingClassId() == sunspecInverterThingClassId) { + + } else if (info->thing()->thingClassId() == sunspecPvModuleThingClassId) { + + } else if (info->thing()->thingClassId() == sunspecMeterThingClassId) { + + } else if (info->thing()->thingClassId() == sunspecTrackerThingClassId) { + + } else if (info->thing()->thingClassId() == sunspecStorageThingClassId) { + + } else { + Q_ASSERT_X(false, "setupThing", QString("Unhandled thingClassId: %1").arg(info->thing()->thingClassId().toString()).toUtf8()); + } +} + +void IntegrationPluginSunSpec::postSetupThing(Thing *thing) +{ + Q_UNUSED(thing) + + if (!m_refreshTimer) { + int refreshTime = configValue(sunSpecPluginUpdateIntervalParamTypeId).toInt(); + m_refreshTimer = hardwareManager()->pluginTimerManager()->registerTimer(refreshTime); + connect(m_refreshTimer, &PluginTimer::timeout, this, &IntegrationPluginSunSpec::onRefreshTimer); + } +} + +void IntegrationPluginSunSpec::thingRemoved(Thing *thing) +{ + Q_UNUSED(thing) + + if (myThings().isEmpty()) { + hardwareManager()->pluginTimerManager()->unregisterTimer(m_refreshTimer); + m_refreshTimer = nullptr; + } +} + +void IntegrationPluginSunSpec::executeAction(ThingActionInfo *info) +{ + Thing *thing = info->thing(); + //Action action = info->action(); + + if (thing->thingClassId() == sunspecInverterThingClassId) { + info->finish(Thing::ThingErrorActionTypeNotFound); + } else if (thing->thingClassId() == sunspecMeterThingClassId) { + info->finish(Thing::ThingErrorActionTypeNotFound); + } else if (thing->thingClassId() == sunspecTrackerThingClassId) { + info->finish(Thing::ThingErrorActionTypeNotFound); + } else if (thing->thingClassId() == sunspecPvModuleThingClassId) { + info->finish(Thing::ThingErrorActionTypeNotFound); + } else if (thing->thingClassId() == sunspecStorageThingClassId) { + info->finish(Thing::ThingErrorActionTypeNotFound); + } else { + Q_ASSERT_X(false, "executeAction", QString("Unhandled thingClassId: %1").arg(info->thing()->thingClassId().toString()).toUtf8()); + } +} + +void IntegrationPluginSunSpec::onRefreshTimer() +{ + //get data +} + +void IntegrationPluginSunSpec::onPluginConfigurationChanged(const ParamTypeId ¶mTypeId, const QVariant &value) +{ + // Check refresh schedule + if (paramTypeId == sunSpecPluginUpdateIntervalParamTypeId) { + if (m_refreshTimer) { + int refreshTime = value.toInt(); + m_refreshTimer->stop(); + m_refreshTimer->startTimer(refreshTime); + } + } +} diff --git a/sunspec/integrationpluginsunspec.h b/sunspec/integrationpluginsunspec.h new file mode 100644 index 0000000..85e62a9 --- /dev/null +++ b/sunspec/integrationpluginsunspec.h @@ -0,0 +1,80 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, 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 INTEGRATIONPLUGINSUNSPEC_H +#define INTEGRATIONPLUGINSUNSPEC_H + +#include "integrations/integrationplugin.h" +#include "plugintimer.h" + +#include "../modbus/modbustcpmaster.h" + +#include + +class IntegrationPluginSunSpec: public IntegrationPlugin +{ + Q_OBJECT + + Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationpluginsunspec.json") + Q_INTERFACES(IntegrationPlugin) + + +public: + explicit IntegrationPluginSunSpec(); + + 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: + + PluginTimer *m_refreshTimer = nullptr; + QHash m_modbusTcpMasters; + QHash m_asyncActions; + + void update(Thing *thing); + +private slots: + void onRefreshTimer(); + + void onPluginConfigurationChanged(const ParamTypeId ¶mTypeId, const QVariant &value); + + void onConnectionStateChanged(bool status); + void onWriteRequestExecuted(QUuid requestId, bool success); + void onWriteRequestError(QUuid requestId, const QString &error); + + void onReceivedHoldingRegister(quint32 slaveAddress, quint32 modbusRegister, const QVector &values); + void onReceivedInputRegister(quint32 slaveAddress, quint32 modbusRegister, const QVector &values); +}; + +#endif // INTEGRATIONPLUGINSUNSPEC_H + diff --git a/sunspec/integrationpluginsunspec.json b/sunspec/integrationpluginsunspec.json new file mode 100644 index 0000000..3a0ffbf --- /dev/null +++ b/sunspec/integrationpluginsunspec.json @@ -0,0 +1,238 @@ +{ + "name": "SunSpec", + "displayName": "sunspec", + "id": "73c7efcc-80d5-4166-ad97-2cbbeb129d91", + "paramTypes":[ + { + "id": "52da5222-9a94-47a2-9adc-004541d2f5ed", + "name": "updateInterval", + "displayName": "Update interval", + "type": "int", + "unit": "Seconds", + "defaultValue": 15 + } + ], + "vendors": [ + { + "name": "sunspec", + "displayName": "SunSpec", + "id": "c143a7b4-a16c-4fff-86a3-9ffab3d6841d", + "thingClasses": [ + { + "name": "sunspecInverter", + "displayName": "SunSpec Inverter", + "id": "2e4122ea-96a5-415c-b5e2-7d6012265a83", + "createMethods": [ "User" ], + "interfaces": ["connectable"], + "paramTypes": [ + { + "id": "6ffaa694-a4f2-4936-b043-37679449a34b", + "name":"ipAddress", + "displayName": "IP address", + "type": "QString" + }, + { + "id": "08bf6597-976d-4fb9-8fc2-4372c07961d4", + "name":"serialNumber", + "displayName": "Serial number", + "type": "QString" + } + ], + "stateTypes":[ + { + "id": "4401468c-0385-40a9-b436-daf7ed6a50d5", + "name": "connected", + "displayName": "Connected", + "displayNameEvent": "Connected changed", + "type": "bool", + "defaultValue": false, + "cached": false + }, + { + "id": "9bdcc785-4738-437e-88a0-fc231095c2dd", + "name": "power", + "displayName": "Power", + "displayNameEvent": "Power changed", + "displayNameAction": "Change power", + "type": "bool", + "defaultValue": 0, + "writable": true + } + ] + }, + { + "name": "sunspecPvModule", + "displayName": "SunSpec PV Module", + "id": "fb7ff0df-a745-4313-83e4-1e5007b06fe2", + "createMethods": [ "User" ], + "interfaces": ["connectable"], + "paramTypes": [ + { + "id": "890e468b-fc76-4641-9569-93cd45e6bb8d", + "name":"ipAddress", + "displayName": "IP address", + "type": "QString" + }, + { + "id": "d5a9510d-720f-4a28-9d91-977eedd022bd", + "name":"serialNumber", + "displayName": "Serial number", + "type": "QString" + } + ], + "stateTypes":[ + { + "id": "edc032d2-022f-43f7-9131-831ad23ee62a", + "name": "connected", + "displayName": "Connected", + "displayNameEvent": "Connected changed", + "type": "bool", + "defaultValue": false, + "cached": false + }, + { + "id": "0b7485eb-3cf7-45b2-87cf-9ec85366b197", + "name": "power", + "displayName": "Power", + "displayNameEvent": "Power changed", + "displayNameAction": "Change power", + "type": "bool", + "defaultValue": 0, + "writable": true + } + ] + }, + { + "name": "sunspecMeter", + "displayName": "SunSpec Meter", + "id": "68f822f9-ff30-4275-b229-39a3674fead7", + "createMethods": [ "User" ], + "interfaces": ["connectable"], + "paramTypes": [ + { + "id": "66bdb89b-bbd4-4edf-96df-649014d94c42", + "name":"ipAddress", + "displayName": "IP address", + "type": "QString" + }, + { + "id": "89af6d27-4b81-42ef-9883-1e2ba2067884", + "name":"serialNumber", + "displayName": "Serial number", + "type": "QString" + } + ], + "stateTypes":[ + { + "id": "36f861c7-afc1-4725-b41f-67113200d78f", + "name": "connected", + "displayName": "Connected", + "displayNameEvent": "Connected changed", + "type": "bool", + "defaultValue": false, + "cached": false + }, + { + "id": "36f18720-69ca-4021-9328-262d87397f1b", + "name": "power", + "displayName": "Power", + "displayNameEvent": "Power changed", + "displayNameAction": "Change power", + "type": "bool", + "defaultValue": 0, + "writable": true + } + ] + }, + { + "name": "sunspecTracker", + "displayName": "SunSpec Tracker", + "id": "9941da30-a6d6-475d-8244-3c2145b419e6", + "createMethods": [ "User" ], + "interfaces": ["connectable"], + "paramTypes": [ + { + "id": "ccdcca78-7efa-4253-8fdb-8731e6880e9b", + "name":"ipAddress", + "displayName": "IP address", + "type": "QString" + }, + { + "id": "67ce05ff-14bf-4d43-94ba-d5f290278514", + "name":"serialNumber", + "displayName": "Serial number", + "type": "QString" + } + ], + "stateTypes":[ + { + "id": "fe57e465-e49e-4d50-b880-6d9a243783ff", + "name": "connected", + "displayName": "Connected", + "displayNameEvent": "Connected changed", + "type": "bool", + "defaultValue": false, + "cached": false + }, + { + "id": "d2bbba4b-998f-444e-935f-f958927afddd", + "name": "power", + "displayName": "Power", + "displayNameEvent": "Power changed", + "displayNameAction": "Change power", + "type": "bool", + "defaultValue": 0, + "writable": true + } + ] + }, + { + "name": "sunspecStorage", + "displayName": "SunSpec Storage", + "id": "9a643ba8-346c-4127-a2f8-956a7133d75e", + "createMethods": [ "User" ], + "interfaces": ["connectable"], + "paramTypes": [ + { + "id": "421cacb9-a94d-4ba9-923c-3bc30d8b94c8", + "name":"ipAddress", + "displayName": "IP address", + "type": "QString" + }, + { + "id": "ae76db81-7969-440f-85f0-28ed46d772db", + "name":"serialNumber", + "displayName": "Serial number", + "type": "QString" + } + ], + "stateTypes":[ + { + "id": "25a1fb10-a6b9-4037-b7cf-ad481a65beb4", + "name": "connected", + "displayName": "Connected", + "displayNameEvent": "Connected changed", + "type": "bool", + "defaultValue": false, + "cached": false + }, + { + "id": "9c0e0b08-4461-4e54-aaf3-cab9155028da", + "name": "power", + "displayName": "Power", + "displayNameEvent": "Power changed", + "displayNameAction": "Change power", + "type": "bool", + "defaultValue": 0, + "writable": true + } + ] + } + ] + } + ] +} + + + + diff --git a/sunspec/meta.json b/sunspec/meta.json new file mode 100644 index 0000000..d93e59c --- /dev/null +++ b/sunspec/meta.json @@ -0,0 +1,12 @@ +{ + "title": "SunSpec", + "tagline": "Connect to SunSpec devices.", + "icon": "sunspec.png", + "stability": "consumer", + "offline": true, + "technologies": [ + "network" + ], + "categories": [ + ] +} diff --git a/sunspec/sunspec.cpp b/sunspec/sunspec.cpp new file mode 100644 index 0000000..e69de29 diff --git a/sunspec/sunspec.h b/sunspec/sunspec.h new file mode 100644 index 0000000..e69de29 diff --git a/sunspec/sunspec.png b/sunspec/sunspec.png new file mode 100644 index 0000000..7a52a45 Binary files /dev/null and b/sunspec/sunspec.png differ diff --git a/sunspec/sunspec.pro b/sunspec/sunspec.pro new file mode 100644 index 0000000..a9c3e6a --- /dev/null +++ b/sunspec/sunspec.pro @@ -0,0 +1,15 @@ +include(../plugins.pri) + +QT += \ + network \ + serialbus \ + +SOURCES += \ + integrationpluginsunspec.cpp \ + sunspec.cpp \ + ../modbus/modbustcpmaster.cpp \ + +HEADERS += \ + integrationpluginsunspec.h \ + sunspec.h \ + ../modbus/modbustcpmaster.h \