From ee205a5bd083bd1e9b733e595023f9d19ab40fea Mon Sep 17 00:00:00 2001 From: Devendra Date: Sun, 23 Mar 2025 01:36:56 +0530 Subject: [PATCH 1/4] Add v2xeamberelectric plugin in nymea_plugin_repo --- v2xeamberelectric/.gitignore | 43 ++ v2xeamberelectric/LICENSE.LGPL3 | 165 ++++++++ v2xeamberelectric/README.md | 8 + v2xeamberelectric/debian/changelog | 5 + v2xeamberelectric/debian/compat | 1 + v2xeamberelectric/debian/control | 26 ++ v2xeamberelectric/debian/copyright | 14 + .../nymea-plugin-v2xeambereletric.install.in | 1 + v2xeamberelectric/debian/rules | 29 ++ v2xeamberelectric/debian/source/format | 1 + .../integrationpluginv2xe_amber_electric.json | 176 ++++++++ v2xeamberelectric/v2xe_amber_electric.cpp | 399 ++++++++++++++++++ v2xeamberelectric/v2xe_amber_electric.h | 84 ++++ v2xeamberelectric/v2xe_amber_electric.pro | 13 + 14 files changed, 965 insertions(+) create mode 100644 v2xeamberelectric/.gitignore create mode 100644 v2xeamberelectric/LICENSE.LGPL3 create mode 100644 v2xeamberelectric/README.md create mode 100644 v2xeamberelectric/debian/changelog create mode 100644 v2xeamberelectric/debian/compat create mode 100644 v2xeamberelectric/debian/control create mode 100644 v2xeamberelectric/debian/copyright create mode 100644 v2xeamberelectric/debian/nymea-plugin-v2xeambereletric.install.in create mode 100644 v2xeamberelectric/debian/rules create mode 100644 v2xeamberelectric/debian/source/format create mode 100644 v2xeamberelectric/integrationpluginv2xe_amber_electric.json create mode 100644 v2xeamberelectric/v2xe_amber_electric.cpp create mode 100644 v2xeamberelectric/v2xe_amber_electric.h create mode 100644 v2xeamberelectric/v2xe_amber_electric.pro diff --git a/v2xeamberelectric/.gitignore b/v2xeamberelectric/.gitignore new file mode 100644 index 00000000..1625ed4e --- /dev/null +++ b/v2xeamberelectric/.gitignore @@ -0,0 +1,43 @@ +# C++ objects and libs + +*.slo +*.lo +*.o +*.a +*.la +*.lai +*.so +*.dll +*.dylib + +# Qt-es + +/.qmake.cache +/.qmake.stash +*.pro.user +*.pro.user.* +*.qbs.user +*.qbs.user.* +*.moc +moc_*.cpp +qrc_*.cpp +ui_*.h +Makefile* +*-build-* + +# QtCreator + +*.autosave + +#QtCtreator Qml +*.qmlproject.user +*.qmlproject.user.* + +build-* +html +build +vendor +*.qmlc +*.swp + +.crossbuilder diff --git a/v2xeamberelectric/LICENSE.LGPL3 b/v2xeamberelectric/LICENSE.LGPL3 new file mode 100644 index 00000000..0a041280 --- /dev/null +++ b/v2xeamberelectric/LICENSE.LGPL3 @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/v2xeamberelectric/README.md b/v2xeamberelectric/README.md new file mode 100644 index 00000000..7c08a00d --- /dev/null +++ b/v2xeamberelectric/README.md @@ -0,0 +1,8 @@ +# v2xe_amber_electric_api +-------------------------------- + +Description of the plugin... + +plugin for amber electric api to get live data of energy use , + + diff --git a/v2xeamberelectric/debian/changelog b/v2xeamberelectric/debian/changelog new file mode 100644 index 00000000..ad09740e --- /dev/null +++ b/v2xeamberelectric/debian/changelog @@ -0,0 +1,5 @@ +nymea-plugin-v2xeamberelectric (0.0.1) bookworm; urgency=medium + + * Initial release. + + -- devendragajjar Mon, 21 Aug 2017 10:12:00 +0000 diff --git a/v2xeamberelectric/debian/compat b/v2xeamberelectric/debian/compat new file mode 100644 index 00000000..b4de3947 --- /dev/null +++ b/v2xeamberelectric/debian/compat @@ -0,0 +1 @@ +11 diff --git a/v2xeamberelectric/debian/control b/v2xeamberelectric/debian/control new file mode 100644 index 00000000..41a8107e --- /dev/null +++ b/v2xeamberelectric/debian/control @@ -0,0 +1,26 @@ +Source: nymea-plugin-v2xeamberelectric +Section: utils +Priority: optional +Maintainer: devendragajjar +Standards-Version: 4.6.0 +Build-depends: debhelper (>= 9.0.0), + libnymea1-dev, + nymea-dev-tools:native, + qt5-qmake:native, + pkg-config, + + +Package: nymea-plugin-v2xeamberelectric +Architecture: any +Multi-Arch: same +Section: libs +Depends: ${shlibs:Depends}, + ${misc:Depends}, +Description: nymea.io plugin for v2xeamberelectric + 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 v2xeamberelectric diff --git a/v2xeamberelectric/debian/copyright b/v2xeamberelectric/debian/copyright new file mode 100644 index 00000000..7c431a35 --- /dev/null +++ b/v2xeamberelectric/debian/copyright @@ -0,0 +1,14 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: ${ProjectName} +Upstream-Contact: devendragajjar +Copyright: 2024, devendragajjar + + +License: LGPL-3 + On Debian systems, the complete text of the GNU Lesser General + Public License can be found in `/usr/share/common-licenses/LGPL-3'. + +Files: * +License: LGPL-3 +Copyright: devendragajjar + diff --git a/v2xeamberelectric/debian/nymea-plugin-v2xeambereletric.install.in b/v2xeamberelectric/debian/nymea-plugin-v2xeambereletric.install.in new file mode 100644 index 00000000..d434a6ea --- /dev/null +++ b/v2xeamberelectric/debian/nymea-plugin-v2xeambereletric.install.in @@ -0,0 +1 @@ +usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationpluginEV_charger.so diff --git a/v2xeamberelectric/debian/rules b/v2xeamberelectric/debian/rules new file mode 100644 index 00000000..682dbb99 --- /dev/null +++ b/v2xeamberelectric/debian/rules @@ -0,0 +1,29 @@ +#!/usr/bin/make -f +# -*- makefile -*- + +export DH_VERBOSE=1 +DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) + +PREPROCESS_FILES := $(wildcard debian/*.in) + +$(PREPROCESS_FILES:.in=): %: %.in + sed 's,/@DEB_HOST_MULTIARCH@,$(DEB_HOST_MULTIARCH:%=/%),g' $< > $@ + +override_dh_install: $(PREPROCESS_FILES:.in=) + make -j9 install DESTDIR=debian/tmp AM_UPDATE_INFO_DIR=no INSTALL_ROOT=debian/tmp + dh_install + +override_dh_missing: + dh_missing --list-missing + +override_dh_auto_build: + dh_auto_build + make lrelease + +override_dh_auto_clean: + dh_auto_clean + rm -rf $(PREPROCESS_FILES:.in=) + +%: + dh $@ --parallel + diff --git a/v2xeamberelectric/debian/source/format b/v2xeamberelectric/debian/source/format new file mode 100644 index 00000000..89ae9db8 --- /dev/null +++ b/v2xeamberelectric/debian/source/format @@ -0,0 +1 @@ +3.0 (native) diff --git a/v2xeamberelectric/integrationpluginv2xe_amber_electric.json b/v2xeamberelectric/integrationpluginv2xe_amber_electric.json new file mode 100644 index 00000000..30c11b16 --- /dev/null +++ b/v2xeamberelectric/integrationpluginv2xe_amber_electric.json @@ -0,0 +1,176 @@ +{ + "name": "Amber_Electric_plgn", + "displayName": "Amber_Electric_plgn", + "id": "0233c848-6f6f-4907-a51c-81391e4f5356", + "vendors": [ + { + "name": "Amber_Electric", + "displayName": "Amber_Electric", + "id": "ec1985b9-5891-435d-9264-e8e18d392978", + "thingClasses": [ + { + "name": "V2Xe_Amber_Electric", + "displayName": "V2Xe_Amber_Electric", + "id": "11295990-7002-432e-b90c-cd4010548a32", + "setupMethod": "JustAdd", + "createMethods": ["User"], + "interfaces": ["energystorage", "connectable"], + "paramTypes": [ + { + "id": "fc899f7b-f452-44dc-b72e-ee7bb8034ff0", + "name": "auth_token", + "displayName": "auth_token", + "type" : "QString", + "defaultValue": "" + }, + { + "id": "c50eac84-714e-4b9c-89d5-0b939b6c18d6", + "name": "crnt_site", + "displayName": "current_site", + "type" : "QString", + "defaultValue": "" + } + ], + "stateTypes": [ + { + "id": "faf2a6c0-1897-4b9b-903a-e12b281efe24", + "name": "connected", + "displayName": "Reachable", + "displayNameEvent": "Reachable changed", + "type": "bool", + "defaultValue": false, + "cached": false + }, + { + "id": "42c8a6f8-4f97-4871-8bfb-ac7e6ffffa74", + "name": "Sites", + "displayName": "Sites", + "displayNameEvent": "Sites_list_updated", + "type": "QString", + "writable": false, + "defaultValue": "" + }, + { + "id": "27c3f8e0-0803-4eb8-ba4f-ce78fb0997a9", + "name": "Type", + "displayName": "type", + "displayNameEvent": "type_evnet", + "type": "QString", + "defaultValue": "Amber" + }, + { + "id": "6e8d3fcd-c235-4793-95b5-321ca6e012a3", + "name": "price", + "displayName": "Feedin Price", + "displayNameEvent": "AveragePrice_changed", + "type": "double", + "minValue": 0, + "maxValue": 100, + "defaultValue": 100, + "unit": "EuroCentPerKiloWattHour", + "suggestLogging": true + }, + { + "id": "a25d3b55-9b93-4465-90e3-5d36adb8fb23", + "name": "currentprice", + "displayName": "Current Price", + "displayNameEvent": "currentPrice_changed", + "type": "double", + "minValue": 0, + "maxValue": 1000, + "unit":"EuroCentPerKiloWattHour", + "defaultValue": 0, + "suggestLogging": true + }, + { + "id": "cd1e22b2-2154-453a-bbdf-59156893258a", + "name": "currentfeedin", + "displayName": "Current Feedin", + "displayNameEvent": "currentfeedinPrice changed", + "type": "double", + "minValue": 0, + "maxValue": 1000, + "unit":"EuroCentPerKiloWattHour", + "defaultValue": 0, + "suggestLogging": true + }, + { + "id": "52188fdf-4a4d-4ca8-b02e-cea5ed8c1615", + "name": "futurefeedin", + "displayName": "Future Feedin", + "displayNameEvent": "futurefeedinPrice changed", + "type": "double", + "minValue": 0, + "maxValue": 1000, + "unit":"EuroCentPerKiloWattHour", + "defaultValue": 0, + "suggestLogging": true + }, + { + "id": "690d562e-a75d-4da9-940f-e1908544dbae", + "name": "chargingState", + "displayName": "Charging state", + "displayNameEvent": "Charging state changed", + "type": "QString", + "possibleValues": ["idle", "charging", "discharging"], + "defaultValue": "idle" + }, + { + "id": "d5ce4925-49e5-49b6-88d8-6e3889080be2", + "name": "currentPower", + "displayName": "Current power", + "displayNameEvent": "Current power changed", + "type": "double", + "unit": "Watt", + "defaultValue": 0, + "cached": false, + "suggestLogging": true + }, + { + "id": "420d2e55-afeb-4a83-b67a-e3c0a86ecc02", + "name": "capacity", + "displayName": "Capacity", + "displayNameEvent": "Capacity changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0 + }, + { + "id": "df196e56-f33a-4883-a9b4-345dab2bac95", + "name": "batteryLevel", + "displayName": "Battery level", + "displayNameEvent": "Battery level changed", + "type": "int", + "unit": "Percentage", + "defaultValue": "0", + "minValue": 0, + "maxValue": 100 + }, + { + "id": "6225b633-b159-4794-9e54-84912049fd32", + "name": "cellTemperature", + "displayName": "Cell temperature", + "displayNameEvent": "Cell temperature changed", + "type": "double", + "unit": "DegreeCelsius", + "defaultValue": "0", + "cached": false + }, + { + "id": "20410ff8-b9aa-4b63-a091-c3636278718e", + "name": "batteryCritical", + "displayName": "Battery level critical", + "displayNameEvent": "Battery level critical changed", + "type": "bool", + "defaultValue": false + } + + ] + } + ] + } + ] +} + + + diff --git a/v2xeamberelectric/v2xe_amber_electric.cpp b/v2xeamberelectric/v2xe_amber_electric.cpp new file mode 100644 index 00000000..060dfa4d --- /dev/null +++ b/v2xeamberelectric/v2xe_amber_electric.cpp @@ -0,0 +1,399 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2024 devendragajjar * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; * + * version 3 of the License. * + * * + * This library 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 library; If not, see * + * . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "v2xe_amber_electric.h" +#include "plugininfo.h" +#include "hardwaremanager.h" +#include "network/networkaccessmanager.h" + +#include +#include +#include +#include +#include +#include + + + + +const QString const_site = "01J1XBQFGX57137EH0C6AG040D"; +const QString no_of_data_need = "5"; +const QString site_http_link = "https://api.amber.com.au/v1/sites"; +const QString price_http_link_front = "https://api.amber.com.au/v1/sites/"; +const QString price_http_link_back = "/prices/current?next="+ no_of_data_need +"&previous=" + no_of_data_need; + //01J1XBQFGX57137EH0C6AG040D/prices/current?next=5&previous=5"; +const QString auth_token = "f5b2c823de5fed2f4c6bdb7c1b0db4f5"; +const QString renewble_http_link = "https://api.amber.com.au/v1/state/vic/renewables/current?next=48&previous=5&resolution=5"; + + +v2xe_amber_electric::v2xe_amber_electric() +{ + m_connectedStateTypeIds[V2Xe_Amber_ElectricThingClassId] = V2Xe_Amber_ElectricConnectedStateTypeId; + m_forecastPriceStateTypeIds[V2Xe_Amber_ElectricThingClassId] = V2Xe_Amber_ElectricForecastpriceStateTypeId; + m_currentPriceStateTypeIds[V2Xe_Amber_ElectricThingClassId] = V2Xe_Amber_ElectricCurrentpriceStateTypeId; + m_currentSiteTypeIds[V2Xe_Amber_ElectricThingClassId] = V2Xe_Amber_ElectricSitesStateTypeId; + m_currentfeddinStateTypeIds[V2Xe_Amber_ElectricThingClassId] = V2Xe_Amber_ElectricCurrentfeedinStateTypeId; + m_fururefeedinStateTypeIds[V2Xe_Amber_ElectricThingClassId] = V2Xe_Amber_ElectricFuturefeedinStateTypeId; + m_consumerKey = auth_token; +} + +v2xe_amber_electric::~v2xe_amber_electric() +{ + +} + +void v2xe_amber_electric::init() +{ + // Initialisation can be done here. + qCDebug(dcAmber_Electric_plgn()) << "Plugin initialized."; +} + + + +void v2xe_amber_electric::setupThing(ThingSetupInfo *info) +{ + // A thing is being set up. Use info->thing() to get details of the thing, do + // the required setup (e.g. connect to the device) and call info->finish() when done. + + qCDebug(dcAmber_Electric_plgn()) << "Setup thing" << info->thing()->name() << info->thing()->params(); + QString key = info->thing()->paramValue(V2Xe_Amber_ElectricThingAuth_tokenParamTypeId).toString(); + if (!key.isEmpty()) { + m_consumerKey = key; + qCCritical(dcAmber_Electric_plgn()) << "m_consumerKey set " << m_consumerKey << "key " << key; + } + + QString site = info->thing()->paramValue(V2Xe_Amber_ElectricThingCrnt_siteParamTypeId).toString(); + if (!site.isEmpty()) { + m_current_site = site; + qCCritical(dcAmber_Electric_plgn()) << "m_current_site set " << m_current_site ; + } + else{ + m_current_site = const_site; + } + + // use defult key for now + qCCritical(dcAmber_Electric_plgn()) << "No API key set."; + qCCritical(dcAmber_Electric_plgn()) << "Either install an API key pacakge (nymea-apikeysprovider-plugin-*) or provide a key in the plugin settings."; + + if (!m_pluginTimer) { + m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(60);//TODO make 30 minutes after test + connect(m_pluginTimer, &PluginTimer::timeout, this, &v2xe_amber_electric::onPluginTimer); + } + info->finish(Thing::ThingErrorNoError); +} + +void v2xe_amber_electric::onPluginTimer() +{ + foreach (Thing *thing, myThings()) { + + //requestPriceData(thing); // TODO +#if ENABLE_RENEWEBLE_API + requestRenewablesData(thing); //TODO +#endif + requestSiteData(thing); + requestSitePriceData(thing); + + } +} + +void v2xe_amber_electric::executeAction(ThingActionInfo *info) +{ + // An action is being executed. Use info->action() to get details about the action, + // do the required operations (e.g. send a command to the network) and call info->finish() when done. + + qCDebug(dcAmber_Electric_plgn()) << "Executing action for thing" << info->thing() << info->action().actionTypeId().toString() << info->action().params(); + + info->finish(Thing::ThingErrorNoError); +} + +void v2xe_amber_electric::thingRemoved(Thing *thing) +{ + // A thing is being removed from the system. Do the required cleanup + // (e.g. disconnect from the device) here. + + qCDebug(dcAmber_Electric_plgn()) << "Remove thing" << thing; +} + +void v2xe_amber_electric::requestSitePriceData(Thing* thing, ThingSetupInfo* setup) { + + QString price_http_link = price_http_link_front + m_current_site + price_http_link_back; + + m_serverUrls[V2Xe_Amber_ElectricThingClassId] = price_http_link; + + QNetworkRequest request; + request.setUrl(QUrl(m_serverUrls[V2Xe_Amber_ElectricThingClassId])); + + // Add the Authorization header with the token + QString token = thing->paramValue(m_consumerKey).toString(); + token = m_consumerKey; + qCCritical(dcAmber_Electric_plgn) << " using m_consumerKey " <networkManager()->get(request); + connect(reply, &QNetworkReply::finished, this, [this, thing, setup, reply]() { + reply->deleteLater(); + + int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + if (status != 200) { + qCWarning(dcAmber_Electric_plgn) << "Update reply HTTP error:" << status << reply->errorString(); + if (setup) { + setup->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Error getting data from server.")); + } else { + //thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), false);//TODO remove comment + } + return; + } + onSitePriceDataReceived(thing, setup, reply); + }); +} + +void v2xe_amber_electric::onSitePriceDataReceived(Thing* thing, ThingSetupInfo* setup, QNetworkReply* reply) { + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcAmber_Electric_plgn) << "Network error:" << reply->errorString(); + if (setup) { + setup->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Network error.")); + } + return; + } + + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll(), &error); + if (error.error != QJsonParseError::NoError) { + qCWarning(dcAmber_Electric_plgn) << "JSON parse error:" << error.errorString(); + if (setup) { + setup->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("JSON parse error.")); + } + return; + } + + if (jsonDoc.isArray()) { + QString channelType; + QJsonArray jsonArray = jsonDoc.array(); + for (const QJsonValue &value : jsonArray) { + if (value.isObject()) { + QJsonObject jsonObject = value.toObject(); + QString type = jsonObject["type"].toString(); //Get type + channelType = jsonObject["channelType"].toString(); + + //Current Price + if((type == "CurrentInterval") && channelType == "general"){ + + if (jsonObject.contains("perKwh") && jsonObject["perKwh"].isDouble()) { // Get perKwh + + double perkwh = jsonObject["perKwh"].toDouble(); + + thing->setStateValue(m_currentPriceStateTypeIds.value(thing->thingClassId()), qAbs(perkwh)); + } + } + + //Future Price + if((type == "ForecastInterval") && channelType == "general"){ + + if (jsonObject.contains("perKwh") && jsonObject["perKwh"].isDouble()) { // Get perKwh + + double perkwh = jsonObject["perKwh"].toDouble(); + + thing->setStateValue(m_forecastPriceStateTypeIds.value(thing->thingClassId()), qAbs(perkwh)); + } + } + + + // Current Feedin //TODO what is feed in price its dummy data + if((type == "CurrentInterval") && (channelType == "feedIn")){ + + if (jsonObject.contains("perKwh") && jsonObject["perKwh"].isDouble()) { // Get SportPerKwh + double spotperkwh = jsonObject["perKwh"].toDouble(); + + thing->setStateValue(m_currentfeddinStateTypeIds.value(thing->thingClassId()), qAbs(spotperkwh)); + } + } + + //Future Feedin + if((type == "ForecastInterval") && (channelType == "feedIn")){ + + if (jsonObject.contains("perKwh") && jsonObject["perKwh"].isDouble()) { // Get SportPerKwh + double spotperkwh = jsonObject["perKwh"].toDouble(); + + thing->setStateValue(m_fururefeedinStateTypeIds.value(thing->thingClassId()), qAbs(spotperkwh)); + } + } + + } + } + } + + if (setup) { + setup->finish(Thing::ThingErrorNoError); + } + thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), true); +} + + +void v2xe_amber_electric::requestSiteData(Thing* thing, ThingSetupInfo* setup) { + + m_serverUrls[V2Xe_Amber_ElectricThingClassId] = site_http_link; + + + QNetworkRequest request; + request.setUrl(QUrl(m_serverUrls[V2Xe_Amber_ElectricThingClassId])); + + // Add the Authorization header with the token + QString token = thing->paramValue(m_consumerKey).toString(); + token = m_consumerKey; + qCCritical(dcAmber_Electric_plgn) << " using m_consumerKey " <networkManager()->get(request); + connect(reply, &QNetworkReply::finished, this, [this, thing, setup, reply]() { + reply->deleteLater(); + + int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + if (status != 200) { + qCWarning(dcAmber_Electric_plgn) << "Update reply HTTP error:" << status << reply->errorString(); + if (setup) { + setup->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Error getting data from server.")); + } else { + thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), false); + } + return; + } + + onSiteDataReceived(thing, setup, reply); + }); +} + +void v2xe_amber_electric::onSiteDataReceived(Thing* thing, ThingSetupInfo* setup, QNetworkReply* reply) { + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcAmber_Electric_plgn) << "Network error:" << reply->errorString(); + if (setup) { + setup->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Network error.")); + } + return; + } + QVariantList stringList = {}; + QString l_site; + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll(), &error); + if (error.error != QJsonParseError::NoError) { + qCWarning(dcAmber_Electric_plgn) << "JSON parse error:" << error.errorString(); + if (setup) { + setup->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("JSON parse error.")); + } + return; + } + qCCritical(dcAmber_Electric_plgn) << "onSiteDataReceived " ; + if (jsonDoc.isArray()) { + QJsonArray jsonArray = jsonDoc.array(); + for (const QJsonValue &value : jsonArray) { + if (value.isObject()) { + QJsonObject jsonObject = value.toObject(); + QString type = jsonObject["id"].toString(); //Get type + + if(!type.isEmpty()){ //update + stringList.append(type); + qCCritical(dcAmber_Electric_plgn) << "type :" << type; + l_site = type; + } + } + } + } + thing->setStateValue(m_currentSiteTypeIds.value(thing->thingClassId()), l_site); + if (setup) { + setup->finish(Thing::ThingErrorNoError); + } + thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), true); +} + + + +#if ENABLE_RENEWEBLE_API +void v2xe_amber_electric::requestRenewablesData(Thing* thing, ThingSetupInfo* setup) { + + m_serverUrls[V2Xe_Amber_ElectricThingClassId] = renewble_http_link; + + QNetworkRequest request; + request.setUrl(QUrl(m_serverUrls[V2Xe_Amber_ElectricThingClassId])); + + // Add the Authorization header with the token + QString token = thing->paramValue(m_consumerKey).toString(); + request.setRawHeader("Authorization", QString("Bearer %1").arg(token).toUtf8()); + request.setRawHeader("accept", "application/json"); + + QNetworkReply* reply = hardwareManager()->networkManager()->get(request); + connect(reply, &QNetworkReply::finished, this, [this, thing, setup, reply]() { + reply->deleteLater(); + + int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + if (status != 200) { + qCWarning(dcAmber_Electric_plgn) << "Update reply HTTP error:" << status << reply->errorString(); + if (setup) { + setup->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Error getting data from server.")); + } else { + //thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), false);//TODO remove comment + } + return; + } + onRenewablesDataReceived(thing, setup, reply); + }); +} + + +void v2xe_amber_electric::onRenewablesDataReceived(Thing* thing, ThingSetupInfo* setup, QNetworkReply* reply) { + + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcAmber_Electric_plgn) << "Network error:" << reply->errorString(); + if (setup) { + setup->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Network error.")); + } + return; + } + + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll(), &error); + if (error.error != QJsonParseError::NoError) { + qCWarning(dcAmber_Electric_plgn) << "JSON parse error:" << error.errorString(); + if (setup) { + setup->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("JSON parse error.")); + } + return; + } + + if (jsonDoc.isArray()) { + QJsonArray jsonArray = jsonDoc.array(); + for (const QJsonValue &value : jsonArray) { + if (value.isObject()) { + QJsonObject jsonObject = value.toObject(); + QString type = jsonObject["type"].toString(); + if (type == "ActualRenewable") { + //double renewables = jsonObject["renewables"].toDouble(); + } + } + } + } + + if (setup) { + setup->finish(Thing::ThingErrorNoError); + } + thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), true); +} + +#endif diff --git a/v2xeamberelectric/v2xe_amber_electric.h b/v2xeamberelectric/v2xe_amber_electric.h new file mode 100644 index 00000000..6f267fae --- /dev/null +++ b/v2xeamberelectric/v2xe_amber_electric.h @@ -0,0 +1,84 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2020 devendragajjar * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; * + * version 3 of the License. * + * * + * This library 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 library; If not, see * + * . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef INTEGRATIONPLUGINEV_CHARGER_H +#define INTEGRATIONPLUGINEV_CHARGER_H + +#include "integrations/integrationplugin.h" +#include "extern-plugininfo.h" +#include "plugintimer.h" +#include "network/networkaccessmanager.h" + +#include +#include +#include +#include +#include + +#define ENABLE_RENEWEBLE_API 0 + +class v2xe_amber_electric: public IntegrationPlugin +{ + Q_OBJECT + + Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationpluginv2xe_amber_electric.json") + Q_INTERFACES(IntegrationPlugin) + + +public: + explicit v2xe_amber_electric(); + ~v2xe_amber_electric(); + + void init() override; + + void setupThing(ThingSetupInfo *info) override; + + void executeAction(ThingActionInfo *info) override; + + void thingRemoved(Thing *thing) override; + +private slots: + void onPluginTimer(); + void requestSitePriceData(Thing* thing, ThingSetupInfo* setup = nullptr); + void requestSiteData(Thing* thing, ThingSetupInfo* setup = nullptr); +#if ENABLE_RENEWEBLE_API + void requestRenewablesData(Thing* thing, ThingSetupInfo* setup = nullptr); +#endif + +private: + PluginTimer *m_pluginTimer = nullptr; + QString m_consumerKey; + QString m_current_site; + QHash m_serverUrls; + QHash m_connectedStateTypeIds; + QHash m_forecastPriceStateTypeIds; + QHash m_currentPriceStateTypeIds; + QHash m_currentSiteTypeIds; + QHash m_currentfeddinStateTypeIds; + QHash m_fururefeedinStateTypeIds; + + void onSiteDataReceived(Thing* thing, ThingSetupInfo* setup = nullptr, QNetworkReply* reply = nullptr); + void onSitePriceDataReceived(Thing* thing, ThingSetupInfo* setup = nullptr, QNetworkReply* reply = nullptr); +#if ENABLE_RENEWEBLE_API + void onRenewablesDataReceived(Thing* thing, ThingSetupInfo* setup = nullptr, QNetworkReply* reply = nullptr); +#endif +}; + +#endif // INTEGRATIONPLUGINEV_CHARGER_H diff --git a/v2xeamberelectric/v2xe_amber_electric.pro b/v2xeamberelectric/v2xe_amber_electric.pro new file mode 100644 index 00000000..5c58270e --- /dev/null +++ b/v2xeamberelectric/v2xe_amber_electric.pro @@ -0,0 +1,13 @@ +include($$[QT_INSTALL_PREFIX]/include/nymea/plugin.pri) + +QT += network + +SOURCES += \ + v2xe_amber_electric.cpp + +HEADERS += \ + v2xe_amber_electric.h + +DISTFILES += \ + integrationpluginv2xe_amber_electric.json + From fec48992389ab29a4789f71379e33c865ade722b Mon Sep 17 00:00:00 2001 From: Devendra Date: Sun, 23 Mar 2025 03:21:39 +0530 Subject: [PATCH 2/4] Add v2xeenergeymeter interaface --- .../integrationpluginv2xe_amber_electric.json | 76 +++---------------- 1 file changed, 9 insertions(+), 67 deletions(-) diff --git a/v2xeamberelectric/integrationpluginv2xe_amber_electric.json b/v2xeamberelectric/integrationpluginv2xe_amber_electric.json index 30c11b16..34c96834 100644 --- a/v2xeamberelectric/integrationpluginv2xe_amber_electric.json +++ b/v2xeamberelectric/integrationpluginv2xe_amber_electric.json @@ -14,7 +14,7 @@ "id": "11295990-7002-432e-b90c-cd4010548a32", "setupMethod": "JustAdd", "createMethods": ["User"], - "interfaces": ["energystorage", "connectable"], + "interfaces": ["v2xeenergymeter", "connectable"], "paramTypes": [ { "id": "fc899f7b-f452-44dc-b72e-ee7bb8034ff0", @@ -60,14 +60,14 @@ }, { "id": "6e8d3fcd-c235-4793-95b5-321ca6e012a3", - "name": "price", + "name": "forecastprice", "displayName": "Feedin Price", - "displayNameEvent": "AveragePrice_changed", + "displayNameEvent": "forecastPrice_changed", "type": "double", "minValue": 0, - "maxValue": 100, - "defaultValue": 100, - "unit": "EuroCentPerKiloWattHour", + "maxValue": 1000, + "defaultValue": 0, + "unit": "KiloWattHour", "suggestLogging": true }, { @@ -78,7 +78,7 @@ "type": "double", "minValue": 0, "maxValue": 1000, - "unit":"EuroCentPerKiloWattHour", + "unit":"KiloWattHour", "defaultValue": 0, "suggestLogging": true }, @@ -90,7 +90,7 @@ "type": "double", "minValue": 0, "maxValue": 1000, - "unit":"EuroCentPerKiloWattHour", + "unit":"KiloWattHour", "defaultValue": 0, "suggestLogging": true }, @@ -102,67 +102,9 @@ "type": "double", "minValue": 0, "maxValue": 1000, - "unit":"EuroCentPerKiloWattHour", + "unit":"KiloWattHour", "defaultValue": 0, "suggestLogging": true - }, - { - "id": "690d562e-a75d-4da9-940f-e1908544dbae", - "name": "chargingState", - "displayName": "Charging state", - "displayNameEvent": "Charging state changed", - "type": "QString", - "possibleValues": ["idle", "charging", "discharging"], - "defaultValue": "idle" - }, - { - "id": "d5ce4925-49e5-49b6-88d8-6e3889080be2", - "name": "currentPower", - "displayName": "Current power", - "displayNameEvent": "Current power changed", - "type": "double", - "unit": "Watt", - "defaultValue": 0, - "cached": false, - "suggestLogging": true - }, - { - "id": "420d2e55-afeb-4a83-b67a-e3c0a86ecc02", - "name": "capacity", - "displayName": "Capacity", - "displayNameEvent": "Capacity changed", - "type": "double", - "unit": "KiloWattHour", - "defaultValue": 0 - }, - { - "id": "df196e56-f33a-4883-a9b4-345dab2bac95", - "name": "batteryLevel", - "displayName": "Battery level", - "displayNameEvent": "Battery level changed", - "type": "int", - "unit": "Percentage", - "defaultValue": "0", - "minValue": 0, - "maxValue": 100 - }, - { - "id": "6225b633-b159-4794-9e54-84912049fd32", - "name": "cellTemperature", - "displayName": "Cell temperature", - "displayNameEvent": "Cell temperature changed", - "type": "double", - "unit": "DegreeCelsius", - "defaultValue": "0", - "cached": false - }, - { - "id": "20410ff8-b9aa-4b63-a091-c3636278718e", - "name": "batteryCritical", - "displayName": "Battery level critical", - "displayNameEvent": "Battery level critical changed", - "type": "bool", - "defaultValue": false } ] From 9d62caeb1c0aebcb5675b8c428ec763f8fc707f3 Mon Sep 17 00:00:00 2001 From: Devendra Date: Tue, 8 Apr 2025 02:52:03 +0530 Subject: [PATCH 3/4] update review comments: -> update file names -> update variable with camel case -> update debian/control -> remove unused files and API -> remove deprecated property -> update indentation -> update code as per comment -> fix typo --- debian/control | 9 + .../nymea-plugin-v2xeambereletric.install.in | 2 +- nymea-plugins.pro | 1 + v2xeamberelectric/.gitignore | 43 -- v2xeamberelectric/LICENSE.LGPL3 | 165 -------- v2xeamberelectric/README.md | 3 +- v2xeamberelectric/debian/changelog | 5 - v2xeamberelectric/debian/compat | 1 - v2xeamberelectric/debian/control | 26 -- v2xeamberelectric/debian/copyright | 14 - v2xeamberelectric/debian/rules | 29 -- v2xeamberelectric/debian/source/format | 1 - .../integrationpluginv2xe_amber_electric.json | 118 ------ .../integrationpluginv2xeamberelectric.json | 102 +++++ v2xeamberelectric/v2xe_amber_electric.cpp | 399 ------------------ v2xeamberelectric/v2xe_amber_electric.pro | 13 - v2xeamberelectric/v2xeamberelectric.cpp | 297 +++++++++++++ ...e_amber_electric.h => v2xeamberelectric.h} | 31 +- v2xeamberelectric/v2xeamberelectric.pro | 13 + 19 files changed, 433 insertions(+), 839 deletions(-) rename {v2xeamberelectric/debian => debian}/nymea-plugin-v2xeambereletric.install.in (71%) delete mode 100644 v2xeamberelectric/.gitignore delete mode 100644 v2xeamberelectric/LICENSE.LGPL3 delete mode 100644 v2xeamberelectric/debian/changelog delete mode 100644 v2xeamberelectric/debian/compat delete mode 100644 v2xeamberelectric/debian/control delete mode 100644 v2xeamberelectric/debian/copyright delete mode 100644 v2xeamberelectric/debian/rules delete mode 100644 v2xeamberelectric/debian/source/format delete mode 100644 v2xeamberelectric/integrationpluginv2xe_amber_electric.json create mode 100644 v2xeamberelectric/integrationpluginv2xeamberelectric.json delete mode 100644 v2xeamberelectric/v2xe_amber_electric.cpp delete mode 100644 v2xeamberelectric/v2xe_amber_electric.pro create mode 100644 v2xeamberelectric/v2xeamberelectric.cpp rename v2xeamberelectric/{v2xe_amber_electric.h => v2xeamberelectric.h} (70%) create mode 100644 v2xeamberelectric/v2xeamberelectric.pro diff --git a/debian/control b/debian/control index 244651b5..99ef84a8 100644 --- a/debian/control +++ b/debian/control @@ -841,6 +841,15 @@ Description: nymea integration plugin to connect to your Tado account This package contains the nymea integration plugin for Tado devices. +Package: nymea-plugin-v2xeamberelectric +Architecture: any +Depends: ${shlibs:Depends}, + ${misc:Depends}, +Conflicts: nymea-plugins-translations (<< 1.0.1) +Description: This nymea plugin fetches live and forecasted price data, + providing real-time and future pricing information for integration with smart energy management systems. + + Package: nymea-plugin-wheretheissat Architecture: any Depends: ${misc:Depends}, diff --git a/v2xeamberelectric/debian/nymea-plugin-v2xeambereletric.install.in b/debian/nymea-plugin-v2xeambereletric.install.in similarity index 71% rename from v2xeamberelectric/debian/nymea-plugin-v2xeambereletric.install.in rename to debian/nymea-plugin-v2xeambereletric.install.in index d434a6ea..03ccd74f 100644 --- a/v2xeamberelectric/debian/nymea-plugin-v2xeambereletric.install.in +++ b/debian/nymea-plugin-v2xeambereletric.install.in @@ -1 +1 @@ -usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationpluginEV_charger.so +usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationpluginv2xeamberelectric.so diff --git a/nymea-plugins.pro b/nymea-plugins.pro index 32eae9f8..5e12641e 100644 --- a/nymea-plugins.pro +++ b/nymea-plugins.pro @@ -84,6 +84,7 @@ PLUGIN_DIRS = \ unifi \ usbrelay \ usbrly82 \ + v2xeamberelectric \ wakeonlan \ wemo \ ws2812fx \ diff --git a/v2xeamberelectric/.gitignore b/v2xeamberelectric/.gitignore deleted file mode 100644 index 1625ed4e..00000000 --- a/v2xeamberelectric/.gitignore +++ /dev/null @@ -1,43 +0,0 @@ -# C++ objects and libs - -*.slo -*.lo -*.o -*.a -*.la -*.lai -*.so -*.dll -*.dylib - -# Qt-es - -/.qmake.cache -/.qmake.stash -*.pro.user -*.pro.user.* -*.qbs.user -*.qbs.user.* -*.moc -moc_*.cpp -qrc_*.cpp -ui_*.h -Makefile* -*-build-* - -# QtCreator - -*.autosave - -#QtCtreator Qml -*.qmlproject.user -*.qmlproject.user.* - -build-* -html -build -vendor -*.qmlc -*.swp - -.crossbuilder diff --git a/v2xeamberelectric/LICENSE.LGPL3 b/v2xeamberelectric/LICENSE.LGPL3 deleted file mode 100644 index 0a041280..00000000 --- a/v2xeamberelectric/LICENSE.LGPL3 +++ /dev/null @@ -1,165 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/v2xeamberelectric/README.md b/v2xeamberelectric/README.md index 7c08a00d..f94db2f8 100644 --- a/v2xeamberelectric/README.md +++ b/v2xeamberelectric/README.md @@ -3,6 +3,5 @@ Description of the plugin... -plugin for amber electric api to get live data of energy use , - +This Nymea plugin fetches live and forecasted price data, providing real-time and future pricing information for integration with smart energy management systems diff --git a/v2xeamberelectric/debian/changelog b/v2xeamberelectric/debian/changelog deleted file mode 100644 index ad09740e..00000000 --- a/v2xeamberelectric/debian/changelog +++ /dev/null @@ -1,5 +0,0 @@ -nymea-plugin-v2xeamberelectric (0.0.1) bookworm; urgency=medium - - * Initial release. - - -- devendragajjar Mon, 21 Aug 2017 10:12:00 +0000 diff --git a/v2xeamberelectric/debian/compat b/v2xeamberelectric/debian/compat deleted file mode 100644 index b4de3947..00000000 --- a/v2xeamberelectric/debian/compat +++ /dev/null @@ -1 +0,0 @@ -11 diff --git a/v2xeamberelectric/debian/control b/v2xeamberelectric/debian/control deleted file mode 100644 index 41a8107e..00000000 --- a/v2xeamberelectric/debian/control +++ /dev/null @@ -1,26 +0,0 @@ -Source: nymea-plugin-v2xeamberelectric -Section: utils -Priority: optional -Maintainer: devendragajjar -Standards-Version: 4.6.0 -Build-depends: debhelper (>= 9.0.0), - libnymea1-dev, - nymea-dev-tools:native, - qt5-qmake:native, - pkg-config, - - -Package: nymea-plugin-v2xeamberelectric -Architecture: any -Multi-Arch: same -Section: libs -Depends: ${shlibs:Depends}, - ${misc:Depends}, -Description: nymea.io plugin for v2xeamberelectric - 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 v2xeamberelectric diff --git a/v2xeamberelectric/debian/copyright b/v2xeamberelectric/debian/copyright deleted file mode 100644 index 7c431a35..00000000 --- a/v2xeamberelectric/debian/copyright +++ /dev/null @@ -1,14 +0,0 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: ${ProjectName} -Upstream-Contact: devendragajjar -Copyright: 2024, devendragajjar - - -License: LGPL-3 - On Debian systems, the complete text of the GNU Lesser General - Public License can be found in `/usr/share/common-licenses/LGPL-3'. - -Files: * -License: LGPL-3 -Copyright: devendragajjar - diff --git a/v2xeamberelectric/debian/rules b/v2xeamberelectric/debian/rules deleted file mode 100644 index 682dbb99..00000000 --- a/v2xeamberelectric/debian/rules +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/make -f -# -*- makefile -*- - -export DH_VERBOSE=1 -DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) - -PREPROCESS_FILES := $(wildcard debian/*.in) - -$(PREPROCESS_FILES:.in=): %: %.in - sed 's,/@DEB_HOST_MULTIARCH@,$(DEB_HOST_MULTIARCH:%=/%),g' $< > $@ - -override_dh_install: $(PREPROCESS_FILES:.in=) - make -j9 install DESTDIR=debian/tmp AM_UPDATE_INFO_DIR=no INSTALL_ROOT=debian/tmp - dh_install - -override_dh_missing: - dh_missing --list-missing - -override_dh_auto_build: - dh_auto_build - make lrelease - -override_dh_auto_clean: - dh_auto_clean - rm -rf $(PREPROCESS_FILES:.in=) - -%: - dh $@ --parallel - diff --git a/v2xeamberelectric/debian/source/format b/v2xeamberelectric/debian/source/format deleted file mode 100644 index 89ae9db8..00000000 --- a/v2xeamberelectric/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (native) diff --git a/v2xeamberelectric/integrationpluginv2xe_amber_electric.json b/v2xeamberelectric/integrationpluginv2xe_amber_electric.json deleted file mode 100644 index 34c96834..00000000 --- a/v2xeamberelectric/integrationpluginv2xe_amber_electric.json +++ /dev/null @@ -1,118 +0,0 @@ -{ - "name": "Amber_Electric_plgn", - "displayName": "Amber_Electric_plgn", - "id": "0233c848-6f6f-4907-a51c-81391e4f5356", - "vendors": [ - { - "name": "Amber_Electric", - "displayName": "Amber_Electric", - "id": "ec1985b9-5891-435d-9264-e8e18d392978", - "thingClasses": [ - { - "name": "V2Xe_Amber_Electric", - "displayName": "V2Xe_Amber_Electric", - "id": "11295990-7002-432e-b90c-cd4010548a32", - "setupMethod": "JustAdd", - "createMethods": ["User"], - "interfaces": ["v2xeenergymeter", "connectable"], - "paramTypes": [ - { - "id": "fc899f7b-f452-44dc-b72e-ee7bb8034ff0", - "name": "auth_token", - "displayName": "auth_token", - "type" : "QString", - "defaultValue": "" - }, - { - "id": "c50eac84-714e-4b9c-89d5-0b939b6c18d6", - "name": "crnt_site", - "displayName": "current_site", - "type" : "QString", - "defaultValue": "" - } - ], - "stateTypes": [ - { - "id": "faf2a6c0-1897-4b9b-903a-e12b281efe24", - "name": "connected", - "displayName": "Reachable", - "displayNameEvent": "Reachable changed", - "type": "bool", - "defaultValue": false, - "cached": false - }, - { - "id": "42c8a6f8-4f97-4871-8bfb-ac7e6ffffa74", - "name": "Sites", - "displayName": "Sites", - "displayNameEvent": "Sites_list_updated", - "type": "QString", - "writable": false, - "defaultValue": "" - }, - { - "id": "27c3f8e0-0803-4eb8-ba4f-ce78fb0997a9", - "name": "Type", - "displayName": "type", - "displayNameEvent": "type_evnet", - "type": "QString", - "defaultValue": "Amber" - }, - { - "id": "6e8d3fcd-c235-4793-95b5-321ca6e012a3", - "name": "forecastprice", - "displayName": "Feedin Price", - "displayNameEvent": "forecastPrice_changed", - "type": "double", - "minValue": 0, - "maxValue": 1000, - "defaultValue": 0, - "unit": "KiloWattHour", - "suggestLogging": true - }, - { - "id": "a25d3b55-9b93-4465-90e3-5d36adb8fb23", - "name": "currentprice", - "displayName": "Current Price", - "displayNameEvent": "currentPrice_changed", - "type": "double", - "minValue": 0, - "maxValue": 1000, - "unit":"KiloWattHour", - "defaultValue": 0, - "suggestLogging": true - }, - { - "id": "cd1e22b2-2154-453a-bbdf-59156893258a", - "name": "currentfeedin", - "displayName": "Current Feedin", - "displayNameEvent": "currentfeedinPrice changed", - "type": "double", - "minValue": 0, - "maxValue": 1000, - "unit":"KiloWattHour", - "defaultValue": 0, - "suggestLogging": true - }, - { - "id": "52188fdf-4a4d-4ca8-b02e-cea5ed8c1615", - "name": "futurefeedin", - "displayName": "Future Feedin", - "displayNameEvent": "futurefeedinPrice changed", - "type": "double", - "minValue": 0, - "maxValue": 1000, - "unit":"KiloWattHour", - "defaultValue": 0, - "suggestLogging": true - } - - ] - } - ] - } - ] -} - - - diff --git a/v2xeamberelectric/integrationpluginv2xeamberelectric.json b/v2xeamberelectric/integrationpluginv2xeamberelectric.json new file mode 100644 index 00000000..f7bcfa44 --- /dev/null +++ b/v2xeamberelectric/integrationpluginv2xeamberelectric.json @@ -0,0 +1,102 @@ +{ + "name": "AmberElectric", + "displayName": "Amber Electric", + "id": "0233c848-6f6f-4907-a51c-81391e4f5356", + "vendors": [ + { + "name": "AmberElectric", + "displayName": "Amber Electric", + "id": "ec1985b9-5891-435d-9264-e8e18d392978", + "thingClasses": [ + { + "name": "V2XeAmberElectric", + "displayName": "Amber Electric - V2Xe Amber Electric", + "id": "11295990-7002-432e-b90c-cd4010548a32", + "setupMethod": "JustAdd", + "createMethods": ["User"], + "interfaces": ["smartmeter", "connectable"], + "paramTypes": [ + { + "id": "fc899f7b-f452-44dc-b72e-ee7bb8034ff0", + "name": "authToken", + "displayName": "auth token", + "type" : "QString", + "defaultValue": "" + }, + { + "id": "c50eac84-714e-4b9c-89d5-0b939b6c18d6", + "name": "currentSite", + "displayName": "current site", + "type" : "QString", + "defaultValue": "" + } + ], + "stateTypes": [ + { + "id": "faf2a6c0-1897-4b9b-903a-e12b281efe24", + "name": "connected", + "displayName": "Reachable", + "type": "bool", + "defaultValue": false, + "cached": false + }, + { + "id": "42c8a6f8-4f97-4871-8bfb-ac7e6ffffa74", + "name": "Sites", + "displayName": "Sites", + "type": "QString", + "writable": false, + "defaultValue": "" + }, + { + "id": "27c3f8e0-0803-4eb8-ba4f-ce78fb0997a9", + "name": "Type", + "displayName": "type", + "type": "QString", + "defaultValue": "Amber" + }, + { + "id": "6e8d3fcd-c235-4793-95b5-321ca6e012a3", + "name": "forecastprice", + "displayName": "Feedin Price", + "type": "double", + "defaultValue": 0, + "unit": "KiloWattHour", + "suggestLogging": true + }, + { + "id": "a25d3b55-9b93-4465-90e3-5d36adb8fb23", + "name": "currentprice", + "displayName": "Current Price", + "type": "double", + "unit":"KiloWattHour", + "defaultValue": 0, + "suggestLogging": true + }, + { + "id": "cd1e22b2-2154-453a-bbdf-59156893258a", + "name": "currentfeedin", + "displayName": "Current Feedin", + "type": "double", + "unit":"KiloWattHour", + "defaultValue": 0, + "suggestLogging": true + }, + { + "id": "52188fdf-4a4d-4ca8-b02e-cea5ed8c1615", + "name": "futurefeedin", + "displayName": "Future Feedin", + "type": "double", + "unit":"KiloWattHour", + "defaultValue": 0, + "suggestLogging": true + } + ] + } + ] + } + ] +} + + + diff --git a/v2xeamberelectric/v2xe_amber_electric.cpp b/v2xeamberelectric/v2xe_amber_electric.cpp deleted file mode 100644 index 060dfa4d..00000000 --- a/v2xeamberelectric/v2xe_amber_electric.cpp +++ /dev/null @@ -1,399 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2024 devendragajjar * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; * - * version 3 of the License. * - * * - * This library 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 library; If not, see * - * . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#include "v2xe_amber_electric.h" -#include "plugininfo.h" -#include "hardwaremanager.h" -#include "network/networkaccessmanager.h" - -#include -#include -#include -#include -#include -#include - - - - -const QString const_site = "01J1XBQFGX57137EH0C6AG040D"; -const QString no_of_data_need = "5"; -const QString site_http_link = "https://api.amber.com.au/v1/sites"; -const QString price_http_link_front = "https://api.amber.com.au/v1/sites/"; -const QString price_http_link_back = "/prices/current?next="+ no_of_data_need +"&previous=" + no_of_data_need; - //01J1XBQFGX57137EH0C6AG040D/prices/current?next=5&previous=5"; -const QString auth_token = "f5b2c823de5fed2f4c6bdb7c1b0db4f5"; -const QString renewble_http_link = "https://api.amber.com.au/v1/state/vic/renewables/current?next=48&previous=5&resolution=5"; - - -v2xe_amber_electric::v2xe_amber_electric() -{ - m_connectedStateTypeIds[V2Xe_Amber_ElectricThingClassId] = V2Xe_Amber_ElectricConnectedStateTypeId; - m_forecastPriceStateTypeIds[V2Xe_Amber_ElectricThingClassId] = V2Xe_Amber_ElectricForecastpriceStateTypeId; - m_currentPriceStateTypeIds[V2Xe_Amber_ElectricThingClassId] = V2Xe_Amber_ElectricCurrentpriceStateTypeId; - m_currentSiteTypeIds[V2Xe_Amber_ElectricThingClassId] = V2Xe_Amber_ElectricSitesStateTypeId; - m_currentfeddinStateTypeIds[V2Xe_Amber_ElectricThingClassId] = V2Xe_Amber_ElectricCurrentfeedinStateTypeId; - m_fururefeedinStateTypeIds[V2Xe_Amber_ElectricThingClassId] = V2Xe_Amber_ElectricFuturefeedinStateTypeId; - m_consumerKey = auth_token; -} - -v2xe_amber_electric::~v2xe_amber_electric() -{ - -} - -void v2xe_amber_electric::init() -{ - // Initialisation can be done here. - qCDebug(dcAmber_Electric_plgn()) << "Plugin initialized."; -} - - - -void v2xe_amber_electric::setupThing(ThingSetupInfo *info) -{ - // A thing is being set up. Use info->thing() to get details of the thing, do - // the required setup (e.g. connect to the device) and call info->finish() when done. - - qCDebug(dcAmber_Electric_plgn()) << "Setup thing" << info->thing()->name() << info->thing()->params(); - QString key = info->thing()->paramValue(V2Xe_Amber_ElectricThingAuth_tokenParamTypeId).toString(); - if (!key.isEmpty()) { - m_consumerKey = key; - qCCritical(dcAmber_Electric_plgn()) << "m_consumerKey set " << m_consumerKey << "key " << key; - } - - QString site = info->thing()->paramValue(V2Xe_Amber_ElectricThingCrnt_siteParamTypeId).toString(); - if (!site.isEmpty()) { - m_current_site = site; - qCCritical(dcAmber_Electric_plgn()) << "m_current_site set " << m_current_site ; - } - else{ - m_current_site = const_site; - } - - // use defult key for now - qCCritical(dcAmber_Electric_plgn()) << "No API key set."; - qCCritical(dcAmber_Electric_plgn()) << "Either install an API key pacakge (nymea-apikeysprovider-plugin-*) or provide a key in the plugin settings."; - - if (!m_pluginTimer) { - m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(60);//TODO make 30 minutes after test - connect(m_pluginTimer, &PluginTimer::timeout, this, &v2xe_amber_electric::onPluginTimer); - } - info->finish(Thing::ThingErrorNoError); -} - -void v2xe_amber_electric::onPluginTimer() -{ - foreach (Thing *thing, myThings()) { - - //requestPriceData(thing); // TODO -#if ENABLE_RENEWEBLE_API - requestRenewablesData(thing); //TODO -#endif - requestSiteData(thing); - requestSitePriceData(thing); - - } -} - -void v2xe_amber_electric::executeAction(ThingActionInfo *info) -{ - // An action is being executed. Use info->action() to get details about the action, - // do the required operations (e.g. send a command to the network) and call info->finish() when done. - - qCDebug(dcAmber_Electric_plgn()) << "Executing action for thing" << info->thing() << info->action().actionTypeId().toString() << info->action().params(); - - info->finish(Thing::ThingErrorNoError); -} - -void v2xe_amber_electric::thingRemoved(Thing *thing) -{ - // A thing is being removed from the system. Do the required cleanup - // (e.g. disconnect from the device) here. - - qCDebug(dcAmber_Electric_plgn()) << "Remove thing" << thing; -} - -void v2xe_amber_electric::requestSitePriceData(Thing* thing, ThingSetupInfo* setup) { - - QString price_http_link = price_http_link_front + m_current_site + price_http_link_back; - - m_serverUrls[V2Xe_Amber_ElectricThingClassId] = price_http_link; - - QNetworkRequest request; - request.setUrl(QUrl(m_serverUrls[V2Xe_Amber_ElectricThingClassId])); - - // Add the Authorization header with the token - QString token = thing->paramValue(m_consumerKey).toString(); - token = m_consumerKey; - qCCritical(dcAmber_Electric_plgn) << " using m_consumerKey " <networkManager()->get(request); - connect(reply, &QNetworkReply::finished, this, [this, thing, setup, reply]() { - reply->deleteLater(); - - int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - if (status != 200) { - qCWarning(dcAmber_Electric_plgn) << "Update reply HTTP error:" << status << reply->errorString(); - if (setup) { - setup->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Error getting data from server.")); - } else { - //thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), false);//TODO remove comment - } - return; - } - onSitePriceDataReceived(thing, setup, reply); - }); -} - -void v2xe_amber_electric::onSitePriceDataReceived(Thing* thing, ThingSetupInfo* setup, QNetworkReply* reply) { - if (reply->error() != QNetworkReply::NoError) { - qCWarning(dcAmber_Electric_plgn) << "Network error:" << reply->errorString(); - if (setup) { - setup->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Network error.")); - } - return; - } - - QJsonParseError error; - QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll(), &error); - if (error.error != QJsonParseError::NoError) { - qCWarning(dcAmber_Electric_plgn) << "JSON parse error:" << error.errorString(); - if (setup) { - setup->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("JSON parse error.")); - } - return; - } - - if (jsonDoc.isArray()) { - QString channelType; - QJsonArray jsonArray = jsonDoc.array(); - for (const QJsonValue &value : jsonArray) { - if (value.isObject()) { - QJsonObject jsonObject = value.toObject(); - QString type = jsonObject["type"].toString(); //Get type - channelType = jsonObject["channelType"].toString(); - - //Current Price - if((type == "CurrentInterval") && channelType == "general"){ - - if (jsonObject.contains("perKwh") && jsonObject["perKwh"].isDouble()) { // Get perKwh - - double perkwh = jsonObject["perKwh"].toDouble(); - - thing->setStateValue(m_currentPriceStateTypeIds.value(thing->thingClassId()), qAbs(perkwh)); - } - } - - //Future Price - if((type == "ForecastInterval") && channelType == "general"){ - - if (jsonObject.contains("perKwh") && jsonObject["perKwh"].isDouble()) { // Get perKwh - - double perkwh = jsonObject["perKwh"].toDouble(); - - thing->setStateValue(m_forecastPriceStateTypeIds.value(thing->thingClassId()), qAbs(perkwh)); - } - } - - - // Current Feedin //TODO what is feed in price its dummy data - if((type == "CurrentInterval") && (channelType == "feedIn")){ - - if (jsonObject.contains("perKwh") && jsonObject["perKwh"].isDouble()) { // Get SportPerKwh - double spotperkwh = jsonObject["perKwh"].toDouble(); - - thing->setStateValue(m_currentfeddinStateTypeIds.value(thing->thingClassId()), qAbs(spotperkwh)); - } - } - - //Future Feedin - if((type == "ForecastInterval") && (channelType == "feedIn")){ - - if (jsonObject.contains("perKwh") && jsonObject["perKwh"].isDouble()) { // Get SportPerKwh - double spotperkwh = jsonObject["perKwh"].toDouble(); - - thing->setStateValue(m_fururefeedinStateTypeIds.value(thing->thingClassId()), qAbs(spotperkwh)); - } - } - - } - } - } - - if (setup) { - setup->finish(Thing::ThingErrorNoError); - } - thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), true); -} - - -void v2xe_amber_electric::requestSiteData(Thing* thing, ThingSetupInfo* setup) { - - m_serverUrls[V2Xe_Amber_ElectricThingClassId] = site_http_link; - - - QNetworkRequest request; - request.setUrl(QUrl(m_serverUrls[V2Xe_Amber_ElectricThingClassId])); - - // Add the Authorization header with the token - QString token = thing->paramValue(m_consumerKey).toString(); - token = m_consumerKey; - qCCritical(dcAmber_Electric_plgn) << " using m_consumerKey " <networkManager()->get(request); - connect(reply, &QNetworkReply::finished, this, [this, thing, setup, reply]() { - reply->deleteLater(); - - int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - if (status != 200) { - qCWarning(dcAmber_Electric_plgn) << "Update reply HTTP error:" << status << reply->errorString(); - if (setup) { - setup->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Error getting data from server.")); - } else { - thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), false); - } - return; - } - - onSiteDataReceived(thing, setup, reply); - }); -} - -void v2xe_amber_electric::onSiteDataReceived(Thing* thing, ThingSetupInfo* setup, QNetworkReply* reply) { - if (reply->error() != QNetworkReply::NoError) { - qCWarning(dcAmber_Electric_plgn) << "Network error:" << reply->errorString(); - if (setup) { - setup->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Network error.")); - } - return; - } - QVariantList stringList = {}; - QString l_site; - QJsonParseError error; - QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll(), &error); - if (error.error != QJsonParseError::NoError) { - qCWarning(dcAmber_Electric_plgn) << "JSON parse error:" << error.errorString(); - if (setup) { - setup->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("JSON parse error.")); - } - return; - } - qCCritical(dcAmber_Electric_plgn) << "onSiteDataReceived " ; - if (jsonDoc.isArray()) { - QJsonArray jsonArray = jsonDoc.array(); - for (const QJsonValue &value : jsonArray) { - if (value.isObject()) { - QJsonObject jsonObject = value.toObject(); - QString type = jsonObject["id"].toString(); //Get type - - if(!type.isEmpty()){ //update - stringList.append(type); - qCCritical(dcAmber_Electric_plgn) << "type :" << type; - l_site = type; - } - } - } - } - thing->setStateValue(m_currentSiteTypeIds.value(thing->thingClassId()), l_site); - if (setup) { - setup->finish(Thing::ThingErrorNoError); - } - thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), true); -} - - - -#if ENABLE_RENEWEBLE_API -void v2xe_amber_electric::requestRenewablesData(Thing* thing, ThingSetupInfo* setup) { - - m_serverUrls[V2Xe_Amber_ElectricThingClassId] = renewble_http_link; - - QNetworkRequest request; - request.setUrl(QUrl(m_serverUrls[V2Xe_Amber_ElectricThingClassId])); - - // Add the Authorization header with the token - QString token = thing->paramValue(m_consumerKey).toString(); - request.setRawHeader("Authorization", QString("Bearer %1").arg(token).toUtf8()); - request.setRawHeader("accept", "application/json"); - - QNetworkReply* reply = hardwareManager()->networkManager()->get(request); - connect(reply, &QNetworkReply::finished, this, [this, thing, setup, reply]() { - reply->deleteLater(); - - int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - if (status != 200) { - qCWarning(dcAmber_Electric_plgn) << "Update reply HTTP error:" << status << reply->errorString(); - if (setup) { - setup->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Error getting data from server.")); - } else { - //thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), false);//TODO remove comment - } - return; - } - onRenewablesDataReceived(thing, setup, reply); - }); -} - - -void v2xe_amber_electric::onRenewablesDataReceived(Thing* thing, ThingSetupInfo* setup, QNetworkReply* reply) { - - if (reply->error() != QNetworkReply::NoError) { - qCWarning(dcAmber_Electric_plgn) << "Network error:" << reply->errorString(); - if (setup) { - setup->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Network error.")); - } - return; - } - - QJsonParseError error; - QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll(), &error); - if (error.error != QJsonParseError::NoError) { - qCWarning(dcAmber_Electric_plgn) << "JSON parse error:" << error.errorString(); - if (setup) { - setup->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("JSON parse error.")); - } - return; - } - - if (jsonDoc.isArray()) { - QJsonArray jsonArray = jsonDoc.array(); - for (const QJsonValue &value : jsonArray) { - if (value.isObject()) { - QJsonObject jsonObject = value.toObject(); - QString type = jsonObject["type"].toString(); - if (type == "ActualRenewable") { - //double renewables = jsonObject["renewables"].toDouble(); - } - } - } - } - - if (setup) { - setup->finish(Thing::ThingErrorNoError); - } - thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), true); -} - -#endif diff --git a/v2xeamberelectric/v2xe_amber_electric.pro b/v2xeamberelectric/v2xe_amber_electric.pro deleted file mode 100644 index 5c58270e..00000000 --- a/v2xeamberelectric/v2xe_amber_electric.pro +++ /dev/null @@ -1,13 +0,0 @@ -include($$[QT_INSTALL_PREFIX]/include/nymea/plugin.pri) - -QT += network - -SOURCES += \ - v2xe_amber_electric.cpp - -HEADERS += \ - v2xe_amber_electric.h - -DISTFILES += \ - integrationpluginv2xe_amber_electric.json - diff --git a/v2xeamberelectric/v2xeamberelectric.cpp b/v2xeamberelectric/v2xeamberelectric.cpp new file mode 100644 index 00000000..036773eb --- /dev/null +++ b/v2xeamberelectric/v2xeamberelectric.cpp @@ -0,0 +1,297 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2025 devendragajjar * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; * + * version 3 of the License. * + * * + * This library 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 library; If not, see * + * . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "v2xeamberelectric.h" +#include "plugininfo.h" +#include "hardwaremanager.h" +#include "network/networkaccessmanager.h" + +#include +#include +#include +#include +#include +#include + + + + +const QString constSite = "01J1XBQFGX57137EH0C6AG040D"; +const QString noOfDataNeed = "5"; +const QString siteHttpLink = "https://api.amber.com.au/v1/sites"; +const QString priceHttpLinkFront = "https://api.amber.com.au/v1/sites/"; +const QString priceHttpLinkBack = "/prices/current?next="+ noOfDataNeed +"&previous=" + noOfDataNeed; +const QString authToken = "f5b2c823de5fed2f4c6bdb7c1b0db4f5"; + + +V2xeAmberElectric::V2xeAmberElectric() +{ + mConsumerKey = authToken; +} + +V2xeAmberElectric::~V2xeAmberElectric() +{ + +} + +void V2xeAmberElectric::init() +{ + // Initialisation can be done here. + qCDebug(dcAmberElectric()) << "Plugin initialized."; +} + + + +void V2xeAmberElectric::setupThing(ThingSetupInfo *info) +{ + // A thing is being set up. Use info->thing() to get details of the thing, do + // the required setup (e.g. connect to the device) and call info->finish() when done. + + qCDebug(dcAmberElectric()) << "Setup thing" << info->thing()->name() << info->thing()->params(); + QString key = info->thing()->paramValue(V2XeAmberElectricThingAuthTokenParamTypeId).toString(); + if (!key.isEmpty()) { + mConsumerKey = key; + qCDebug(dcAmberElectric()) << "mConsumerKey set " << mConsumerKey << "key " << key; + } + + QString site = info->thing()->paramValue(V2XeAmberElectricThingCurrentSiteParamTypeId).toString(); + if (!site.isEmpty()) { + mCurrentSite = site; + qCDebug(dcAmberElectric()) << "mCurrentSite set " << mCurrentSite ; + } + else{ + mCurrentSite = constSite; + } + + // use default key for now + qCDebug(dcAmberElectric()) << "No API key set."; + qCDebug(dcAmberElectric()) << "Either install an API key pacakge (nymea-apikeysprovider-plugin-*) or provide a key in the plugin settings."; + + if (!mPluginTimer) { + mPluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(30);//TODO make 30 minutes after test + connect(mPluginTimer, &PluginTimer::timeout, this, &V2xeAmberElectric::onPluginTimer); + } + info->finish(Thing::ThingErrorNoError); +} + +void V2xeAmberElectric::onPluginTimer() +{ + foreach (Thing *thing, myThings()) { + + requestSiteData(thing); + requestSitePriceData(thing); + + } +} + +void V2xeAmberElectric::executeAction(ThingActionInfo *info) +{ + // An action is being executed. Use info->action() to get details about the action, + // do the required operations (e.g. send a command to the network) and call info->finish() when done. + + qCDebug(dcAmberElectric()) << "Executing action for thing" << info->thing() << info->action().actionTypeId().toString() << info->action().params(); + + info->finish(Thing::ThingErrorNoError); +} + +void V2xeAmberElectric::thingRemoved(Thing *thing) +{ + // A thing is being removed from the system. Do the required cleanup + // (e.g. disconnect from the device) here. + + qCDebug(dcAmberElectric()) << "Remove thing" << thing; +} + +void V2xeAmberElectric::requestSitePriceData(Thing* thing, ThingSetupInfo* setup) { + + QString price_http_link = priceHttpLinkFront + mCurrentSite + priceHttpLinkBack; + + mServerUrls[V2XeAmberElectricThingClassId] = price_http_link; + + QNetworkRequest request; + request.setUrl(QUrl(mServerUrls[V2XeAmberElectricThingClassId])); + + // Add the Authorization header with the token + QString token = thing->paramValue(mConsumerKey).toString(); + token = mConsumerKey; + qCDebug(dcAmberElectric) << " using mConsumerKey " <networkManager()->get(request); + connect(reply, &QNetworkReply::finished, this, [this, thing, setup, reply]() { + reply->deleteLater(); + + int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + if (status != 200) { + qCWarning(dcAmberElectric) << "Update reply HTTP error:" << status << reply->errorString(); + if (setup) { + setup->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Error getting data from server.")); + } else { + thing->setStateValue(V2XeAmberElectricConnectedStateTypeId, false); + } + return; + } + onSitePriceDataReceived(thing, setup, reply); + }); +} + +void V2xeAmberElectric::onSitePriceDataReceived(Thing* thing, ThingSetupInfo* setup, QNetworkReply* reply) { + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcAmberElectric) << "Network error:" << reply->errorString(); + if (setup) { + setup->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Network error.")); + } + return; + } + + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll(), &error); + if (error.error != QJsonParseError::NoError) { + qCWarning(dcAmberElectric) << "JSON parse error:" << error.errorString(); + if (setup) { + setup->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("JSON parse error.")); + } + return; + } + + if (jsonDoc.isArray()) { + QString channelType; + QJsonArray jsonArray = jsonDoc.array(); + for (const QJsonValue &value : jsonArray) { + if (value.isObject()) { + QJsonObject jsonObject = value.toObject(); + QString type = jsonObject["type"].toString(); //Get type + channelType = jsonObject["channelType"].toString(); + //Current Price + if((type == "CurrentInterval") && channelType == "general"){ + if (jsonObject.contains("perKwh") && jsonObject["perKwh"].isDouble()) { // Get perKwh + double perkwh = jsonObject["perKwh"].toDouble(); + thing->setStateValue(V2XeAmberElectricCurrentpriceStateTypeId, qAbs(perkwh)); + } + } + //Future Price + if((type == "ForecastInterval") && channelType == "general"){ + if (jsonObject.contains("perKwh") && jsonObject["perKwh"].isDouble()) { // Get perKwh + double perkwh = jsonObject["perKwh"].toDouble(); + thing->setStateValue(V2XeAmberElectricForecastpriceStateTypeId, qAbs(perkwh)); + } + } + // Current Feedin //TODO what is feed in price its dummy data + if((type == "CurrentInterval") && (channelType == "feedIn")){ + if (jsonObject.contains("perKwh") && jsonObject["perKwh"].isDouble()) { // Get SportPerKwh + double spotperkwh = jsonObject["perKwh"].toDouble(); + thing->setStateValue(V2XeAmberElectricCurrentfeedinStateTypeId, qAbs(spotperkwh)); + } + } + //Future Feedin + if((type == "ForecastInterval") && (channelType == "feedIn")){ + if (jsonObject.contains("perKwh") && jsonObject["perKwh"].isDouble()) { // Get SportPerKwh + double spotperkwh = jsonObject["perKwh"].toDouble(); + thing->setStateValue(V2XeAmberElectricFuturefeedinStateTypeId, qAbs(spotperkwh)); + } + } + } + } + } + + if (setup) { + setup->finish(Thing::ThingErrorNoError); + } + thing->setStateValue(V2XeAmberElectricConnectedStateTypeId, true); +} + + +void V2xeAmberElectric::requestSiteData(Thing* thing, ThingSetupInfo* setup) { + + mServerUrls[V2XeAmberElectricThingClassId] = siteHttpLink; + + + QNetworkRequest request; + request.setUrl(QUrl(mServerUrls[V2XeAmberElectricThingClassId])); + + // Add the Authorization header with the token + QString token = thing->paramValue(mConsumerKey).toString(); + token = mConsumerKey; + qCDebug(dcAmberElectric) << " using mConsumerKey " <networkManager()->get(request); + connect(reply, &QNetworkReply::finished, this, [this, thing, setup, reply]() { + reply->deleteLater(); + + int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + if (status != 200) { + qCWarning(dcAmberElectric) << "Update reply HTTP error:" << status << reply->errorString(); + if (setup) { + setup->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Error getting data from server.")); + } else { + thing->setStateValue(V2XeAmberElectricConnectedStateTypeId, false); + } + return; + } + + onSiteDataReceived(thing, setup, reply); + }); +} + +void V2xeAmberElectric::onSiteDataReceived(Thing* thing, ThingSetupInfo* setup, QNetworkReply* reply) { + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcAmberElectric) << "Network error:" << reply->errorString(); + if (setup) { + setup->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Network error.")); + } + return; + } + QVariantList stringList = {}; + QString l_site; + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll(), &error); + if (error.error != QJsonParseError::NoError) { + qCWarning(dcAmberElectric) << "JSON parse error:" << error.errorString(); + if (setup) { + setup->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("JSON parse error.")); + } + return; + } + qCDebug(dcAmberElectric) << "onSiteDataReceived " ; + if (jsonDoc.isArray()) { + QJsonArray jsonArray = jsonDoc.array(); + for (const QJsonValue &value : jsonArray) { + if (value.isObject()) { + QJsonObject jsonObject = value.toObject(); + QString type = jsonObject["id"].toString(); //Get type + + if(!type.isEmpty()){ //update + stringList.append(type); + qCDebug(dcAmberElectric) << "type :" << type; + l_site = type; + } + } + } + } + thing->setStateValue(V2XeAmberElectricSitesStateTypeId, l_site); + if (setup) { + setup->finish(Thing::ThingErrorNoError); + } + thing->setStateValue(V2XeAmberElectricConnectedStateTypeId, true); +} + diff --git a/v2xeamberelectric/v2xe_amber_electric.h b/v2xeamberelectric/v2xeamberelectric.h similarity index 70% rename from v2xeamberelectric/v2xe_amber_electric.h rename to v2xeamberelectric/v2xeamberelectric.h index 6f267fae..6774899c 100644 --- a/v2xeamberelectric/v2xe_amber_electric.h +++ b/v2xeamberelectric/v2xeamberelectric.h @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright (C) 2020 devendragajjar * + * Copyright (C) 2025 devendragajjar * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * @@ -32,19 +32,18 @@ #include #include -#define ENABLE_RENEWEBLE_API 0 -class v2xe_amber_electric: public IntegrationPlugin +class V2xeAmberElectric: public IntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationpluginv2xe_amber_electric.json") + Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationpluginv2xeamberelectric.json") Q_INTERFACES(IntegrationPlugin) public: - explicit v2xe_amber_electric(); - ~v2xe_amber_electric(); + explicit V2xeAmberElectric(); + ~V2xeAmberElectric(); void init() override; @@ -58,27 +57,15 @@ private slots: void onPluginTimer(); void requestSitePriceData(Thing* thing, ThingSetupInfo* setup = nullptr); void requestSiteData(Thing* thing, ThingSetupInfo* setup = nullptr); -#if ENABLE_RENEWEBLE_API - void requestRenewablesData(Thing* thing, ThingSetupInfo* setup = nullptr); -#endif private: - PluginTimer *m_pluginTimer = nullptr; - QString m_consumerKey; - QString m_current_site; - QHash m_serverUrls; - QHash m_connectedStateTypeIds; - QHash m_forecastPriceStateTypeIds; - QHash m_currentPriceStateTypeIds; - QHash m_currentSiteTypeIds; - QHash m_currentfeddinStateTypeIds; - QHash m_fururefeedinStateTypeIds; + PluginTimer *mPluginTimer = nullptr; + QString mConsumerKey; + QString mCurrentSite; + QHash mServerUrls; void onSiteDataReceived(Thing* thing, ThingSetupInfo* setup = nullptr, QNetworkReply* reply = nullptr); void onSitePriceDataReceived(Thing* thing, ThingSetupInfo* setup = nullptr, QNetworkReply* reply = nullptr); -#if ENABLE_RENEWEBLE_API - void onRenewablesDataReceived(Thing* thing, ThingSetupInfo* setup = nullptr, QNetworkReply* reply = nullptr); -#endif }; #endif // INTEGRATIONPLUGINEV_CHARGER_H diff --git a/v2xeamberelectric/v2xeamberelectric.pro b/v2xeamberelectric/v2xeamberelectric.pro new file mode 100644 index 00000000..fde101af --- /dev/null +++ b/v2xeamberelectric/v2xeamberelectric.pro @@ -0,0 +1,13 @@ +include(../plugins.pri) + +QT += network + +SOURCES += \ + v2xeamberelectric.cpp + +HEADERS += \ + v2xeamberelectric.h + +DISTFILES += \ + integrationpluginv2xeamberelectric.json + From c6b992eb5923e834d136966d895ec838f66d4de2 Mon Sep 17 00:00:00 2001 From: devendragajjar Date: Tue, 8 Apr 2025 04:15:22 +0530 Subject: [PATCH 4/4] Update v2xeamberelectric.cpp update timer time to 30 minutes 1800 seconds --- v2xeamberelectric/v2xeamberelectric.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v2xeamberelectric/v2xeamberelectric.cpp b/v2xeamberelectric/v2xeamberelectric.cpp index 036773eb..d7911c7b 100644 --- a/v2xeamberelectric/v2xeamberelectric.cpp +++ b/v2xeamberelectric/v2xeamberelectric.cpp @@ -85,7 +85,7 @@ void V2xeAmberElectric::setupThing(ThingSetupInfo *info) qCDebug(dcAmberElectric()) << "Either install an API key pacakge (nymea-apikeysprovider-plugin-*) or provide a key in the plugin settings."; if (!mPluginTimer) { - mPluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(30);//TODO make 30 minutes after test + mPluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(1800);//TODO make 30 minutes after test for connect(mPluginTimer, &PluginTimer::timeout, this, &V2xeAmberElectric::onPluginTimer); } info->finish(Thing::ThingErrorNoError);