Étape 1 complete: V2C Trydan nymea plugin (Modbus TCP, status Partial).
Plugin (IntegrationPluginV2c):
- discoverThings: delegates to V2cTcpDiscovery, maps results to
ThingDescriptors; createMethod "user" bypasses discovery.
- setupThing: registers a NetworkDeviceMonitor (IP tracking on DHCP
renewal), creates TrydanModbusTcpMaster, wires reachableChanged →
initialize() → state update on initializationFinished(), then starts
periodic polls on a 30s PluginTimer.
- updateThingStates: ChargeState 0/1/2 → pluggedIn/charging;
power = (PauseState==0 AND Lock==0) per evcc trydan.go Enabled().
- handleDynamicConflict: if Dynamic==1 (V2C internal PV optimizer),
write PauseDynamic=1 to suppress it. NEVER write Dynamic=0 (silences
ChargePower telemetry). Writes only on state transition to minimize
flash wear. cf. github.com/evcc-io/evcc/issues/28047.
- Action "power": writes PauseState then Lock (always in mirror), then
fire-and-forgets PauseDynamic if Dynamic==1. Action handlers filter
writeCompleted by register address to avoid reacting to concurrent
background writes.
- Action "maxChargingCurrent": clamps to [minIntensity, maxIntensity],
writes Intensity. Below 6A → pause instead of invalid setpoint.
JSON (integrationpluginv2c.json):
- ThingClass "trydan" implementing evcharger + connectable + networkdevice.
- settingsTypes: suspendInternalOptimizer (bool, default true) — allows
the user to disable Dynamic conflict management if they want the V2C
PID to remain active alongside the HEMS.
- State "chargeEnergy" exposed as diagnostic only (NOT sessionEnergy) —
firmware reliability on this register is unvalidated; cf. evcc #28047.
Build (v2c.pro):
- MODBUS_CONNECTIONS intentionally empty: the modbus-tool code generator
assumes non-overlapping block reads; leaving it empty skips generation
while still linking nymea-modbus via the PKGCONFIG in modbus.pri.
VendorId 56c3e7bb… is new (no existing V2C vendor in the repo).
PluginId f0692725… is new (generated for this plugin).
PORTING_STATUS_modbus.md documents register sources, the 4 items that
require validation on real hardware, and the "no beta matrix" constraint.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
69 lines
2.4 KiB
C++
69 lines
2.4 KiB
C++
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
#ifndef INTEGRATIONPLUGINV2C_H
|
|
#define INTEGRATIONPLUGINV2C_H
|
|
|
|
#include <plugintimer.h>
|
|
#include <integrations/integrationplugin.h>
|
|
#include <network/networkdevicemonitor.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
|
|
*
|
|
* É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);
|
|
|
|
PluginTimer *m_pluginTimer = nullptr;
|
|
|
|
QHash<Thing *, TrydanModbusTcpMaster *> m_tcpMasters;
|
|
QHash<Thing *, NetworkDeviceMonitor *> m_monitors;
|
|
};
|
|
|
|
#endif // INTEGRATIONPLUGINV2C_H
|