From c1cdaac571b5d711f0849ee11af4efaf080bee45 Mon Sep 17 00:00:00 2001 From: Boernsman Date: Fri, 19 Jun 2020 11:52:22 +0200 Subject: [PATCH] added sunspec plugin --- debian/control | 19 +- debian/nymea-plugin-sunspec.install.in | 1 + mypv/integrationpluginmypv.cpp | 1 - nymea-plugins-modbus.pro | 1 + sunspec/README.md | 16 ++ sunspec/integrationpluginsunspec.cpp | 119 +++++++++++++ sunspec/integrationpluginsunspec.h | 80 +++++++++ sunspec/integrationpluginsunspec.json | 238 +++++++++++++++++++++++++ sunspec/meta.json | 12 ++ sunspec/sunspec.cpp | 0 sunspec/sunspec.h | 0 sunspec/sunspec.png | Bin 0 -> 8836 bytes sunspec/sunspec.pro | 15 ++ 13 files changed, 499 insertions(+), 3 deletions(-) create mode 100644 debian/nymea-plugin-sunspec.install.in create mode 100644 sunspec/README.md create mode 100644 sunspec/integrationpluginsunspec.cpp create mode 100644 sunspec/integrationpluginsunspec.h create mode 100644 sunspec/integrationpluginsunspec.json create mode 100644 sunspec/meta.json create mode 100644 sunspec/sunspec.cpp create mode 100644 sunspec/sunspec.h create mode 100644 sunspec/sunspec.png create mode 100644 sunspec/sunspec.pro 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 0000000000000000000000000000000000000000..7a52a4529d365fccd4b06978df239f8736c553e5 GIT binary patch literal 8836 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 WJti%64eyJ(1VLU#1yn0#8uDMIk*;+B literal 0 HcmV?d00001 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 \