From 952c87a0d9d785bc84caa7cd60a72346239bec54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 21 Nov 2024 16:41:07 +0100 Subject: [PATCH 1/2] EVerest: Autosetup connectors on localhost MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Simon Stürz --- everest/everestdiscovery.cpp | 20 +++++++++ everest/everestdiscovery.h | 4 ++ everest/integrationplugineverest.cpp | 61 +++++++++++++++++++++++++++- 3 files changed, 84 insertions(+), 1 deletion(-) diff --git a/everest/everestdiscovery.cpp b/everest/everestdiscovery.cpp index d258daff..fadc3534 100644 --- a/everest/everestdiscovery.cpp +++ b/everest/everestdiscovery.cpp @@ -69,6 +69,18 @@ void EverestDiscovery::start() checkNetworkDevice(localHostInfo); } +void EverestDiscovery::startLocalhost() +{ + qCInfo(dcEverest()) << "Discovery: Start discovering EVerest on localhost ..."; + m_startDateTime = QDateTime::currentDateTime(); + m_localhostDiscovery = true; + + // For development, check local host + NetworkDeviceInfo localHostInfo; + localHostInfo.setAddress(QHostAddress::LocalHost); + checkNetworkDevice(localHostInfo); +} + QList EverestDiscovery::results() const { return m_results; @@ -88,6 +100,10 @@ void EverestDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDevice << "...skip connection"; // We give up on the first error here cleanupClient(client); + + if (m_localhostDiscovery) { + finishDiscovery(); + } }); connect(client, &MqttClient::disconnected, this, [this, client](){ @@ -156,6 +172,10 @@ void EverestDiscovery::cleanupClient(MqttClient *client) client->disconnectFromHost(); client->deleteLater(); + + if (m_localhostDiscovery) { + finishDiscovery(); + } } void EverestDiscovery::finishDiscovery() diff --git a/everest/everestdiscovery.h b/everest/everestdiscovery.h index 8181e8aa..7a64d552 100644 --- a/everest/everestdiscovery.h +++ b/everest/everestdiscovery.h @@ -50,6 +50,8 @@ public: void start(); + void startLocalhost(); + QList results() const; signals: @@ -61,6 +63,8 @@ private: QList m_results; QList m_clients; + bool m_localhostDiscovery = false; + QString m_everestApiModuleTopicConnectors = "everest_api/connectors"; void checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo); diff --git a/everest/integrationplugineverest.cpp b/everest/integrationplugineverest.cpp index cea8fa7b..a4f7e394 100644 --- a/everest/integrationplugineverest.cpp +++ b/everest/integrationplugineverest.cpp @@ -46,7 +46,66 @@ void IntegrationPluginTruffle::init() void IntegrationPluginTruffle::startMonitoringAutoThings() { - // TODO: auto setup everest instance running on localhost + // Check on localhost if there is any EVerest instance running and if we have to set up a thing for this EV charger + // Since this integration plugin is most luikly running on an EV charger running EVerest, the local instance should + // be set up automatically. Additional instances in the network can still be added by running a normal network discovery + + EverestDiscovery *discovery = new EverestDiscovery(nullptr, this); + connect(discovery, &EverestDiscovery::finished, discovery, &EverestDiscovery::deleteLater); + connect(discovery, &EverestDiscovery::finished, this, [this, discovery](){ + + ThingDescriptors descriptors; + + foreach (const EverestDiscovery::Result &result, discovery->results()) { + + // Create one EV charger foreach available connector on that host + foreach(const QString &connectorName, result.connectors) { + + QString title = QString("EVerest"); + QString description = connectorName; + ThingDescriptor descriptor(everestThingClassId, title, description); + + qCInfo(dcEverest()) << "Discovered -->" << title << description; + + ParamList params; + params.append(Param(everestThingConnectorParamTypeId, connectorName)); + params.append(Param(everestThingAddressParamTypeId, result.networkDeviceInfo.address().toString())); + descriptor.setParams(params); + + // Let's check if we aleardy have a thing with those params + bool thingExists = true; + Thing *existingThing = nullptr; + foreach (Thing *thing, myThings()) { + foreach(const Param ¶m, params) { + if (param.value() != thing->paramValue(param.paramTypeId())) { + thingExists = false; + break; + } + } + + // The params are equal, we already have set up this thing + if (thingExists) { + existingThing = thing; + } + } + + // Add only connectors we don't have set up yet + if (existingThing) { + qCDebug(dcEverest()) << "Discovered EVerest connector on localhost but we already set up this connector" << existingThing->name() << existingThing->params(); + } else { + qCDebug(dcEverest()) << "Adding new EVerest connector on localhost" << title << params; + descriptors.append(descriptor); + } + } + } + + if (!descriptors.isEmpty()) { + qCDebug(dcEverest()) << "Adding" << descriptors.count() << "new EVerest instances."; + emit autoThingsAppeared(descriptors); + } + }); + + discovery->startLocalhost(); } void IntegrationPluginTruffle::discoverThings(ThingDiscoveryInfo *info) From 3995238fd559fa1507e3a5a2a3cdfed2bd246173 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 25 Nov 2024 14:25:11 +0100 Subject: [PATCH 2/2] EVerest: Fix shutdown crash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Simon Stürz --- everest/everest.cpp | 15 +++++++++++---- everest/everest.h | 2 ++ everest/everestclient.cpp | 10 +++++++++- everest/everestclient.h | 1 + 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/everest/everest.cpp b/everest/everest.cpp index 10705282..e4676cc1 100644 --- a/everest/everest.cpp +++ b/everest/everest.cpp @@ -77,6 +77,11 @@ Everest::~Everest() deinitialize(); } +Thing *Everest::thing() const +{ + return m_thing; +} + QString Everest::connector() const { return m_connector; @@ -192,11 +197,13 @@ void Everest::onPublishReceived(const QString &topic, const QByteArray &payload, */ QVariantMap dataMap = jsonDoc.toVariant().toMap(); + uint maxCurrent = dataMap.value("max_current_A_import").toUInt(); + uint minCurrent = dataMap.value("min_current_A_import").toUInt(); - m_thing->setStateMaxValue(everestMaxChargingCurrentStateTypeId, - dataMap.value("max_current_A_import").toUInt()); - m_thing->setStateMinValue(everestMaxChargingCurrentStateTypeId, - dataMap.value("min_current_A_import").toUInt()); + m_thing->setStateMaxValue(everestMaxChargingCurrentStateTypeId, maxCurrent); + m_thing->setStateMinValue(everestMaxChargingCurrentStateTypeId, minCurrent == 0 ? 6 : minCurrent); + + // FIXME: once we have a method for phase switching, we can re-enable the featre here // bool phaseSwitchingAvailable = dataMap.value("supports_changing_phases_during_charging", false).toBool(); // if (!phaseSwitchingAvailable) { diff --git a/everest/everest.h b/everest/everest.h index 2058aa82..4dc3101a 100644 --- a/everest/everest.h +++ b/everest/everest.h @@ -61,6 +61,8 @@ public: explicit Everest(MqttClient *client, Thing *thing, QObject *parent = nullptr); ~Everest(); + Thing *thing() const; + QString connector() const; void initialize(); diff --git a/everest/everestclient.cpp b/everest/everestclient.cpp index b7bc8b65..fb1999aa 100644 --- a/everest/everestclient.cpp +++ b/everest/everestclient.cpp @@ -36,6 +36,7 @@ EverestClient::EverestClient(QObject *parent) { m_client = new MqttClient("nymea-" + QUuid::createUuid().toString().left(8), 300, QString(), QByteArray(), Mqtt::QoS0, false, this); + connect(m_client, &MqttClient::disconnected, this, [this](){ qCDebug(dcEverest()) << "The MQTT client is now disconnected" << this; if (!m_address.isNull()) { @@ -71,6 +72,13 @@ EverestClient::EverestClient(QObject *parent) }); } +EverestClient::~EverestClient() +{ + foreach (Everest *everest, m_everests) { + removeThing(everest->thing()); + } +} + MqttClient *EverestClient::client() const { return m_client; @@ -86,7 +94,7 @@ void EverestClient::addThing(Thing *thing) if (m_everests.contains(thing)) { qCWarning(dcEverest()) << "The" << thing << "has already been added to the everest client. " "Please report a bug if you see this message."; - // FIXME: maybe cleanup and recreate the client due to reconfigure + // TODO: maybe cleanup and recreate the client due to reconfigure return; } diff --git a/everest/everestclient.h b/everest/everestclient.h index 4d650bd5..a74c5266 100644 --- a/everest/everestclient.h +++ b/everest/everestclient.h @@ -49,6 +49,7 @@ class EverestClient : public QObject Q_OBJECT public: explicit EverestClient(QObject *parent = nullptr); + ~EverestClient(); MqttClient *client() const;