Architecture choice: Modbus TCP has no network discovery mechanism, so
discovery piggybacks on nymea's NetworkDeviceDiscovery (ARP/mDNS scan)
and then probes each host via GET /RealTimeData (V2C Trydan HTTP REST API).
The presence of a "Paused" field in the JSON response is used as a Trydan
fingerprint — it matches the charger model and is absent on generic devices.
cf. evcc charger/trydan.go realTimeData struct.
Probes run concurrently (one QNetworkReply per host) but the sequence
terminates via two independent paths that could both fire:
1. The NetworkDeviceDiscoveryReply::finished callback arms a 3-second
QTimer::singleShot to give outstanding probes time to complete.
2. Each probe completion path checks (m_scanFinished && pendingProbes==0)
and calls finishDiscovery() early if all probes are already done.
A m_finished bool guard prevents double-emission of discoveryFinished()
if both paths fire in quick succession (e.g. all probes complete exactly
as the timer fires).
Manual-entry (createMethod "user") skips discovery entirely; setupThing()
is called directly with the user-supplied IP.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
62 lines
1.7 KiB
C++
62 lines
1.7 KiB
C++
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
#ifndef V2CTCPDISCOVERY_H
|
|
#define V2CTCPDISCOVERY_H
|
|
|
|
#include <QObject>
|
|
#include <QDateTime>
|
|
#include <QNetworkAccessManager>
|
|
#include <QHash>
|
|
|
|
#include <network/networkdevicediscovery.h>
|
|
|
|
/*!
|
|
* \brief Network discovery for V2C Trydan chargers (Modbus TCP).
|
|
*
|
|
* Uses nymea's NetworkDeviceDiscovery to enumerate LAN hosts, then probes
|
|
* each one with \c GET /RealTimeData (the V2C Trydan HTTP REST API) to
|
|
* confirm it is a Trydan. The probe is HTTP — not Modbus — because the
|
|
* Trydan has no network-accessible Modbus discovery mechanism.
|
|
* cf. AGENTS.md § HTTP and evcc charger/trydan.go.
|
|
*
|
|
* Manual-entry (createMethod "user") bypasses discovery entirely;
|
|
* the plugin calls setupThing() directly with the user-supplied IP.
|
|
*/
|
|
class V2cTcpDiscovery : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
struct Result {
|
|
NetworkDeviceInfo networkDeviceInfo;
|
|
QString ipAddress;
|
|
};
|
|
|
|
explicit V2cTcpDiscovery(NetworkDeviceDiscovery *networkDeviceDiscovery,
|
|
QObject *parent = nullptr);
|
|
|
|
void startDiscovery();
|
|
|
|
/*! \brief Results available after discoveryFinished() is emitted. */
|
|
QList<Result> results() const;
|
|
|
|
signals:
|
|
void discoveryFinished();
|
|
|
|
private:
|
|
void probeAddress(const QHostAddress &address);
|
|
void finishDiscovery();
|
|
|
|
NetworkDeviceDiscovery *m_networkDeviceDiscovery = nullptr;
|
|
QNetworkAccessManager m_nam;
|
|
|
|
QDateTime m_startTime;
|
|
NetworkDeviceInfos m_networkDeviceInfos;
|
|
int m_pendingProbes = 0;
|
|
QList<Result> m_results;
|
|
bool m_scanFinished = false;
|
|
bool m_finished = false;
|
|
};
|
|
|
|
#endif // V2CTCPDISCOVERY_H
|