EVerest: Update to networkdevice interface

everest-network-device-interface
Simon Stürz 2024-12-10 14:09:36 +01:00
parent 3995238fd5
commit c8aa352d5c
7 changed files with 119 additions and 146 deletions

View File

@ -34,14 +34,13 @@
EverestClient::EverestClient(QObject *parent)
: QObject{parent}
{
m_client = new MqttClient("nymea-" + QUuid::createUuid().toString().left(8), 300,
QString(), QByteArray(), Mqtt::QoS0, false, this);
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()) {
if (m_monitor->reachable()) {
// Start the reconnect timer
qCDebug(dcEverest()) << "Starting reconnect timer for mqtt connection to" << m_address.toString();
qCDebug(dcEverest()) << "Starting reconnect timer for mqtt connection to" << m_monitor->networkDeviceInfo().address().toString();
m_reconnectTimer.start();
}
});
@ -68,7 +67,7 @@ EverestClient::EverestClient(QObject *parent)
return;
}
m_client->connectToHost(m_address.toString(), m_port);
m_client->connectToHost(m_monitor->networkDeviceInfo().address().toString(), m_port);
});
}
@ -123,26 +122,6 @@ Everest *EverestClient::getEverest(Thing *thing) const
return m_everests.value(thing);
}
QHostAddress EverestClient::address() const
{
return m_address;
}
void EverestClient::setAddress(const QHostAddress &address)
{
m_address = address;
}
MacAddress EverestClient::macAddress() const
{
return m_macAddress;
}
void EverestClient::setMacAddress(const MacAddress &macAddress)
{
m_macAddress = macAddress;
}
NetworkDeviceMonitor *EverestClient::monitor() const
{
return m_monitor;
@ -168,8 +147,8 @@ void EverestClient::start()
m_client->connectToHost(m_monitor->networkDeviceInfo().address().toString(), m_port);
}
} else {
qCDebug(dcEverest()) << "Connecting MQTT client to" << m_address.toString();
m_client->connectToHost(m_address.toString(), m_port);
qCDebug(dcEverest()) << "Connecting MQTT client to" << m_monitor->networkDeviceInfo().address().toString();
m_client->connectToHost(m_monitor->networkDeviceInfo().address().toString(), m_port);
// Note: on connected this will be stopped, otherwise we want the timer running
m_reconnectTimer.start();
@ -201,6 +180,8 @@ void EverestClient::onMonitorReachableChanged(bool reachable)
m_client->disconnectFromHost();
m_client->connectToHost(m_monitor->networkDeviceInfo().address().toString(), m_port);
} else {
m_reconnectTimer.stop();
}
}
@ -208,11 +189,18 @@ QDebug operator<<(QDebug debug, EverestClient *everestClient)
{
QDebugStateSaver saver(debug);
debug.nospace() << "EverestClient(";
if (everestClient->monitor()) {
debug.nospace() << everestClient->monitor()->networkDeviceInfo().macAddress() << ", ";
switch(everestClient->monitor()->monitorMode()) {
case NetworkDeviceInfo::MonitorModeMac:
debug.nospace() << everestClient->monitor()->networkDeviceInfo().macAddressInfos().constFirst() << ", ";
debug.nospace() << everestClient->monitor()->networkDeviceInfo().address().toString() << ", ";
} else {
debug.nospace() << everestClient->address().toString() << ", ";
break;
case NetworkDeviceInfo::MonitorModeHostName:
debug.nospace() << everestClient->monitor()->networkDeviceInfo().hostName() << ", ";
debug.nospace() << everestClient->monitor()->networkDeviceInfo().address().toString() << ", ";
break;
case NetworkDeviceInfo::MonitorModeIp:
debug.nospace() << everestClient->monitor()->networkDeviceInfo().address().toString() << ", ";
break;
}
debug.nospace() << "MQTT connected: " << everestClient->client()->isConnected() << ")";

View File

@ -59,12 +59,6 @@ public:
Everest *getEverest(Thing *thing) const;
QHostAddress address() const;
void setAddress(const QHostAddress &address);
MacAddress macAddress() const;
void setMacAddress(const MacAddress &macAddress);
NetworkDeviceMonitor *monitor() const;
void setMonitor(NetworkDeviceMonitor *monitor);
@ -83,12 +77,6 @@ private:
bool m_running = false;
QHash<Thing *, Everest *> m_everests;
// One of both must be defined, never both
QHostAddress m_address;
MacAddress m_macAddress;
// Available for mac based connections
NetworkDeviceMonitor *m_monitor = nullptr;
};

View File

@ -50,11 +50,11 @@ void EverestDiscovery::start()
NetworkDeviceDiscoveryReply *discoveryReply = m_networkDeviceDiscovery->discover();
connect(discoveryReply, &NetworkDeviceDiscoveryReply::networkDeviceInfoAdded, this, &EverestDiscovery::checkNetworkDevice);
connect(discoveryReply, &NetworkDeviceDiscoveryReply::hostAddressDiscovered, this, &EverestDiscovery::checkHostAddress);
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, discoveryReply, &NetworkDeviceDiscoveryReply::deleteLater);
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=](){
qCDebug(dcEverest()) << "Discovery: Network discovery finished. Found"
<< discoveryReply->networkDeviceInfos().count() << "network devices";
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [discoveryReply, this](){
qCDebug(dcEverest()) << "Discovery: Network device discovery finished. Found" << discoveryReply->networkDeviceInfos().count() << "network devices";
m_networkDeviceInfos = discoveryReply->networkDeviceInfos();
// Give the last connections added right before the network discovery finished a chance to check the device...
QTimer::singleShot(3000, this, [this](){
@ -65,8 +65,7 @@ void EverestDiscovery::start()
// For development, check local host
NetworkDeviceInfo localHostInfo;
localHostInfo.setAddress(QHostAddress::LocalHost);
checkNetworkDevice(localHostInfo);
checkHostAddress(QHostAddress::LocalHost);
}
void EverestDiscovery::startLocalhost()
@ -77,8 +76,7 @@ void EverestDiscovery::startLocalhost()
// For development, check local host
NetworkDeviceInfo localHostInfo;
localHostInfo.setAddress(QHostAddress::LocalHost);
checkNetworkDevice(localHostInfo);
checkHostAddress(QHostAddress::LocalHost);
}
QList<EverestDiscovery::Result> EverestDiscovery::results() const
@ -86,7 +84,7 @@ QList<EverestDiscovery::Result> EverestDiscovery::results() const
return m_results;
}
void EverestDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo)
void EverestDiscovery::checkHostAddress(const QHostAddress &address)
{
MqttClient *client = new MqttClient("nymea-" + QUuid::createUuid().toString().left(8), 300,
QString(), QByteArray(), Mqtt::QoS0, false, this);
@ -94,9 +92,9 @@ void EverestDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDevice
m_clients.append(client);
connect(client, &MqttClient::error, this, [this, client, networkDeviceInfo](QAbstractSocket::SocketError socketError){
connect(client, &MqttClient::error, this, [this, client, address](QAbstractSocket::SocketError socketError){
qCDebug(dcEverest()) << "Discovery: MQTT client error occurred on"
<< networkDeviceInfo.address().toString() << socketError
<< address.toString() << socketError
<< "...skip connection";
// We give up on the first error here
cleanupClient(client);
@ -110,11 +108,11 @@ void EverestDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDevice
cleanupClient(client);
});
connect(client, &MqttClient::connected, this, [this, client, networkDeviceInfo](){
connect(client, &MqttClient::connected, this, [this, client, address](){
// We found a mqtt server, let's check if we find everest_api module on it...
qCDebug(dcEverest()) << "Discovery: Successfully connected to host" << networkDeviceInfo;
qCDebug(dcEverest()) << "Discovery: Successfully connected to host" << address.toString();
connect(client, &MqttClient::publishReceived, client, [this, client, networkDeviceInfo]
connect(client, &MqttClient::publishReceived, client, [this, client, address]
(const QString &topic, const QByteArray &payload, bool retained) {
qCDebug(dcEverest()) << "Discovery: Received publish on" << topic
@ -131,9 +129,9 @@ void EverestDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDevice
}
QStringList connectors = jsonDoc.toVariant().toStringList();
qCInfo(dcEverest()) << "Discovery: Found Everest on" << networkDeviceInfo << connectors;
qCInfo(dcEverest()) << "Discovery: Found Everest on" << address.toString() << connectors;
Result result;
result.networkDeviceInfo = networkDeviceInfo;
result.address = address;
result.connectors = connectors;
m_results.append(result);
@ -159,10 +157,11 @@ void EverestDiscovery::checkNetworkDevice(const NetworkDeviceInfo &networkDevice
// });
});
qCDebug(dcEverest()) << "Discovery: Verifying host" << networkDeviceInfo;
client->connectToHost(networkDeviceInfo.address().toString(), 1883);
qCDebug(dcEverest()) << "Discovery: Verifying host" << address.toString();
client->connectToHost(address.toString(), 1883);
}
void EverestDiscovery::cleanupClient(MqttClient *client)
{
if (!m_clients.contains(client))
@ -186,6 +185,10 @@ void EverestDiscovery::finishDiscovery()
foreach (MqttClient *client, m_clients)
cleanupClient(client);
// Update results with final network device infos
for (int i = 0; i < m_results.count(); i++)
m_results[i].networkDeviceInfo = m_networkDeviceInfos.get(m_results.at(i).address);
qCInfo(dcEverest()) << "Discovery: Finished the discovery process. Found"
<< m_results.count() << "Everest instances in"
<< QTime::fromMSecsSinceStartOfDay(durationMilliSeconds).toString("mm:ss.zzz");

View File

@ -42,6 +42,7 @@ class EverestDiscovery : public QObject
Q_OBJECT
public:
typedef struct Result {
QHostAddress address;
QStringList connectors;
NetworkDeviceInfo networkDeviceInfo;
} Result;
@ -49,7 +50,6 @@ public:
explicit EverestDiscovery(NetworkDeviceDiscovery *networkDeviceDiscovery, QObject *parent = nullptr);
void start();
void startLocalhost();
QList<EverestDiscovery::Result> results() const;
@ -62,12 +62,13 @@ private:
QDateTime m_startDateTime;
QList<EverestDiscovery::Result> m_results;
QList<MqttClient *> m_clients;
NetworkDeviceInfos m_networkDeviceInfos;
bool m_localhostDiscovery = false;
QString m_everestApiModuleTopicConnectors = "everest_api/connectors";
void checkNetworkDevice(const NetworkDeviceInfo &networkDeviceInfo);
void checkHostAddress(const QHostAddress &address);
void cleanupClient(MqttClient *client);
void finishDiscovery();
};

View File

@ -34,17 +34,17 @@
#include <network/networkdevicediscovery.h>
IntegrationPluginTruffle::IntegrationPluginTruffle()
IntegrationPluginEverest::IntegrationPluginEverest()
{
}
void IntegrationPluginTruffle::init()
void IntegrationPluginEverest::init()
{
}
void IntegrationPluginTruffle::startMonitoringAutoThings()
void IntegrationPluginEverest::startMonitoringAutoThings()
{
// 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
@ -108,7 +108,7 @@ void IntegrationPluginTruffle::startMonitoringAutoThings()
discovery->startLocalhost();
}
void IntegrationPluginTruffle::discoverThings(ThingDiscoveryInfo *info)
void IntegrationPluginEverest::discoverThings(ThingDiscoveryInfo *info)
{
qCDebug(dcEverest()) << "Start discovering Everest systems in the local network";
if (!hardwareManager()->networkDeviceDiscovery()->available()) {
@ -127,22 +127,36 @@ void IntegrationPluginTruffle::discoverThings(ThingDiscoveryInfo *info)
foreach(const QString &connectorName, result.connectors) {
QString title = QString("Everest (%1)").arg(connectorName);
QString description = result.networkDeviceInfo.address().toString() +
" " + result.networkDeviceInfo.macAddress();
ThingDescriptor descriptor(everestThingClassId, title, description);
QString description;
MacAddressInfo macInfo;
switch (result.networkDeviceInfo.monitorMode()) {
case NetworkDeviceInfo::MonitorModeMac:
macInfo = result.networkDeviceInfo.macAddressInfos().constFirst();
description = result.networkDeviceInfo.address().toString();
if (!macInfo.vendorName().isEmpty())
description += " - " + result.networkDeviceInfo.macAddressInfos().constFirst().vendorName();
break;
case NetworkDeviceInfo::MonitorModeHostName:
description = result.networkDeviceInfo.address().toString();
break;
case NetworkDeviceInfo::MonitorModeIp:
description = "Interface: " + result.networkDeviceInfo.networkInterface().name();
break;
}
ThingDescriptor descriptor(everestThingClassId, title, description);
qCInfo(dcEverest()) << "Discovered -->" << title << description;
// Note: the network device info already provides the correct set of parameters in order to be used by the monitor
// depending on the possibilities within this network. It is not recommended to fill in all information available.
// Only the information available depending on the monitor mode are relevant for the monitor.
ParamList params;
params.append(Param(everestThingConnectorParamTypeId, connectorName));
if (!MacAddress(result.networkDeviceInfo.macAddress()).isNull())
params.append(Param(everestThingMacParamTypeId, result.networkDeviceInfo.macAddress()));
if (!result.networkDeviceInfo.address().isNull())
params.append(Param(everestThingAddressParamTypeId,
result.networkDeviceInfo.address().toString()));
params.append(Param(everestThingMacAddressParamTypeId, result.networkDeviceInfo.thingParamValueMacAddress()));
params.append(Param(everestThingHostNameParamTypeId, result.networkDeviceInfo.thingParamValueHostName()));
params.append(Param(everestThingAddressParamTypeId, result.networkDeviceInfo.thingParamValueAddress()));
descriptor.setParams(params);
// Let's check if we aleardy have a thing with those params
@ -179,77 +193,42 @@ void IntegrationPluginTruffle::discoverThings(ThingDiscoveryInfo *info)
discovery->start();
}
void IntegrationPluginTruffle::setupThing(ThingSetupInfo *info)
void IntegrationPluginEverest::setupThing(ThingSetupInfo *info)
{
Thing *thing = info->thing();
QHostAddress address(thing->paramValue(everestThingAddressParamTypeId).toString());
MacAddress macAddress(thing->paramValue(everestThingMacParamTypeId).toString());
MacAddress macAddress(thing->paramValue(everestThingMacAddressParamTypeId).toString());
QString hostName(thing->paramValue(everestThingHostNameParamTypeId).toString());
QString connector(thing->paramValue(everestThingConnectorParamTypeId).toString());
if (!macAddress.isNull()) {
EverestClient *everstClient = nullptr;
qCInfo(dcEverest()) << "Setting up everest for" << macAddress.toString() << connector;
EverestClient *everstClient = nullptr;
foreach (EverestClient *ec, m_everstClients) {
if (ec->macAddress() == macAddress) {
// We have already a client for this host
qCDebug(dcEverest()) << "Using existing" << ec;
everstClient = ec;
}
foreach (EverestClient *ec, m_everstClients) {
if (ec->monitor()->macAddress() == macAddress &&
ec->monitor()->hostName() == hostName &&
ec->monitor()->address() == address) {
// We have already a client for this host
qCDebug(dcEverest()) << "Using existing" << ec;
everstClient = ec;
}
if (!everstClient) {
qCDebug(dcEverest()) << "Creating new mac address based everst client";
everstClient = new EverestClient(this);
everstClient->setMacAddress(macAddress);
everstClient->setMonitor(hardwareManager()->networkDeviceDiscovery()->registerMonitor(macAddress));
m_everstClients.append(everstClient);
everstClient->start();
}
everstClient->addThing(thing);
m_thingClients.insert(thing, everstClient);
info->finish(Thing::ThingErrorNoError);
return;
} else {
qCInfo(dcEverest()) << "Setting up IP based everest for" << address.toString() << connector;
EverestClient *everstClient = nullptr;
foreach (EverestClient *ec, m_everstClients) {
if (ec->address().isNull())
continue;
if (ec->address() == address) {
// We have already a client for this host
qCDebug(dcEverest()) << "Using existing" << ec;
everstClient = ec;
break;
}
}
if (!everstClient) {
qCDebug(dcEverest()) << "Creating new IP based everst client";
everstClient = new EverestClient(this);
everstClient->setAddress(address);
m_everstClients.append(everstClient);
everstClient->start();
}
everstClient->addThing(thing);
m_thingClients.insert(thing, everstClient);
info->finish(Thing::ThingErrorNoError);
return;
}
if (!everstClient) {
everstClient = new EverestClient(this);
everstClient->setMonitor(hardwareManager()->networkDeviceDiscovery()->registerMonitor(thing));
m_everstClients.append(everstClient);
qCDebug(dcEverest()) << "Created new" << everstClient;
everstClient->start();
}
everstClient->addThing(thing);
m_thingClients.insert(thing, everstClient);
info->finish(Thing::ThingErrorNoError);
return;
}
void IntegrationPluginTruffle::executeAction(ThingActionInfo *info)
void IntegrationPluginEverest::executeAction(ThingActionInfo *info)
{
qCDebug(dcEverest()) << "Executing action for thing" << info->thing()
<< info->action().actionTypeId().toString() << info->action().params();
@ -298,7 +277,7 @@ void IntegrationPluginTruffle::executeAction(ThingActionInfo *info)
info->finish(Thing::ThingErrorNoError);
}
void IntegrationPluginTruffle::thingRemoved(Thing *thing)
void IntegrationPluginEverest::thingRemoved(Thing *thing)
{
qCDebug(dcEverest()) << "Remove thing" << thing;
if (thing->thingClassId() == everestThingClassId) {
@ -308,8 +287,16 @@ void IntegrationPluginTruffle::thingRemoved(Thing *thing)
qCDebug(dcEverest()) << "Deleting" << everestClient << "since there is no thing left";
// No more things related to this client, we can delete it
m_everstClients.removeAll(everestClient);
// Unregister monitor
if (everestClient->monitor())
hardwareManager()->networkDeviceDiscovery()->unregisterMonitor(everestClient->monitor());
everestClient->deleteLater();
}
}
}

View File

@ -38,7 +38,7 @@
#include <mqttclient.h>
class IntegrationPluginTruffle: public IntegrationPlugin
class IntegrationPluginEverest: public IntegrationPlugin
{
Q_OBJECT
@ -46,7 +46,7 @@ class IntegrationPluginTruffle: public IntegrationPlugin
Q_INTERFACES(IntegrationPlugin)
public:
explicit IntegrationPluginTruffle();
explicit IntegrationPluginEverest();
void init() override;
void startMonitoringAutoThings() override;

View File

@ -14,23 +14,29 @@
"id": "965cbe0d-088c-42a2-965d-ceafbb8b01e9",
"setupMethod": "JustAdd",
"createMethods": ["discovery", "user"],
"interfaces": [ "evcharger", "smartmeterconsumer", "connectable" ],
"interfaces": [ "evcharger", "smartmeterconsumer", "networkdevice", "connectable" ],
"paramTypes": [
{
"id": "f1f3e9a7-3a35-4089-8869-b9bfd64659e5",
"name": "hostName",
"displayName": "Host name",
"type": "QString"
},
{
"id": "911b6fa3-010c-486e-8251-71a6aa21adb3",
"name": "address",
"displayName": "Host address",
"displayName": "IP address",
"type": "QString",
"inputType": "IPv4Address",
"defaultValue": ""
},
{
"id": "cb9517ef-1ae2-49c9-9036-0c6e15bb3652",
"name": "mac",
"name": "macAddress",
"displayName": "MAC address",
"type": "QString",
"readOnly": true,
"defaultValue": "00:00:00:00:00:00"
"defaultValue": "00:00:00:00:00:00",
"readOnly": true
},
{
"id": "73f27e36-6f68-40a9-8805-22e88911736c",