etm-powersync-plugins-modbus/v2c/integrationpluginv2c.h
Patrick Schurig 076a0dcae9 feat(v2c): remove NetworkDeviceMonitor, add poll-based connectivity + statusMessage
The Trydan ESP32 WiFi stack saturates under nymea's periodic ICMP pings
(observed: latency > 14 s, Modbus timeouts, charger drops off).

Changes:
- NetworkDeviceMonitor removed entirely from setupThing() and thingRemoved().
  The charger is expected to have a DHCP-reserved IP (documented in code).
  Address comes from trydanThingAddressParamTypeId param — already the correct
  path after the previous setup fix.
- Connectivity now derives from Modbus poll success/failure only (reachable()
  from TrydanModbusTcpMaster), NOT from network ping.  A ping response does
  not imply Modbus usability on this hardware.
- postSetupThing() timer (30 s): if not reachable, calls connectDevice() for
  reconnect; if reachable, calls update().  The 30 s period IS the backoff —
  no aggressive retry loop.
- Modbus timeout: 2 s → 5 s (tolerates residual WiFi latency spikes).
- Modbus retries per read: 1 → 0 (abort fast on first timeout; full poll
  sequence already aborts at first error via doNextRead).
- k_errorLimit: 5 → 3 (3 × 5 s = 15 s before marking unreachable).
- New state "statusMessage" (QString): set on disconnect with timestamp +
  cause ("timeout Modbus — vérifier signal WiFi de la borne"); cleared on
  successful poll.  Visible in nymea-app; helps SAV without SSH access.
- "networkdevice" removed from JSON interfaces (contract broken without monitor).

Invariants preserved: Big/Big float32 decode, no block read, PauseState+Lock
mirror, PauseDynamic conflict management, writeCompleted address filtering.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 18:15:30 +02:00

71 lines
2.5 KiB
C++

// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef INTEGRATIONPLUGINV2C_H
#define INTEGRATIONPLUGINV2C_H
#include <plugintimer.h>
#include <integrations/integrationplugin.h>
#include "extern-plugininfo.h"
#include "trydanmodbusmaster.h"
#include "trydanmodbustcpmaster.h"
/*!
* \brief nymea integration plugin for the V2C Trydan EV charger.
*
* ThingClass \c trydan implementing the \c evcharger interface via Modbus TCP
* (Étape 1). All register-level I/O is delegated to TrydanModbusTcpMaster;
* this class owns the evcharger business logic:
* - ChargeState → pluggedIn / charging mapping
* - chargingEnabled = (PauseState==0 AND Lock==0)
* - Dynamic optimizer conflict management via PauseDynamic
*
* No NetworkDeviceMonitor: the Trydan ESP32 WiFi stack saturates under
* periodic ICMP pings (latency > 14 s, Modbus timeouts). Connectivity is
* derived from Modbus poll success/failure instead.
*
* Étape 2 (RTU) will add TrydanModbusRtuMaster on the same TrydanModbusMaster
* interface; the logic in this file requires no changes.
*/
class IntegrationPluginV2c : public IntegrationPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationpluginv2c.json")
Q_INTERFACES(IntegrationPlugin)
public:
explicit IntegrationPluginV2c();
void discoverThings(ThingDiscoveryInfo *info) override;
void setupThing(ThingSetupInfo *info) override;
void postSetupThing(Thing *thing) override;
void thingRemoved(Thing *thing) override;
public slots:
void executeAction(ThingActionInfo *info) override;
private:
/*! \brief Apply all evcharger states from the last completed poll. */
void updateThingStates(Thing *thing, TrydanModbusMaster *master);
/*!
* \brief Manage the Dynamic/PauseDynamic conflict on each poll.
*
* If Dynamic==1 (V2C internal optimizer is running) and HEMS is in control
* (chargingEnabled==true), write PauseDynamic=1 to suppress the internal PID
* without disabling the telemetry. Release PauseDynamic=0 when HEMS
* relinquishes control. Dynamic is NEVER written (would silence ChargePower).
* cf. AGENTS.md § CONFLIT and evcc charger/trydan.go.
*/
void handleDynamicConflict(Thing *thing, TrydanModbusMaster *master);
void setDisconnectedState(Thing *thing, const QString &cause = QString());
PluginTimer *m_pluginTimer = nullptr;
QHash<Thing *, TrydanModbusTcpMaster *> m_tcpMasters;
};
#endif // INTEGRATIONPLUGINV2C_H