Skip to content

Commit

Permalink
Merge PR #202: SunSpec: Update to networkdevice intrface
Browse files Browse the repository at this point in the history
  • Loading branch information
jenkins committed Dec 19, 2024
2 parents ea20308 + fba95a3 commit 9c9ecc3
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 53 deletions.
80 changes: 51 additions & 29 deletions sunspec/integrationpluginsunspec.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2023, nymea GmbH
* Copyright 2013 - 2024, nymea GmbH
* Contact: [email protected]
*
* This file is part of nymea.
Expand Down Expand Up @@ -70,12 +70,18 @@ IntegrationPluginSunSpec::IntegrationPluginSunSpec()
void IntegrationPluginSunSpec::init()
{
// SunSpec connection params
m_connectionPortParamTypeIds.insert(sunspecConnectionThingClassId, sunspecConnectionThingPortParamTypeId);
m_connectionPortParamTypeIds.insert(solarEdgeConnectionThingClassId, solarEdgeConnectionThingPortParamTypeId);

m_connectionMacAddressParamTypeIds.insert(sunspecConnectionThingClassId, sunspecConnectionThingMacAddressParamTypeId);
m_connectionMacAddressParamTypeIds.insert(solarEdgeConnectionThingClassId, solarEdgeConnectionThingMacAddressParamTypeId);

m_connectionHostNameParamTypeIds.insert(sunspecConnectionThingClassId, sunspecConnectionThingHostNameParamTypeId);
m_connectionHostNameParamTypeIds.insert(solarEdgeConnectionThingClassId, solarEdgeConnectionThingHostNameParamTypeId);

m_connectionAddressParamTypeIds.insert(sunspecConnectionThingClassId, sunspecConnectionThingAddressParamTypeId);
m_connectionAddressParamTypeIds.insert(solarEdgeConnectionThingClassId, solarEdgeConnectionThingAddressParamTypeId);

m_connectionPortParamTypeIds.insert(sunspecConnectionThingClassId, sunspecConnectionThingPortParamTypeId);
m_connectionPortParamTypeIds.insert(solarEdgeConnectionThingClassId, solarEdgeConnectionThingPortParamTypeId);

m_connectionSlaveIdParamTypeIds.insert(sunspecConnectionThingClassId, sunspecConnectionThingSlaveIdParamTypeId);
m_connectionSlaveIdParamTypeIds.insert(solarEdgeConnectionThingClassId, solarEdgeConnectionThingSlaveIdParamTypeId);

Expand Down Expand Up @@ -141,7 +147,7 @@ void IntegrationPluginSunSpec::discoverThings(ThingDiscoveryInfo *info)

SunSpecDiscovery *discovery = new SunSpecDiscovery(hardwareManager()->networkDeviceDiscovery(), slaveIds, byteOrder, info);
// Note: we could add here more
connect(discovery, &SunSpecDiscovery::discoveryFinished, info, [=](){
connect(discovery, &SunSpecDiscovery::discoveryFinished, info, [this, info, discovery](){
foreach (const SunSpecDiscovery::Result &result, discovery->results()) {

// Extract the manufacturer: we pick the first manufacturer name of the first common model having a manufacturer name for now
Expand All @@ -166,6 +172,7 @@ void IntegrationPluginSunSpec::discoverThings(ThingDiscoveryInfo *info)
// Full support of meter, inverter and storage will be provided in the kostal plugin which makes
// use of the native modbus communication from kostal.
if (hasManufacturer(result.modelManufacturers, "kostal")) {
qCWarning(dcSunSpec()) << "Skipping Kostal manufacturer on SunSpec. Please use the native kostal integration plugin in order to add it to the system.";
continue;
}
}
Expand All @@ -177,26 +184,40 @@ void IntegrationPluginSunSpec::discoverThings(ThingDiscoveryInfo *info)
title.append("SunSpec connection");

QString description;
if (result.networkDeviceInfo.macAddressManufacturer().isEmpty()) {
description = result.networkDeviceInfo.macAddress();
} else {
description = result.networkDeviceInfo.macAddress() + " (" + result.networkDeviceInfo.macAddressManufacturer() + ")";
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.hostName();
break;
case NetworkDeviceInfo::MonitorModeIp:
description = "Interface: " + result.networkDeviceInfo.networkInterface().name();
break;
}

ThingDescriptor descriptor(info->thingClassId(), title, description);

// Check if we already have set up this device
Things existingThings = myThings().filterByParam(m_connectionMacAddressParamTypeIds.value(info->thingClassId()), result.networkDeviceInfo.macAddress());
if (existingThings.count() == 1) {
qCDebug(dcSunSpec()) << "This thing already exists in the system." << existingThings.first() << result.networkDeviceInfo;
descriptor.setThingId(existingThings.first()->id());
}

ParamList params;
params << Param(m_connectionMacAddressParamTypeIds.value(info->thingClassId()), result.networkDeviceInfo.thingParamValueMacAddress());
params << Param(m_connectionHostNameParamTypeIds.value(info->thingClassId()), result.networkDeviceInfo.thingParamValueHostName());
params << Param(m_connectionAddressParamTypeIds.value(info->thingClassId()), result.networkDeviceInfo.thingParamValueAddress());
params << Param(m_connectionPortParamTypeIds.value(info->thingClassId()), result.port);
params << Param(m_connectionMacAddressParamTypeIds.value(info->thingClassId()), result.networkDeviceInfo.macAddress());
params << Param(m_connectionSlaveIdParamTypeIds.value(info->thingClassId()), result.slaveId);
descriptor.setParams(params);

// Check if we already have set up this device
Thing *existingThing = myThings().findByParams(params);
if (existingThing) {
qCDebug(dcSunSpec()) << "This thing already exists in the system:" << result.networkDeviceInfo;
descriptor.setThingId(existingThing->id());
}

info->addThingDescriptor(descriptor);
}

Expand All @@ -213,7 +234,8 @@ void IntegrationPluginSunSpec::setupThing(ThingSetupInfo *info)
qCDebug(dcSunSpec()) << "Setup thing" << thing;
qCDebug(dcSunSpec()) << thing->params();

if (thing->thingClassId() == sunspecConnectionThingClassId || thing->thingClassId() == solarEdgeConnectionThingClassId) {
if (thing->thingClassId() == sunspecConnectionThingClassId ||
thing->thingClassId() == solarEdgeConnectionThingClassId) {

// Handle reconfigure
if (m_sunSpecConnections.contains(thing->id())) {
Expand All @@ -225,16 +247,17 @@ void IntegrationPluginSunSpec::setupThing(ThingSetupInfo *info)
}
}

MacAddress macAddress = MacAddress(thing->paramValue(m_connectionMacAddressParamTypeIds.value(thing->thingClassId())).toString());
if (!macAddress.isValid()) {
qCWarning(dcSunSpec()) << "The configured mac address is not valid" << thing->params();
info->finish(Thing::ThingErrorInvalidParameter, QT_TR_NOOP("The MAC address is not known. Please reconfigure the connection."));

// Create the monitor
NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(thing);
if (!monitor) {
qCWarning(dcSunSpec()) << "Unable to register monitor with the given params" << thing->params();
info->finish(Thing::ThingErrorInvalidParameter, QT_TR_NOOP("Unable to set up the connection with this configuration, please reconfigure the connection."));
return;
}

// Create the monitor
NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(macAddress);
m_monitors.insert(thing, monitor);

QHostAddress address = monitor->networkDeviceInfo().address();
if (address.isNull() && info->isInitialSetup()) {
qCWarning(dcSunSpec()) << "Cannot set up thing. The host address is not known and this is an initial setup";
Expand Down Expand Up @@ -305,9 +328,9 @@ void IntegrationPluginSunSpec::setupThing(ThingSetupInfo *info)
}
}

} else if (thing->thingClassId() == sunspecThreePhaseInverterThingClassId
|| thing->thingClassId() == sunspecSplitPhaseInverterThingClassId
|| thing->thingClassId() == sunspecSinglePhaseInverterThingClassId ) {
} else if (thing->thingClassId() == sunspecThreePhaseInverterThingClassId ||
thing->thingClassId() == sunspecSplitPhaseInverterThingClassId ||
thing->thingClassId() == sunspecSinglePhaseInverterThingClassId ) {

Thing *thing = info->thing();
uint modelId = thing->paramValue(m_modelIdParamTypeIds.value(thing->thingClassId())).toInt();
Expand Down Expand Up @@ -420,9 +443,8 @@ void IntegrationPluginSunSpec::thingRemoved(Thing *thing)
Q_ASSERT_X(false, "thingRemoved", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8());
}

if (m_monitors.contains(thing)) {
if (m_monitors.contains(thing))
hardwareManager()->networkDeviceDiscovery()->unregisterMonitor(m_monitors.take(thing));
}

if (myThings().isEmpty()) {
qCDebug(dcSunSpec()) << "Stopping refresh timer";
Expand Down
7 changes: 4 additions & 3 deletions sunspec/integrationpluginsunspec.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2023, nymea GmbH
* Copyright 2013 - 2024, nymea GmbH
* Contact: [email protected]
*
* This file is part of nymea.
Expand Down Expand Up @@ -62,9 +62,10 @@ class IntegrationPluginSunSpec: public IntegrationPlugin

private:
// SunSpec Connection params map
QHash<ThingClassId, ParamTypeId> m_connectionIpParamTypeIds;
QHash<ThingClassId, ParamTypeId> m_connectionPortParamTypeIds;
QHash<ThingClassId, ParamTypeId> m_connectionMacAddressParamTypeIds;
QHash<ThingClassId, ParamTypeId> m_connectionAddressParamTypeIds;
QHash<ThingClassId, ParamTypeId> m_connectionHostNameParamTypeIds;
QHash<ThingClassId, ParamTypeId> m_connectionPortParamTypeIds;
QHash<ThingClassId, ParamTypeId> m_connectionSlaveIdParamTypeIds;

// SunSpec thing params map
Expand Down
42 changes: 38 additions & 4 deletions sunspec/integrationpluginsunspec.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,32 @@
"displayName": "SunSpec Generic",
"id": "f51853f3-8815-4cf3-b337-45cda1f3e6d5",
"createMethods": [ "Discovery" ],
"interfaces": ["gateway"],
"interfaces": [ "gateway", "networkdevice" ],
"providedInterfaces": [ "solarinverter", "energymeter", "energystorage"],
"paramTypes": [
{
"id": "3567b389-9d42-48f9-a29b-d18388fb36a1",
"name": "address",
"displayName": "Host address",
"type": "QString",
"inputType": "IPv4Address",
"defaultValue": ""
},
{
"id": "1667b0ed-9a2b-47c6-a01f-690caee55ffa",
"name": "hostName",
"displayName": "Host name",
"type": "QString",
"inputType": "TextLine",
"defaultValue": ""
},
{
"id": "f65d6c36-1672-44cb-b52a-62d71837ae67",
"name":"macAddress",
"displayName": "MAC address",
"type": "QString",
"defaultValue": "00:00:00:00:00:00"
"inputType": "MacAddress",
"defaultValue": ""
},
{
"id": "1fa4fc9c-f6be-47c7-928a-bcefc1142eec",
Expand Down Expand Up @@ -1458,15 +1475,32 @@
"displayName": "SolarEdge",
"id": "7a92bf65-b443-4491-a012-2bec35eb5bf0",
"createMethods": [ "Discovery" ],
"interfaces": ["gateway"],
"interfaces": [ "gateway", "networkdevice" ],
"providedInterfaces": [ "solarinverter", "energymeter", "energystorage" ],
"paramTypes": [
{
"id": "9c2bafd0-6d56-42e0-8ef3-c4940b4f18b5",
"name": "address",
"displayName": "Host address",
"type": "QString",
"inputType": "IPv4Address",
"defaultValue": ""
},
{
"id": "2e22c369-8476-4908-9cdc-186472f4d472",
"name": "hostName",
"displayName": "Host name",
"type": "QString",
"inputType": "TextLine",
"defaultValue": ""
},
{
"id": "bb395c12-54d6-4139-b0a6-e31b28bc4d2e",
"name":"macAddress",
"displayName": "MAC address",
"type": "QString",
"defaultValue": "00:00:00:00:00:00"
"inputType": "MacAddress",
"defaultValue": ""
},
{
"id": "1bcede48-d167-4ced-8f1b-bea6302dd43f",
Expand Down
Loading

0 comments on commit 9c9ecc3

Please sign in to comment.