renamed block or map to model
This commit is contained in:
parent
4a9064c647
commit
b536b1b16e
@ -5,12 +5,19 @@ Connect to SunSpec devices over Modbus TCP
|
|||||||
## Supported Things
|
## Supported Things
|
||||||
|
|
||||||
* SunSpec Inverter
|
* SunSpec Inverter
|
||||||
|
* 101 & 111 Single phase inverter
|
||||||
|
* 102 & 112 Split phase inverter
|
||||||
|
* 103 & 113 Three phase inverter
|
||||||
* SunSpec Meter
|
* SunSpec Meter
|
||||||
* SunSpec Storage
|
* Single phase meter
|
||||||
|
* Split phase meter
|
||||||
|
* 203 Three phase meter
|
||||||
|
* SunSpec Storage [124]
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
* The package 'nymea-plugin-sunspec' must be installed.
|
* The package 'nymea-plugin-sunspec' must be installed.
|
||||||
|
* The SunSpec device must support SunSpec over modbus TCP
|
||||||
|
|
||||||
## More
|
## More
|
||||||
https://sunspec.org
|
https://sunspec.org
|
||||||
|
|||||||
@ -49,13 +49,13 @@ void IntegrationPluginSunSpec::init()
|
|||||||
m_connectedStateTypeIds.insert(sunspecSplitPhaseMeterThingClassId, sunspecSplitPhaseMeterConnectedStateTypeId);
|
m_connectedStateTypeIds.insert(sunspecSplitPhaseMeterThingClassId, sunspecSplitPhaseMeterConnectedStateTypeId);
|
||||||
m_connectedStateTypeIds.insert(sunspecThreePhaseMeterThingClassId, sunspecThreePhaseMeterConnectedStateTypeId);
|
m_connectedStateTypeIds.insert(sunspecThreePhaseMeterThingClassId, sunspecThreePhaseMeterConnectedStateTypeId);
|
||||||
|
|
||||||
m_mapIdParamTypeIds.insert(sunspecSinglePhaseInverterThingClassId, sunspecSinglePhaseInverterThingMapIdParamTypeId);
|
m_modelIdParamTypeIds.insert(sunspecSinglePhaseInverterThingClassId, sunspecSinglePhaseInverterThingModelIdParamTypeId);
|
||||||
m_mapIdParamTypeIds.insert(sunspecSplitPhaseInverterThingClassId, sunspecSplitPhaseInverterThingMapIdParamTypeId);
|
m_modelIdParamTypeIds.insert(sunspecSplitPhaseInverterThingClassId, sunspecSplitPhaseInverterThingModelIdParamTypeId);
|
||||||
m_mapIdParamTypeIds.insert(sunspecThreePhaseInverterThingClassId, sunspecThreePhaseInverterThingMapIdParamTypeId);
|
m_modelIdParamTypeIds.insert(sunspecThreePhaseInverterThingClassId, sunspecThreePhaseInverterThingModelIdParamTypeId);
|
||||||
m_mapIdParamTypeIds.insert(sunspecStorageThingClassId, sunspecStorageThingMapIdParamTypeId);
|
m_modelIdParamTypeIds.insert(sunspecStorageThingClassId, sunspecStorageThingModelIdParamTypeId);
|
||||||
m_mapIdParamTypeIds.insert(sunspecSinglePhaseMeterThingClassId, sunspecSinglePhaseMeterThingMapIdParamTypeId);
|
m_modelIdParamTypeIds.insert(sunspecSinglePhaseMeterThingClassId, sunspecSinglePhaseMeterThingModelIdParamTypeId);
|
||||||
m_mapIdParamTypeIds.insert(sunspecSplitPhaseMeterThingClassId, sunspecSplitPhaseMeterThingMapIdParamTypeId);
|
m_modelIdParamTypeIds.insert(sunspecSplitPhaseMeterThingClassId, sunspecSplitPhaseMeterThingModelIdParamTypeId);
|
||||||
m_mapIdParamTypeIds.insert(sunspecThreePhaseMeterThingClassId, sunspecThreePhaseMeterThingMapIdParamTypeId);
|
m_modelIdParamTypeIds.insert(sunspecThreePhaseMeterThingClassId, sunspecThreePhaseMeterThingModelIdParamTypeId);
|
||||||
|
|
||||||
m_modbusAddressParamTypeIds.insert(sunspecSinglePhaseInverterThingClassId, sunspecSinglePhaseInverterThingModbusAddressParamTypeId);
|
m_modbusAddressParamTypeIds.insert(sunspecSinglePhaseInverterThingClassId, sunspecSinglePhaseInverterThingModbusAddressParamTypeId);
|
||||||
m_modbusAddressParamTypeIds.insert(sunspecSplitPhaseInverterThingClassId, sunspecSplitPhaseInverterThingModbusAddressParamTypeId);
|
m_modbusAddressParamTypeIds.insert(sunspecSplitPhaseInverterThingClassId, sunspecSplitPhaseInverterThingModbusAddressParamTypeId);
|
||||||
@ -98,17 +98,17 @@ void IntegrationPluginSunSpec::setupThing(ThingSetupInfo *info)
|
|||||||
|
|
||||||
QHostAddress address = QHostAddress(info->thing()->paramValue(sunspecConnectionThingIpAddressParamTypeId).toString());
|
QHostAddress address = QHostAddress(info->thing()->paramValue(sunspecConnectionThingIpAddressParamTypeId).toString());
|
||||||
int port = info->thing()->paramValue(sunspecConnectionThingPortParamTypeId).toInt();
|
int port = info->thing()->paramValue(sunspecConnectionThingPortParamTypeId).toInt();
|
||||||
//int slaveId = info->thing()->paramValue(sunspecConnectionThingSlaveIdParamTypeId).toInt();
|
int slaveId = info->thing()->paramValue(sunspecConnectionThingSlaveIdParamTypeId).toInt();
|
||||||
|
|
||||||
SunSpec *sunSpec;
|
|
||||||
if (m_sunSpecConnections.contains(thing->id())) {
|
if (m_sunSpecConnections.contains(thing->id())) {
|
||||||
qCDebug(dcSunSpec()) << "Reconfigure SunSpec connection with new address" << address;
|
qCDebug(dcSunSpec()) << "Reconfigure SunSpec connection with new address" << address;
|
||||||
sunSpec = m_sunSpecConnections.value(thing->id());
|
m_sunSpecConnections.take(thing->id())->deleteLater();
|
||||||
sunSpec->setHostAddress(address);
|
|
||||||
} else {
|
|
||||||
sunSpec = new SunSpec(address, port, this);
|
|
||||||
m_sunSpecConnections.insert(thing->id(), sunSpec);
|
|
||||||
}
|
}
|
||||||
|
SunSpec *sunSpec;
|
||||||
|
sunSpec = new SunSpec(address, port, slaveId, this);
|
||||||
|
sunSpec->setTimeout(configValue(sunSpecPluginTimeoutParamTypeId).toUInt());
|
||||||
|
sunSpec->setNumberOfRetries(configValue(sunSpecPluginNumberOfRetriesParamTypeId).toUInt());
|
||||||
|
m_sunSpecConnections.insert(thing->id(), sunSpec);
|
||||||
|
|
||||||
if (!sunSpec->connectModbus()) {
|
if (!sunSpec->connectModbus()) {
|
||||||
qCWarning(dcSunSpec()) << "Error connecting to SunSpec device";
|
qCWarning(dcSunSpec()) << "Error connecting to SunSpec device";
|
||||||
@ -127,9 +127,9 @@ void IntegrationPluginSunSpec::setupThing(ThingSetupInfo *info)
|
|||||||
connect(sunSpec, &SunSpec::destroyed, [this, thing] {
|
connect(sunSpec, &SunSpec::destroyed, [this, thing] {
|
||||||
m_sunSpecConnections.remove(thing->id());
|
m_sunSpecConnections.remove(thing->id());
|
||||||
});
|
});
|
||||||
connect(sunSpec, &SunSpec::foundModbusMap, this, &IntegrationPluginSunSpec::onFoundModbusMap);
|
connect(sunSpec, &SunSpec::foundSunSpecModel, this, &IntegrationPluginSunSpec::onFoundSunSpecModel);
|
||||||
connect(sunSpec, &SunSpec::modbusMapSearchFinished, this, &IntegrationPluginSunSpec::onModbusMapSearchFinished);
|
connect(sunSpec, &SunSpec::sunspecModelSearchFinished, this, &IntegrationPluginSunSpec::onSunSpecModelSearchFinished);
|
||||||
connect(sunSpec, &SunSpec::commonMapReceived, thing, [thing] (const QString &manufacturer, const QString &deviceModel, const QString &serielNumber) {
|
connect(sunSpec, &SunSpec::commonModelReceived, thing, [thing] (const QString &manufacturer, const QString &deviceModel, const QString &serielNumber) {
|
||||||
thing->setStateValue(sunspecConnectionConnectedStateTypeId, true);
|
thing->setStateValue(sunspecConnectionConnectedStateTypeId, true);
|
||||||
thing->setStateValue(sunspecConnectionManufacturerStateTypeId, manufacturer);
|
thing->setStateValue(sunspecConnectionManufacturerStateTypeId, manufacturer);
|
||||||
thing->setStateValue(sunspecConnectionDeviceModelStateTypeId, deviceModel);
|
thing->setStateValue(sunspecConnectionDeviceModelStateTypeId, deviceModel);
|
||||||
@ -140,14 +140,14 @@ void IntegrationPluginSunSpec::setupThing(ThingSetupInfo *info)
|
|||||||
thing->thingClassId() == sunspecSplitPhaseInverterThingClassId ||
|
thing->thingClassId() == sunspecSplitPhaseInverterThingClassId ||
|
||||||
thing->thingClassId() == sunspecSinglePhaseInverterThingClassId ) {
|
thing->thingClassId() == sunspecSinglePhaseInverterThingClassId ) {
|
||||||
|
|
||||||
uint mapId = thing->paramValue(m_mapIdParamTypeIds.value(thing->thingClassId())).toInt();
|
uint modelId = thing->paramValue(m_modelIdParamTypeIds.value(thing->thingClassId())).toInt();
|
||||||
int modbusAddress = thing->paramValue(m_modbusAddressParamTypeIds.value(thing->thingClassId())).toInt();
|
int modbusAddress = thing->paramValue(m_modbusAddressParamTypeIds.value(thing->thingClassId())).toInt();
|
||||||
SunSpec *connection = m_sunSpecConnections.value(thing->parentId());
|
SunSpec *connection = m_sunSpecConnections.value(thing->parentId());
|
||||||
if (!connection) {
|
if (!connection) {
|
||||||
qCWarning(dcSunSpec()) << "Could not find SunSpec connection";
|
qCWarning(dcSunSpec()) << "Could not find SunSpec connection";
|
||||||
return info->finish(Thing::ThingErrorHardwareNotAvailable);
|
return info->finish(Thing::ThingErrorHardwareNotAvailable);
|
||||||
}
|
}
|
||||||
SunSpecInverter *sunSpecInverter = new SunSpecInverter(connection, SunSpec::BlockId(mapId), modbusAddress);
|
SunSpecInverter *sunSpecInverter = new SunSpecInverter(connection, SunSpec::ModelId(modelId), modbusAddress);
|
||||||
sunSpecInverter->init();
|
sunSpecInverter->init();
|
||||||
connect(sunSpecInverter, &SunSpecInverter::initFinished, info, [this, sunSpecInverter, info] (bool success){
|
connect(sunSpecInverter, &SunSpecInverter::initFinished, info, [this, sunSpecInverter, info] (bool success){
|
||||||
qCDebug(dcSunSpec()) << "Modbus Inverter init finished, success:" << success;
|
qCDebug(dcSunSpec()) << "Modbus Inverter init finished, success:" << success;
|
||||||
@ -167,14 +167,14 @@ void IntegrationPluginSunSpec::setupThing(ThingSetupInfo *info)
|
|||||||
thing->thingClassId() == sunspecSplitPhaseMeterThingClassId ||
|
thing->thingClassId() == sunspecSplitPhaseMeterThingClassId ||
|
||||||
thing->thingClassId() == sunspecThreePhaseMeterThingClassId) {
|
thing->thingClassId() == sunspecThreePhaseMeterThingClassId) {
|
||||||
|
|
||||||
uint mapId = thing->paramValue(m_mapIdParamTypeIds.value(thing->thingClassId())).toInt();
|
uint modelId = thing->paramValue(m_modelIdParamTypeIds.value(thing->thingClassId())).toInt();
|
||||||
int modbusAddress = thing->paramValue(m_modbusAddressParamTypeIds.value(thing->thingClassId())).toInt();
|
int modbusAddress = thing->paramValue(m_modbusAddressParamTypeIds.value(thing->thingClassId())).toInt();
|
||||||
SunSpec *connection = m_sunSpecConnections.value(thing->parentId());
|
SunSpec *connection = m_sunSpecConnections.value(thing->parentId());
|
||||||
if (!connection) {
|
if (!connection) {
|
||||||
qCWarning(dcSunSpec()) << "Could not find SunSpec connection";
|
qCWarning(dcSunSpec()) << "Could not find SunSpec connection";
|
||||||
return info->finish(Thing::ThingErrorHardwareNotAvailable);
|
return info->finish(Thing::ThingErrorHardwareNotAvailable);
|
||||||
}
|
}
|
||||||
SunSpecMeter *sunSpecMeter = new SunSpecMeter(connection, SunSpec::BlockId(mapId), modbusAddress);
|
SunSpecMeter *sunSpecMeter = new SunSpecMeter(connection, SunSpec::ModelId(modelId), modbusAddress);
|
||||||
sunSpecMeter->init();
|
sunSpecMeter->init();
|
||||||
connect(sunSpecMeter, &SunSpecMeter::initFinished, info, [this, sunSpecMeter, info] (bool success){
|
connect(sunSpecMeter, &SunSpecMeter::initFinished, info, [this, sunSpecMeter, info] (bool success){
|
||||||
qCDebug(dcSunSpec()) << "Modbus meter init finished, success:" << success;
|
qCDebug(dcSunSpec()) << "Modbus meter init finished, success:" << success;
|
||||||
@ -192,6 +192,28 @@ void IntegrationPluginSunSpec::setupThing(ThingSetupInfo *info)
|
|||||||
|
|
||||||
} else if (info->thing()->thingClassId() == sunspecStorageThingClassId) {
|
} else if (info->thing()->thingClassId() == sunspecStorageThingClassId) {
|
||||||
|
|
||||||
|
uint modelId = thing->paramValue(m_modelIdParamTypeIds.value(thing->thingClassId())).toInt();
|
||||||
|
int modbusAddress = thing->paramValue(m_modbusAddressParamTypeIds.value(thing->thingClassId())).toInt();
|
||||||
|
SunSpec *connection = m_sunSpecConnections.value(thing->parentId());
|
||||||
|
if (!connection) {
|
||||||
|
qCWarning(dcSunSpec()) << "Could not find SunSpec connection";
|
||||||
|
return info->finish(Thing::ThingErrorHardwareNotAvailable);
|
||||||
|
}
|
||||||
|
SunSpecStorage *sunSpecStorage = new SunSpecStorage(connection, SunSpec::ModelId(modelId), modbusAddress);
|
||||||
|
sunSpecStorage->init();
|
||||||
|
connect(sunSpecStorage, &SunSpecStorage::initFinished, info, [this, sunSpecStorage, info] (bool success){
|
||||||
|
qCDebug(dcSunSpec()) << "Modbus storage init finished, success:" << success;
|
||||||
|
if (success) {
|
||||||
|
m_sunSpecStorages.insert(info->thing(), sunSpecStorage);
|
||||||
|
info->finish(Thing::ThingErrorNoError);
|
||||||
|
} else {
|
||||||
|
info->finish(Thing::ThingErrorHardwareNotAvailable);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(info, &ThingSetupInfo::aborted, sunSpecStorage, &SunSpecStorage::deleteLater);
|
||||||
|
connect(sunSpecStorage, &SunSpecStorage::destroyed, thing, [thing, this] {m_sunSpecStorages.remove(thing);});
|
||||||
|
connect(sunSpecStorage, &SunSpecStorage::storageDataReceived, this, &IntegrationPluginSunSpec::onStorageDataReceived);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Q_ASSERT_X(false, "setupThing", QString("Unhandled thingClassId: %1").arg(info->thing()->thingClassId().toString()).toUtf8());
|
Q_ASSERT_X(false, "setupThing", QString("Unhandled thingClassId: %1").arg(info->thing()->thingClassId().toString()).toUtf8());
|
||||||
@ -215,8 +237,8 @@ void IntegrationPluginSunSpec::postSetupThing(Thing *thing)
|
|||||||
qCDebug(dcSunSpec()) << "SunSpecConnection not found";
|
qCDebug(dcSunSpec()) << "SunSpecConnection not found";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
connection->readCommonMap();
|
connection->readCommonModel();
|
||||||
connection->findModbusMap(QList<SunSpec::BlockId>()); // Discover all maps, without filter
|
connection->findSunSpecModels(QList<SunSpec::ModelId>()); // Discover all models, without filter
|
||||||
|
|
||||||
} else if (thing->thingClassId() == sunspecSinglePhaseInverterThingClassId ||
|
} else if (thing->thingClassId() == sunspecSinglePhaseInverterThingClassId ||
|
||||||
thing->thingClassId() == sunspecSplitPhaseInverterThingClassId ||
|
thing->thingClassId() == sunspecSplitPhaseInverterThingClassId ||
|
||||||
@ -227,7 +249,7 @@ void IntegrationPluginSunSpec::postSetupThing(Thing *thing)
|
|||||||
qCDebug(dcSunSpec()) << "SunSpecInverter not found";
|
qCDebug(dcSunSpec()) << "SunSpecInverter not found";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sunSpecInverter->getInverterMap();
|
sunSpecInverter->getInverterModelDataBlock();
|
||||||
|
|
||||||
} else if (thing->thingClassId() == sunspecSinglePhaseMeterThingClassId ||
|
} else if (thing->thingClassId() == sunspecSinglePhaseMeterThingClassId ||
|
||||||
thing->thingClassId() == sunspecSplitPhaseMeterThingClassId ||
|
thing->thingClassId() == sunspecSplitPhaseMeterThingClassId ||
|
||||||
@ -238,7 +260,7 @@ void IntegrationPluginSunSpec::postSetupThing(Thing *thing)
|
|||||||
qCDebug(dcSunSpec()) << "SunSpecMeter not found";
|
qCDebug(dcSunSpec()) << "SunSpecMeter not found";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sunSpecMeter->getMeterMap();
|
sunSpecMeter->getMeterModelDataBlock();
|
||||||
|
|
||||||
} else if (thing->thingClassId() == sunspecStorageThingClassId) {
|
} else if (thing->thingClassId() == sunspecStorageThingClassId) {
|
||||||
SunSpecStorage *sunSpecStorage = m_sunSpecStorages.value(thing);
|
SunSpecStorage *sunSpecStorage = m_sunSpecStorages.value(thing);
|
||||||
@ -246,7 +268,7 @@ void IntegrationPluginSunSpec::postSetupThing(Thing *thing)
|
|||||||
qCDebug(dcSunSpec()) << "SunSpecStorage not found";
|
qCDebug(dcSunSpec()) << "SunSpecStorage not found";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sunSpecStorage->getStorageMap();
|
sunSpecStorage->getStorageModelDataBlock();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Q_ASSERT_X(false, "postSetupThing", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8());
|
Q_ASSERT_X(false, "postSetupThing", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8());
|
||||||
@ -373,11 +395,11 @@ void IntegrationPluginSunSpec::executeAction(ThingActionInfo *info)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IntegrationPluginSunSpec::checkIfThingExists(uint mapId, uint modbusAddress)
|
bool IntegrationPluginSunSpec::checkIfThingExists(uint modelId, uint modbusAddress)
|
||||||
{
|
{
|
||||||
Q_FOREACH(Thing *thing, myThings()) {
|
Q_FOREACH(Thing *thing, myThings()) {
|
||||||
if (thing->paramValue(m_mapIdParamTypeIds.value(thing->thingClassId())).toUInt() == mapId &&
|
if (thing->paramValue(m_modelIdParamTypeIds.value(thing->thingClassId())).toUInt() == modelId &&
|
||||||
thing->paramValue(m_modbusAddressParamTypeIds.value(thing->thingClassId())).toUInt() == modbusAddress) {
|
thing->paramValue(m_modbusAddressParamTypeIds.value(thing->thingClassId())).toUInt() == modbusAddress) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -387,16 +409,16 @@ bool IntegrationPluginSunSpec::checkIfThingExists(uint mapId, uint modbusAddress
|
|||||||
void IntegrationPluginSunSpec::onRefreshTimer()
|
void IntegrationPluginSunSpec::onRefreshTimer()
|
||||||
{
|
{
|
||||||
foreach (SunSpec *connection, m_sunSpecConnections) {
|
foreach (SunSpec *connection, m_sunSpecConnections) {
|
||||||
connection->readCommonMap(); //check connection
|
connection->readCommonModel(); //check connection
|
||||||
}
|
}
|
||||||
foreach (SunSpecInverter *inverter, m_sunSpecInverters) {
|
foreach (SunSpecInverter *inverter, m_sunSpecInverters) {
|
||||||
inverter->getInverterMap();
|
inverter->getInverterModelDataBlock();
|
||||||
}
|
}
|
||||||
foreach (SunSpecMeter *meter, m_sunSpecMeters) {
|
foreach (SunSpecMeter *meter, m_sunSpecMeters) {
|
||||||
meter->getMeterMap();
|
meter->getMeterModelDataBlock();
|
||||||
}
|
}
|
||||||
foreach (SunSpecStorage *storage, m_sunSpecStorages) {
|
foreach (SunSpecStorage *storage, m_sunSpecStorages) {
|
||||||
storage->getStorageMap();
|
storage->getStorageModelDataBlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,6 +432,18 @@ void IntegrationPluginSunSpec::onPluginConfigurationChanged(const ParamTypeId &p
|
|||||||
m_refreshTimer->stop();
|
m_refreshTimer->stop();
|
||||||
m_refreshTimer->startTimer(refreshTime);
|
m_refreshTimer->startTimer(refreshTime);
|
||||||
}
|
}
|
||||||
|
} else if (paramTypeId == sunSpecPluginNumberOfRetriesParamTypeId) {
|
||||||
|
qCDebug(dcSunSpec()) << "Updating number of retires" << value.toUInt();
|
||||||
|
Q_FOREACH(SunSpec *connection, m_sunSpecConnections) {
|
||||||
|
connection->setNumberOfRetries(value.toUInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (paramTypeId == sunSpecPluginTimeoutParamTypeId) {
|
||||||
|
qCDebug(dcSunSpec()) << "Updating timeout" << value.toUInt() << "[ms]";
|
||||||
|
Q_FOREACH(SunSpec *connection, m_sunSpecConnections) {
|
||||||
|
connection->setTimeout(value.toUInt());
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcSunSpec()) << "Unknown plugin configuration" << paramTypeId << "Value" << value;
|
qCWarning(dcSunSpec()) << "Unknown plugin configuration" << paramTypeId << "Value" << value;
|
||||||
}
|
}
|
||||||
@ -431,23 +465,7 @@ void IntegrationPluginSunSpec::onConnectionStateChanged(bool status)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntegrationPluginSunSpec::onMapHeaderReceived(uint modbusAddress, SunSpec::BlockId mapId, uint mapLength)
|
void IntegrationPluginSunSpec::onFoundSunSpecModel(SunSpec::ModelId modelId, int modbusStartRegister)
|
||||||
{
|
|
||||||
qCDebug(dcSunSpec()) << "On map header received" << modbusAddress << mapId << mapLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntegrationPluginSunSpec::onMapReceived(SunSpec::BlockId mapId, uint mapLength, QVector<quint16> data)
|
|
||||||
{
|
|
||||||
Q_UNUSED(data)
|
|
||||||
SunSpec *connection = static_cast<SunSpec *>(sender());
|
|
||||||
Thing *thing = myThings().findById(m_sunSpecConnections.key(connection));
|
|
||||||
if (!thing)
|
|
||||||
return;
|
|
||||||
|
|
||||||
qCDebug(dcSunSpec()) << "On map received" << mapId << "Map length" << mapLength << "Thing:" << thing->name();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntegrationPluginSunSpec::onFoundModbusMap(SunSpec::BlockId mapId, int modbusStartRegister)
|
|
||||||
{
|
{
|
||||||
SunSpec *connection = static_cast<SunSpec *>(sender());
|
SunSpec *connection = static_cast<SunSpec *>(sender());
|
||||||
Thing *thing = myThings().findById(m_sunSpecConnections.key(connection));
|
Thing *thing = myThings().findById(m_sunSpecConnections.key(connection));
|
||||||
@ -456,71 +474,71 @@ void IntegrationPluginSunSpec::onFoundModbusMap(SunSpec::BlockId mapId, int modb
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qCDebug(dcSunSpec()) << "On map received" << mapId << "Map length" << modbusStartRegister << "Thing:" << thing->name();
|
qCDebug(dcSunSpec()) << "On model received" << modelId << "length" << modbusStartRegister << "Thing:" << thing->name();
|
||||||
if (checkIfThingExists(mapId, modbusStartRegister)) {
|
if (checkIfThingExists(modelId, modbusStartRegister)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QString model = thing->stateValue(sunspecConnectionDeviceModelStateTypeId).toString();
|
QString model = thing->stateValue(sunspecConnectionDeviceModelStateTypeId).toString();
|
||||||
switch (mapId) {
|
switch (modelId) {
|
||||||
case SunSpec::BlockId::BlockIdInverterSinglePhase:
|
case SunSpec::ModelId::ModelIdInverterSinglePhase:
|
||||||
case SunSpec::BlockId::BlockIdInverterSinglePhaseFloat: {
|
case SunSpec::ModelId::ModelIdInverterSinglePhaseFloat: {
|
||||||
ThingDescriptor descriptor(sunspecSinglePhaseInverterThingClassId, model+tr(" single phase inverter"), "", thing->id());
|
ThingDescriptor descriptor(sunspecSinglePhaseInverterThingClassId, model+tr(" single phase inverter"), "", thing->id());
|
||||||
ParamList params;
|
ParamList params;
|
||||||
params.append(Param(sunspecSinglePhaseInverterThingMapIdParamTypeId, mapId));
|
params.append(Param(sunspecSinglePhaseInverterThingModelIdParamTypeId, modelId));
|
||||||
params.append(Param(sunspecSinglePhaseInverterThingModbusAddressParamTypeId, modbusStartRegister));
|
params.append(Param(sunspecSinglePhaseInverterThingModbusAddressParamTypeId, modbusStartRegister));
|
||||||
descriptor.setParams(params);
|
descriptor.setParams(params);
|
||||||
emit autoThingsAppeared({descriptor});
|
emit autoThingsAppeared({descriptor});
|
||||||
} break;
|
} break;
|
||||||
case SunSpec::BlockId::BlockIdInverterSplitPhase:
|
case SunSpec::ModelId::ModelIdInverterSplitPhase:
|
||||||
case SunSpec::BlockId::BlockIdInverterSplitPhaseFloat: {
|
case SunSpec::ModelId::ModelIdInverterSplitPhaseFloat: {
|
||||||
ThingDescriptor descriptor(sunspecSplitPhaseInverterThingClassId, model+tr(" split phase inverter"), "", thing->id());
|
ThingDescriptor descriptor(sunspecSplitPhaseInverterThingClassId, model+tr(" split phase inverter"), "", thing->id());
|
||||||
ParamList params;
|
ParamList params;
|
||||||
params.append(Param(sunspecSplitPhaseInverterThingMapIdParamTypeId, mapId));
|
params.append(Param(sunspecSplitPhaseInverterThingModelIdParamTypeId, modelId));
|
||||||
params.append(Param(sunspecSplitPhaseInverterThingModbusAddressParamTypeId, modbusStartRegister));
|
params.append(Param(sunspecSplitPhaseInverterThingModbusAddressParamTypeId, modbusStartRegister));
|
||||||
descriptor.setParams(params);
|
descriptor.setParams(params);
|
||||||
emit autoThingsAppeared({descriptor});
|
emit autoThingsAppeared({descriptor});
|
||||||
} break;
|
} break;
|
||||||
case SunSpec::BlockId::BlockIdInverterThreePhase:
|
case SunSpec::ModelId::ModelIdInverterThreePhase:
|
||||||
case SunSpec::BlockId::BlockIdInverterThreePhaseFloat: {
|
case SunSpec::ModelId::ModelIdInverterThreePhaseFloat: {
|
||||||
ThingDescriptor descriptor(sunspecThreePhaseInverterThingClassId, model+tr(" three phase inverter"), "", thing->id());
|
ThingDescriptor descriptor(sunspecThreePhaseInverterThingClassId, model+tr(" three phase inverter"), "", thing->id());
|
||||||
ParamList params;
|
ParamList params;
|
||||||
params.append(Param(sunspecThreePhaseInverterThingMapIdParamTypeId, mapId));
|
params.append(Param(sunspecThreePhaseInverterThingModelIdParamTypeId, modelId));
|
||||||
params.append(Param(sunspecThreePhaseInverterThingModbusAddressParamTypeId, modbusStartRegister));
|
params.append(Param(sunspecThreePhaseInverterThingModbusAddressParamTypeId, modbusStartRegister));
|
||||||
descriptor.setParams(params);
|
descriptor.setParams(params);
|
||||||
emit autoThingsAppeared({descriptor});
|
emit autoThingsAppeared({descriptor});
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case SunSpec::BlockIdSinglePhaseMeter:
|
case SunSpec::ModelIdSinglePhaseMeter:
|
||||||
case SunSpec::BlockIdSinglePhaseMeterFloat: {
|
case SunSpec::ModelIdSinglePhaseMeterFloat: {
|
||||||
ThingDescriptor descriptor(sunspecSinglePhaseMeterThingClassId, model+tr(" Meter"), "", thing->id());
|
ThingDescriptor descriptor(sunspecSinglePhaseMeterThingClassId, model+tr(" Meter"), "", thing->id());
|
||||||
ParamList params;
|
ParamList params;
|
||||||
params.append(Param(sunspecSinglePhaseMeterThingMapIdParamTypeId, mapId));
|
params.append(Param(sunspecSinglePhaseMeterThingModelIdParamTypeId, modelId));
|
||||||
params.append(Param(sunspecSinglePhaseMeterThingModbusAddressParamTypeId, modbusStartRegister));
|
params.append(Param(sunspecSinglePhaseMeterThingModbusAddressParamTypeId, modbusStartRegister));
|
||||||
descriptor.setParams(params);
|
descriptor.setParams(params);
|
||||||
emit autoThingsAppeared({descriptor});
|
emit autoThingsAppeared({descriptor});
|
||||||
} break;
|
} break;
|
||||||
case SunSpec::BlockIdSplitSinglePhaseMeter:
|
case SunSpec::ModelIdSplitSinglePhaseMeter:
|
||||||
case SunSpec::BlockIdSplitSinglePhaseMeterFloat: {
|
case SunSpec::ModelIdSplitSinglePhaseMeterFloat: {
|
||||||
ThingDescriptor descriptor(sunspecSplitPhaseMeterThingClassId, model+tr(" Meter"), "", thing->id());
|
ThingDescriptor descriptor(sunspecSplitPhaseMeterThingClassId, model+tr(" Meter"), "", thing->id());
|
||||||
ParamList params;
|
ParamList params;
|
||||||
params.append(Param(sunspecSplitPhaseMeterThingMapIdParamTypeId, mapId));
|
params.append(Param(sunspecSplitPhaseMeterThingModelIdParamTypeId, modelId));
|
||||||
params.append(Param(sunspecSplitPhaseMeterThingModbusAddressParamTypeId, modbusStartRegister));
|
params.append(Param(sunspecSplitPhaseMeterThingModbusAddressParamTypeId, modbusStartRegister));
|
||||||
descriptor.setParams(params);
|
descriptor.setParams(params);
|
||||||
emit autoThingsAppeared({descriptor});
|
emit autoThingsAppeared({descriptor});
|
||||||
} break;
|
} break;
|
||||||
case SunSpec::BlockIdWyeConnectThreePhaseMeterFloat:
|
case SunSpec::ModelIdWyeConnectThreePhaseMeterFloat:
|
||||||
case SunSpec::BlockIdDeltaConnectThreePhaseMeterFloat: {
|
case SunSpec::ModelIdDeltaConnectThreePhaseMeterFloat: {
|
||||||
ThingDescriptor descriptor(sunspecThreePhaseMeterThingClassId, model+" Meter", "", thing->id());
|
ThingDescriptor descriptor(sunspecThreePhaseMeterThingClassId, model+" Meter", "", thing->id());
|
||||||
ParamList params;
|
ParamList params;
|
||||||
params.append(Param(sunspecThreePhaseMeterThingMapIdParamTypeId, mapId));
|
params.append(Param(sunspecThreePhaseMeterThingModelIdParamTypeId, modelId));
|
||||||
params.append(Param(sunspecThreePhaseMeterThingModbusAddressParamTypeId, modbusStartRegister));
|
params.append(Param(sunspecThreePhaseMeterThingModbusAddressParamTypeId, modbusStartRegister));
|
||||||
descriptor.setParams(params);
|
descriptor.setParams(params);
|
||||||
emit autoThingsAppeared({descriptor});
|
emit autoThingsAppeared({descriptor});
|
||||||
} break;
|
} break;
|
||||||
case SunSpec::BlockIdStorage: {
|
case SunSpec::ModelIdStorage: {
|
||||||
ThingDescriptor descriptor(sunspecStorageThingClassId, model+" Storage", "", thing->id());
|
ThingDescriptor descriptor(sunspecStorageThingClassId, model+" Storage", "", thing->id());
|
||||||
ParamList params;
|
ParamList params;
|
||||||
params.append(Param(sunspecStorageThingMapIdParamTypeId, mapId));
|
params.append(Param(sunspecStorageThingModelIdParamTypeId, modelId));
|
||||||
params.append(Param(sunspecThreePhaseInverterThingModbusAddressParamTypeId, modbusStartRegister));
|
params.append(Param(sunspecThreePhaseInverterThingModbusAddressParamTypeId, modbusStartRegister));
|
||||||
descriptor.setParams(params);
|
descriptor.setParams(params);
|
||||||
emit autoThingsAppeared({descriptor});
|
emit autoThingsAppeared({descriptor});
|
||||||
@ -530,7 +548,7 @@ void IntegrationPluginSunSpec::onFoundModbusMap(SunSpec::BlockId mapId, int modb
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntegrationPluginSunSpec::onModbusMapSearchFinished(const QHash<SunSpec::BlockId, int> &mapIds)
|
void IntegrationPluginSunSpec::onSunSpecModelSearchFinished(const QHash<SunSpec::ModelId, int> &modelIds)
|
||||||
{
|
{
|
||||||
SunSpec *connection = static_cast<SunSpec *>(sender());
|
SunSpec *connection = static_cast<SunSpec *>(sender());
|
||||||
Thing *thing = myThings().findById(m_sunSpecConnections.key(connection));
|
Thing *thing = myThings().findById(m_sunSpecConnections.key(connection));
|
||||||
@ -539,7 +557,7 @@ void IntegrationPluginSunSpec::onModbusMapSearchFinished(const QHash<SunSpec::Bl
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qCDebug(dcSunSpec()) << "On modbus map search finished, maps:" << mapIds.count();
|
qCDebug(dcSunSpec()) << "On sunspec model search finished, models:" << modelIds.count();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -679,6 +697,7 @@ void IntegrationPluginSunSpec::onStorageDataReceived(const SunSpecStorage::Stora
|
|||||||
if(!thing) {
|
if(!thing) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), true);
|
||||||
thing->setStateValue(sunspecStorageStorageStateStateTypeId, storageData.chargingState);
|
thing->setStateValue(sunspecStorageStorageStateStateTypeId, storageData.chargingState);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -688,8 +707,8 @@ void IntegrationPluginSunSpec::onMeterDataReceived(const SunSpecMeter::MeterData
|
|||||||
SunSpecMeter *meter = static_cast<SunSpecMeter *>(sender());
|
SunSpecMeter *meter = static_cast<SunSpecMeter *>(sender());
|
||||||
Thing *thing = m_sunSpecMeters.key(meter);
|
Thing *thing = m_sunSpecMeters.key(meter);
|
||||||
|
|
||||||
if(!thing) {
|
if (!thing) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//thing->setStateValue(sunspecMeterStorageStateStateTypeId, meterData.event);
|
thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), true);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -59,7 +59,7 @@ public:
|
|||||||
void executeAction(ThingActionInfo *info) override;
|
void executeAction(ThingActionInfo *info) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QHash<ThingClassId, ParamTypeId> m_mapIdParamTypeIds;
|
QHash<ThingClassId, ParamTypeId> m_modelIdParamTypeIds;
|
||||||
QHash<ThingClassId, ParamTypeId> m_modbusAddressParamTypeIds;
|
QHash<ThingClassId, ParamTypeId> m_modbusAddressParamTypeIds;
|
||||||
|
|
||||||
QHash<ThingClassId, StateTypeId> m_connectedStateTypeIds;
|
QHash<ThingClassId, StateTypeId> m_connectedStateTypeIds;
|
||||||
@ -77,7 +77,7 @@ private:
|
|||||||
QHash<Thing *, SunSpecStorage *> m_sunSpecStorages;
|
QHash<Thing *, SunSpecStorage *> m_sunSpecStorages;
|
||||||
QHash<Thing *, SunSpecMeter *> m_sunSpecMeters;
|
QHash<Thing *, SunSpecMeter *> m_sunSpecMeters;
|
||||||
|
|
||||||
bool checkIfThingExists(uint mapId, uint modbusAddress);
|
bool checkIfThingExists(uint modelId, uint modbusAddress);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onRefreshTimer();
|
void onRefreshTimer();
|
||||||
@ -86,11 +86,8 @@ private slots:
|
|||||||
|
|
||||||
void onConnectionStateChanged(bool status);
|
void onConnectionStateChanged(bool status);
|
||||||
|
|
||||||
void onMapHeaderReceived(uint modbusAddress, SunSpec::BlockId mapId, uint mapLength);
|
void onFoundSunSpecModel(SunSpec::ModelId modelId, int modbusStartRegister);
|
||||||
void onMapReceived(SunSpec::BlockId mapId, uint mapLength, QVector<quint16> data);
|
void onSunSpecModelSearchFinished(const QHash<SunSpec::ModelId, int> &modelIds);
|
||||||
|
|
||||||
void onFoundModbusMap(SunSpec::BlockId mapId, int modbusStartRegister);
|
|
||||||
void onModbusMapSearchFinished(const QHash<SunSpec::BlockId, int> &mapIds);
|
|
||||||
|
|
||||||
void onWriteRequestExecuted(QUuid requestId, bool success);
|
void onWriteRequestExecuted(QUuid requestId, bool success);
|
||||||
void onWriteRequestError(QUuid requestId, const QString &error);
|
void onWriteRequestError(QUuid requestId, const QString &error);
|
||||||
@ -99,6 +96,5 @@ private slots:
|
|||||||
void onStorageDataReceived(const SunSpecStorage::StorageData &storageData);
|
void onStorageDataReceived(const SunSpecStorage::StorageData &storageData);
|
||||||
void onMeterDataReceived(const SunSpecMeter::MeterData &meterData);
|
void onMeterDataReceived(const SunSpecMeter::MeterData &meterData);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // INTEGRATIONPLUGINSUNSPEC_H
|
#endif // INTEGRATIONPLUGINSUNSPEC_H
|
||||||
|
|
||||||
|
|||||||
@ -37,7 +37,7 @@
|
|||||||
"thingClasses": [
|
"thingClasses": [
|
||||||
{
|
{
|
||||||
"name": "sunspecConnection",
|
"name": "sunspecConnection",
|
||||||
"displayName": "SunSpec Device",
|
"displayName": "SunSpec connection",
|
||||||
"id": "f51853f3-8815-4cf3-b337-45cda1f3e6d5",
|
"id": "f51853f3-8815-4cf3-b337-45cda1f3e6d5",
|
||||||
"createMethods": [ "User" ],
|
"createMethods": [ "User" ],
|
||||||
"interfaces": ["connectable"],
|
"interfaces": ["connectable"],
|
||||||
@ -109,8 +109,8 @@
|
|||||||
"paramTypes": [
|
"paramTypes": [
|
||||||
{
|
{
|
||||||
"id": "41715d00-a947-4f43-a475-cea05790e01d",
|
"id": "41715d00-a947-4f43-a475-cea05790e01d",
|
||||||
"name":"mapId",
|
"name":"modelId",
|
||||||
"displayName": "Map id",
|
"displayName": "Model",
|
||||||
"type": "int",
|
"type": "int",
|
||||||
"readOnly": true
|
"readOnly": true
|
||||||
},
|
},
|
||||||
@ -243,8 +243,8 @@
|
|||||||
"paramTypes": [
|
"paramTypes": [
|
||||||
{
|
{
|
||||||
"id": "c42fb50e-210f-4b53-88eb-fa216e15f88f",
|
"id": "c42fb50e-210f-4b53-88eb-fa216e15f88f",
|
||||||
"name":"mapId",
|
"name":"modelId",
|
||||||
"displayName": "Map id",
|
"displayName": "Model",
|
||||||
"type": "int",
|
"type": "int",
|
||||||
"readOnly": true
|
"readOnly": true
|
||||||
},
|
},
|
||||||
@ -404,8 +404,8 @@
|
|||||||
"paramTypes": [
|
"paramTypes": [
|
||||||
{
|
{
|
||||||
"id": "8d5b2b58-ce46-406d-844e-f53136afcf09",
|
"id": "8d5b2b58-ce46-406d-844e-f53136afcf09",
|
||||||
"name":"mapId",
|
"name":"modelId",
|
||||||
"displayName": "Map id",
|
"displayName": "Model",
|
||||||
"type": "int",
|
"type": "int",
|
||||||
"readOnly": true
|
"readOnly": true
|
||||||
},
|
},
|
||||||
@ -583,8 +583,8 @@
|
|||||||
"paramTypes": [
|
"paramTypes": [
|
||||||
{
|
{
|
||||||
"id": "7d6fcafb-c62e-4a21-aae2-f4041c487149",
|
"id": "7d6fcafb-c62e-4a21-aae2-f4041c487149",
|
||||||
"name":"mapId",
|
"name":"modelId",
|
||||||
"displayName": "Map id",
|
"displayName": "Model",
|
||||||
"type": "int",
|
"type": "int",
|
||||||
"readOnly": true,
|
"readOnly": true,
|
||||||
"defaultValue": 0
|
"defaultValue": 0
|
||||||
@ -682,8 +682,8 @@
|
|||||||
"paramTypes": [
|
"paramTypes": [
|
||||||
{
|
{
|
||||||
"id": "89aeec6d-abeb-48b5-9594-214ad5db2d03",
|
"id": "89aeec6d-abeb-48b5-9594-214ad5db2d03",
|
||||||
"name":"mapId",
|
"name":"modelId",
|
||||||
"displayName": "Map id",
|
"displayName": "Model",
|
||||||
"type": "int",
|
"type": "int",
|
||||||
"readOnly": true,
|
"readOnly": true,
|
||||||
"defaultValue": 0
|
"defaultValue": 0
|
||||||
@ -808,8 +808,8 @@
|
|||||||
"paramTypes": [
|
"paramTypes": [
|
||||||
{
|
{
|
||||||
"id": "a1960821-155c-4176-86fa-974429039182",
|
"id": "a1960821-155c-4176-86fa-974429039182",
|
||||||
"name":"mapId",
|
"name":"modelId",
|
||||||
"displayName": "Map id",
|
"displayName": "Model",
|
||||||
"type": "int",
|
"type": "int",
|
||||||
"readOnly": true,
|
"readOnly": true,
|
||||||
"defaultValue": 0
|
"defaultValue": 0
|
||||||
@ -952,8 +952,8 @@
|
|||||||
"paramTypes": [
|
"paramTypes": [
|
||||||
{
|
{
|
||||||
"id": "219beb96-b9fe-4dd2-a386-ecfbbab8786d",
|
"id": "219beb96-b9fe-4dd2-a386-ecfbbab8786d",
|
||||||
"name":"mapId",
|
"name":"modelId",
|
||||||
"displayName": "Map id",
|
"displayName": "Model",
|
||||||
"type": "int",
|
"type": "int",
|
||||||
"readOnly": true,
|
"readOnly": true,
|
||||||
"defaultValue": 0
|
"defaultValue": 0
|
||||||
|
|||||||
@ -32,10 +32,11 @@
|
|||||||
#include "extern-plugininfo.h"
|
#include "extern-plugininfo.h"
|
||||||
#include <QtEndian>
|
#include <QtEndian>
|
||||||
|
|
||||||
SunSpec::SunSpec(const QHostAddress &hostAddress, uint port, QObject *parent) :
|
SunSpec::SunSpec(const QHostAddress &hostAddress, uint port, uint slaveId, QObject *parent) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
m_hostAddress(hostAddress),
|
m_hostAddress(hostAddress),
|
||||||
m_port(port)
|
m_port(port),
|
||||||
|
m_slaveId(slaveId)
|
||||||
{
|
{
|
||||||
qCDebug(dcSunSpec()) << "SunSpec: Creating SunSpec connection";
|
qCDebug(dcSunSpec()) << "SunSpec: Creating SunSpec connection";
|
||||||
m_modbusTcpClient = new QModbusTcpClient(this);
|
m_modbusTcpClient = new QModbusTcpClient(this);
|
||||||
@ -143,8 +144,8 @@ void SunSpec::findBaseRegister()
|
|||||||
if (reply->error() == QModbusDevice::NoError) {
|
if (reply->error() == QModbusDevice::NoError) {
|
||||||
const QModbusDataUnit unit = reply->result();
|
const QModbusDataUnit unit = reply->result();
|
||||||
if ((unit.value(0) << 16 | unit.value(1)) == 0x53756e53) {
|
if ((unit.value(0) << 16 | unit.value(1)) == 0x53756e53) {
|
||||||
//Well-known value. Uniquely identifies this as a SunSpec Modbus Map
|
//Well-known value. Uniquely identifies this as a SunSpec Modbus model
|
||||||
qCDebug(dcSunSpec()) << "SunSpec: Found start of modbus map" << baseRegister;
|
qCDebug(dcSunSpec()) << "SunSpec: Found start of modbus model" << baseRegister;
|
||||||
m_baseRegister = baseRegister;
|
m_baseRegister = baseRegister;
|
||||||
emit foundBaseRegister(baseRegister);
|
emit foundBaseRegister(baseRegister);
|
||||||
} else {
|
} else {
|
||||||
@ -162,9 +163,9 @@ void SunSpec::findBaseRegister()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SunSpec::findModbusMap(const QList<BlockId> &ids, uint modbusAddressOffset)
|
void SunSpec::findSunSpecModels(const QList<ModelId> &ids, uint modbusAddressOffset)
|
||||||
{
|
{
|
||||||
qCDebug(dcSunSpec()) << "SunSpec: Find modbus map. Start register" << m_baseRegister+modbusAddressOffset;
|
qCDebug(dcSunSpec()) << "SunSpec: Find modbus model. Start register" << m_baseRegister+modbusAddressOffset;
|
||||||
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, m_baseRegister+modbusAddressOffset, 2);
|
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, m_baseRegister+modbusAddressOffset, 2);
|
||||||
|
|
||||||
if (QModbusReply *reply = m_modbusTcpClient->sendReadRequest(request, m_slaveId)) {
|
if (QModbusReply *reply = m_modbusTcpClient->sendReadRequest(request, m_slaveId)) {
|
||||||
@ -175,23 +176,23 @@ void SunSpec::findModbusMap(const QList<BlockId> &ids, uint modbusAddressOffset)
|
|||||||
if (reply->error() == QModbusDevice::NoError) {
|
if (reply->error() == QModbusDevice::NoError) {
|
||||||
const QModbusDataUnit unit = reply->result();
|
const QModbusDataUnit unit = reply->result();
|
||||||
uint modbusAddress = unit.startAddress();
|
uint modbusAddress = unit.startAddress();
|
||||||
BlockId blockId = BlockId(unit.value(0));
|
ModelId modelId = ModelId(unit.value(0));
|
||||||
int blockLength = unit.value(1);
|
int modelLength = unit.value(1);
|
||||||
if (blockId == BlockIdEnd) {
|
if (modelId == ModelIdEnd) {
|
||||||
qCDebug(dcSunSpec()) << "SunSpec: Block Id End";
|
qCDebug(dcSunSpec()) << "SunSpec: Model Id End";
|
||||||
modbusMapSearchFinished(m_mapList);
|
sunspecModelSearchFinished(m_modelList);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ids.isEmpty() || ids.contains(blockId)) {
|
if (ids.isEmpty() || ids.contains(modelId)) {
|
||||||
// If ids is empty then emit all blocks
|
// If ids is empty then emit all models
|
||||||
qCDebug(dcSunSpec()) << "SunSpec: Found block" << BlockId(blockId) << "with block length" << blockLength;
|
qCDebug(dcSunSpec()) << "SunSpec: Found model" << ModelId(modelId) << "with length" << modelLength;
|
||||||
m_mapList.insert(BlockId(blockId), modbusAddress);
|
m_modelList.insert(ModelId(modelId), modbusAddress);
|
||||||
foundModbusMap(BlockId(blockId), modbusAddress);
|
foundSunSpecModel(ModelId(modelId), modbusAddress);
|
||||||
}
|
}
|
||||||
findModbusMap(ids, modbusAddress+2+blockLength-m_baseRegister); //read next block
|
findSunSpecModels(ids, modbusAddress+2+modelLength-m_baseRegister); //read next model
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcSunSpec()) << "SunSpec: Find modbus map, read response error:" << reply->error();
|
qCWarning(dcSunSpec()) << "SunSpec: Find modbus model, read response error:" << reply->error();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -204,9 +205,9 @@ void SunSpec::findModbusMap(const QList<BlockId> &ids, uint modbusAddressOffset)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SunSpec::readMapHeader(uint modbusAddress)
|
void SunSpec::readModelHeader(uint modbusAddress)
|
||||||
{
|
{
|
||||||
qCDebug(dcSunSpec()) << "SunSpec: Read map header, modbus address:" << modbusAddress << "Slave ID" << m_slaveId;
|
qCDebug(dcSunSpec()) << "SunSpec: Read model header, modbus address:" << modbusAddress << "Slave ID" << m_slaveId;
|
||||||
if (modbusAddress == 0 || modbusAddress == 40000 || modbusAddress == 50000)
|
if (modbusAddress == 0 || modbusAddress == 40000 || modbusAddress == 50000)
|
||||||
modbusAddress += 2;
|
modbusAddress += 2;
|
||||||
|
|
||||||
@ -220,34 +221,34 @@ void SunSpec::readMapHeader(uint modbusAddress)
|
|||||||
if (reply->error() == QModbusDevice::NoError) {
|
if (reply->error() == QModbusDevice::NoError) {
|
||||||
const QModbusDataUnit unit = reply->result();
|
const QModbusDataUnit unit = reply->result();
|
||||||
uint modbusAddress = unit.startAddress();
|
uint modbusAddress = unit.startAddress();
|
||||||
BlockId mapId = BlockId(unit.value(0));
|
ModelId modelId = ModelId(unit.value(0));
|
||||||
int mapLength = unit.value(1);
|
int length = unit.value(1);
|
||||||
qCDebug(dcSunSpec()) << "Received block header response. Map ID:" << mapId << "Map length" << mapLength;
|
qCDebug(dcSunSpec()) << "SunSpec: Received model header response. Model ID:" << modelId << "length" << length;
|
||||||
mapHeaderReceived(modbusAddress, mapId, mapLength);
|
modelHeaderReceived(modbusAddress, modelId, length);
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcSunSpec()) << "Read response error:" << reply->error();
|
qCWarning(dcSunSpec()) << "SunSpec: Read response error:" << reply->error();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
connect(reply, &QModbusReply::errorOccurred, this, [reply] (QModbusDevice::Error error) {
|
connect(reply, &QModbusReply::errorOccurred, this, [reply] (QModbusDevice::Error error) {
|
||||||
qCWarning(dcSunSpec()) << "Modbus reply error:" << error;
|
qCWarning(dcSunSpec()) << "SunSpec: Modbus reply error:" << error;
|
||||||
reply->finished(); // To make sure it will be deleted
|
reply->finished(); // To make sure it will be deleted
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcSunSpec()) << "Read error: " << m_modbusTcpClient->errorString();
|
qCWarning(dcSunSpec()) << "SunSpec: Read error: " << m_modbusTcpClient->errorString();
|
||||||
delete reply; // broadcast replies return immediately
|
delete reply; // broadcast replies return immediately
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcSunSpec()) << "Read error: " << m_modbusTcpClient->errorString();
|
qCWarning(dcSunSpec()) << "SunSpec: Read error: " << m_modbusTcpClient->errorString();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SunSpec::readMap(uint modbusAddress, uint modelLength)
|
void SunSpec::readModelDataBlock(uint modbusAddress, uint length)
|
||||||
{
|
{
|
||||||
qCDebug(dcSunSpec()) << "SunSpec: Read map, modbus address" << modbusAddress << "model length" << modelLength << ", Slave ID" << m_slaveId;
|
qCDebug(dcSunSpec()) << "SunSpec: Read model, modbus address" << modbusAddress << "length" << length << ", Slave ID" << m_slaveId;
|
||||||
|
|
||||||
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, modbusAddress, modelLength+2);
|
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, modbusAddress, length+2);
|
||||||
|
|
||||||
if (QModbusReply *reply = m_modbusTcpClient->sendReadRequest(request, m_slaveId)) {
|
if (QModbusReply *reply = m_modbusTcpClient->sendReadRequest(request, m_slaveId)) {
|
||||||
if (!reply->isFinished()) {
|
if (!reply->isFinished()) {
|
||||||
@ -257,32 +258,32 @@ void SunSpec::readMap(uint modbusAddress, uint modelLength)
|
|||||||
if (reply->error() == QModbusDevice::NoError) {
|
if (reply->error() == QModbusDevice::NoError) {
|
||||||
const QModbusDataUnit unit = reply->result();
|
const QModbusDataUnit unit = reply->result();
|
||||||
uint modbusAddress = unit.startAddress();
|
uint modbusAddress = unit.startAddress();
|
||||||
BlockId mapId = BlockId(unit.value(0));
|
ModelId modelId = ModelId(unit.value(0));
|
||||||
uint mapLength = unit.value(1);
|
uint length = unit.value(1);
|
||||||
qCDebug(dcSunSpec()) << "Received map. Modbus address" << modbusAddress << "Map ID" << mapId << "Map Length" << mapLength;
|
qCDebug(dcSunSpec()) << "SunSpec: Received model. Modbus address" << modbusAddress << "model ID" << modelId << "length" << length;
|
||||||
emit mapReceived(mapId, mapLength, unit.values().mid(2));
|
emit modelDataBlockReceived(modelId, length, unit.values().mid(2));
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcSunSpec()) << "Read response error:" << reply->error();
|
qCWarning(dcSunSpec()) << "SunSpec: Read response error:" << reply->error();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
connect(reply, &QModbusReply::errorOccurred, this, [reply] (QModbusDevice::Error error) {
|
connect(reply, &QModbusReply::errorOccurred, this, [reply] (QModbusDevice::Error error) {
|
||||||
qCWarning(dcSunSpec()) << "Modbus reply error:" << error;
|
qCWarning(dcSunSpec()) << "SunSpec: Modbus reply error:" << error;
|
||||||
reply->finished(); // To make sure it will be deleted
|
reply->finished(); // To make sure it will be deleted
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcSunSpec()) << "Read error: " << m_modbusTcpClient->errorString();
|
qCWarning(dcSunSpec()) << "SunSpec: Read error: " << m_modbusTcpClient->errorString();
|
||||||
delete reply; // broadcast replies return immediately
|
delete reply; // broadcast replies return immediately
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcSunSpec()) << "Read error: " << m_modbusTcpClient->errorString();
|
qCWarning(dcSunSpec()) << "SunSpec: Read error: " << m_modbusTcpClient->errorString();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SunSpec::readCommonMap()
|
void SunSpec::readCommonModel()
|
||||||
{
|
{
|
||||||
qCDebug(dcSunSpec()) << "SunSpec: Read common block header. Modbus Address" << m_baseRegister+2 << ", Slave ID" << m_slaveId;
|
qCDebug(dcSunSpec()) << "SunSpec: Read common model header. Modbus Address" << m_baseRegister+2 << ", Slave ID" << m_slaveId;
|
||||||
|
|
||||||
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, m_baseRegister+2, 66);
|
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, m_baseRegister+2, 66);
|
||||||
|
|
||||||
@ -293,9 +294,6 @@ void SunSpec::readCommonMap()
|
|||||||
|
|
||||||
if (reply->error() == QModbusDevice::NoError) {
|
if (reply->error() == QModbusDevice::NoError) {
|
||||||
const QModbusDataUnit unit = reply->result();
|
const QModbusDataUnit unit = reply->result();
|
||||||
//uint modbusAddress = unit.startAddress();
|
|
||||||
//BlockId mapId = BlockId(unit.value(0));
|
|
||||||
//int mapLength = unit.value(1);
|
|
||||||
m_manufacturer = convertModbusRegisters(unit.values(), MandatoryRegistersModel1::Manufacturer, 16);
|
m_manufacturer = convertModbusRegisters(unit.values(), MandatoryRegistersModel1::Manufacturer, 16);
|
||||||
m_manufacturer.remove('\x00');
|
m_manufacturer.remove('\x00');
|
||||||
m_deviceModel = convertModbusRegisters(unit.values(), MandatoryRegistersModel1::Model, 16);
|
m_deviceModel = convertModbusRegisters(unit.values(), MandatoryRegistersModel1::Model, 16);
|
||||||
@ -303,60 +301,22 @@ void SunSpec::readCommonMap()
|
|||||||
m_serialNumber = convertModbusRegisters(unit.values(), MandatoryRegistersModel1::SerialNumber, 16);
|
m_serialNumber = convertModbusRegisters(unit.values(), MandatoryRegistersModel1::SerialNumber, 16);
|
||||||
m_serialNumber.remove('\x00');
|
m_serialNumber.remove('\x00');
|
||||||
qCDebug(dcSunSpec()) << "SunSpec: Received common block response. Manufacturer" << m_manufacturer << "Model" << m_deviceModel << "Serial number" << m_serialNumber;
|
qCDebug(dcSunSpec()) << "SunSpec: Received common block response. Manufacturer" << m_manufacturer << "Model" << m_deviceModel << "Serial number" << m_serialNumber;
|
||||||
commonMapReceived(m_manufacturer, m_deviceModel, m_serialNumber);
|
commonModelReceived(m_manufacturer, m_deviceModel, m_serialNumber);
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcSunSpec()) << "SunSpec: Read common map, read response error:" << reply->error();
|
qCWarning(dcSunSpec()) << "SunSpec: Read common model, read response error:" << reply->error();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcSunSpec()) << "Sunspec: Read common map read error: " << m_modbusTcpClient->errorString();
|
qCWarning(dcSunSpec()) << "Sunspec: Read common model read error: " << m_modbusTcpClient->errorString();
|
||||||
delete reply; // broadcast replies return immediately
|
delete reply; // broadcast replies return immediately
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcSunSpec()) << "Read error: " << m_modbusTcpClient->errorString();
|
qCWarning(dcSunSpec()) << "SunSpec: Read error: " << m_modbusTcpClient->errorString();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SunSpec::onReceivedHoldingRegister(quint32 slaveAddress, quint32 modbusRegister, const QVector<quint16> &data)
|
|
||||||
{
|
|
||||||
if (modbusRegister == 00000 || modbusRegister == 40000 || modbusRegister == 50000) {
|
|
||||||
// Common block, 66 registers long + 2 header registers
|
|
||||||
|
|
||||||
qCDebug(dcSunSpec()) << "Sunspec Identification:" << convertModbusRegisters(data, 0, 2);
|
|
||||||
|
|
||||||
if (convertModbusRegisters(data, 0, 2) != "SunS") {
|
|
||||||
qCWarning(dcSunSpec()) << "Could not find SunS value at" << modbusRegister << "at Slave" << slaveAddress;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_baseRegister = modbusRegister;
|
|
||||||
|
|
||||||
//Mandatory SunSpec Registers
|
|
||||||
// ID: 40003
|
|
||||||
qCDebug(dcSunSpec()) << "Id:" << data[MandatoryRegistersModel1::Manufacturer];
|
|
||||||
|
|
||||||
// Manufacturer: 40005 | 16
|
|
||||||
qCDebug(dcSunSpec()) << "Manufacturer:" << QString::fromLatin1(convertModbusRegisters(data, MandatoryRegistersModel1::Manufacturer, 16));
|
|
||||||
|
|
||||||
// Thing model: 40021 | 16
|
|
||||||
qCDebug(dcSunSpec()) << "Thing model:" << QString::fromLatin1(convertModbusRegisters(data, MandatoryRegistersModel1::Model, 16));
|
|
||||||
|
|
||||||
// Data manager version: 40037 | 8
|
|
||||||
qCDebug(dcSunSpec()) << "Data manager version:" << QString::fromLatin1(convertModbusRegisters(data, 36, 8));
|
|
||||||
|
|
||||||
// Inverter Version: 40045 | 8
|
|
||||||
qCDebug(dcSunSpec()) << "Inverter version:" << QString::fromLatin1(convertModbusRegisters(data, 44, 8));
|
|
||||||
|
|
||||||
// Serial Number: 40053 | 16
|
|
||||||
qCDebug(dcSunSpec()) << "Serial number:" << QString::fromLatin1(convertModbusRegisters(data, MandatoryRegistersModel1::SerialNumber, 16));
|
|
||||||
|
|
||||||
// Modbus thing address : 40069 | 1
|
|
||||||
qCDebug(dcSunSpec()) << "Thing modbus address:" << data[67];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
QByteArray SunSpec::convertModbusRegister(const uint16_t &modbusData)
|
QByteArray SunSpec::convertModbusRegister(const uint16_t &modbusData)
|
||||||
{
|
{
|
||||||
uint8_t data[2];
|
uint8_t data[2];
|
||||||
@ -438,22 +398,18 @@ QUuid SunSpec::writeHoldingRegisters(uint registerAddress, const QVector<quint16
|
|||||||
connect(reply, &QModbusReply::finished, this, [reply, requestId, this] {
|
connect(reply, &QModbusReply::finished, this, [reply, requestId, this] {
|
||||||
|
|
||||||
if (reply->error() != QModbusDevice::NoError) {
|
if (reply->error() != QModbusDevice::NoError) {
|
||||||
qCWarning(dcSunSpec()) << "Read response error:" << reply->error();
|
qCWarning(dcSunSpec()) << "SunSpec: Read response error:" << reply->error();
|
||||||
|
emit requestExecuted(requestId, false);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
reply->deleteLater();
|
emit requestExecuted(requestId, true);
|
||||||
});
|
});
|
||||||
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
|
|
||||||
|
|
||||||
qCWarning(dcSunSpec()) << "Modbus reply error:" << error;
|
|
||||||
reply->finished(); // To make sure it will be deleted
|
|
||||||
});
|
|
||||||
QTimer::singleShot(200, reply, &QModbusReply::deleteLater);
|
|
||||||
} else {
|
} else {
|
||||||
delete reply; // broadcast replies return immediately
|
delete reply; // broadcast replies return immediately
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcSunSpec()) << "Read error: " << m_modbusTcpClient->errorString();
|
qCWarning(dcSunSpec()) << "SunSpec: Read error: " << m_modbusTcpClient->errorString();
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return requestId;
|
return requestId;
|
||||||
|
|||||||
@ -87,89 +87,89 @@ public:
|
|||||||
};
|
};
|
||||||
Q_ENUM(SunSpecEvent1)
|
Q_ENUM(SunSpecEvent1)
|
||||||
|
|
||||||
enum BlockId {
|
enum ModelId {
|
||||||
BlockIdCommon = 1,
|
ModelIdCommon = 1,
|
||||||
BlockIdBasicAggregator = 2,
|
ModelIdBasicAggregator = 2,
|
||||||
BlockIdSecureDatasetReadRequest = 3,
|
ModelIdSecureDatasetReadRequest = 3,
|
||||||
BlockIdSecureDatasetReadResponse = 4,
|
ModelIdSecureDatasetReadResponse = 4,
|
||||||
BlockIdSecureWriteRequest = 5,
|
ModelIdSecureWriteRequest = 5,
|
||||||
BlockIdSecureWriteSequentialRequest = 6,
|
ModelIdSecureWriteSequentialRequest = 6,
|
||||||
BlockIdSecureWriteResponseModel = 7,
|
ModelIdSecureWriteResponseModel = 7,
|
||||||
BlockIdGetDeviceSecurityCertificate = 8,
|
ModelIdGetDeviceSecurityCertificate = 8,
|
||||||
BlockIdSetOperatorSecurityCertificate = 9,
|
ModelIdSetOperatorSecurityCertificate = 9,
|
||||||
BlockIdCommunicationInterfaceHeader = 10,
|
ModelIdCommunicationInterfaceHeader = 10,
|
||||||
BlockIdEthernetLinkLayer = 11,
|
ModelIdEthernetLinkLayer = 11,
|
||||||
BlockIdIPv4 = 12,
|
ModelIdIPv4 = 12,
|
||||||
BlockIdIPv6 = 13,
|
ModelIdIPv6 = 13,
|
||||||
BlockIdProxyServer = 14,
|
ModelIdProxyServer = 14,
|
||||||
BlockIdInterfaceCountersModel = 15,
|
ModelIdInterfaceCountersModel = 15,
|
||||||
BlockIdSimpleIpNetwork = 16,
|
ModelIdSimpleIpNetwork = 16,
|
||||||
BlockIdSerialInterface = 17,
|
ModelIdSerialInterface = 17,
|
||||||
BlockIdCellularLink = 18,
|
ModelIdCellularLink = 18,
|
||||||
BlockIdPPPLink = 19,
|
ModelIdPPPLink = 19,
|
||||||
BlockIdInverterSinglePhase = 101,
|
ModelIdInverterSinglePhase = 101,
|
||||||
BlockIdInverterSplitPhase = 102,
|
ModelIdInverterSplitPhase = 102,
|
||||||
BlockIdInverterThreePhase = 103,
|
ModelIdInverterThreePhase = 103,
|
||||||
BlockIdInverterSinglePhaseFloat = 111,
|
ModelIdInverterSinglePhaseFloat = 111,
|
||||||
BlockIdInverterSplitPhaseFloat = 112,
|
ModelIdInverterSplitPhaseFloat = 112,
|
||||||
BlockIdInverterThreePhaseFloat = 113,
|
ModelIdInverterThreePhaseFloat = 113,
|
||||||
BlockIdNameplate = 120,
|
ModelIdNameplate = 120,
|
||||||
BlockIdBasicSettings = 121,
|
ModelIdBasicSettings = 121,
|
||||||
BlockIdMeasurementsStatus = 122,
|
ModelIdMeasurementsStatus = 122,
|
||||||
BlockIdImmediateControls = 123,
|
ModelIdImmediateControls = 123,
|
||||||
BlockIdStorage = 124,
|
ModelIdStorage = 124,
|
||||||
BlockIdPricing = 125,
|
ModelIdPricing = 125,
|
||||||
BlockIdStaticVoltVAR = 126,
|
ModelIdStaticVoltVAR = 126,
|
||||||
BlockIdFreqWattParam = 127,
|
ModelIdFreqWattParam = 127,
|
||||||
BlockIdDynamicReactiveCurrent = 128,
|
ModelIdDynamicReactiveCurrent = 128,
|
||||||
BlockIdLVRTD = 129,
|
ModelIdLVRTD = 129,
|
||||||
BlockIdHVRTD = 130,
|
ModelIdHVRTD = 130,
|
||||||
BlockIdWattPF = 131,
|
ModelIdWattPF = 131,
|
||||||
BlockIdVoltWatt = 132,
|
ModelIdVoltWatt = 132,
|
||||||
BlockIdBasicScheduling = 133,
|
ModelIdBasicScheduling = 133,
|
||||||
BlockIdFreqWattCrv = 134,
|
ModelIdFreqWattCrv = 134,
|
||||||
BlockIdLFRT = 135,
|
ModelIdLFRT = 135,
|
||||||
BlockIdHFRT = 136,
|
ModelIdHFRT = 136,
|
||||||
BlockIdLVRTC = 137,
|
ModelIdLVRTC = 137,
|
||||||
BlockIdHVRTC = 138,
|
ModelIdHVRTC = 138,
|
||||||
BlockIdMultipleMPPTInverterExtensionModel = 160,
|
ModelIdMultipleMPPTInverterExtensionModel = 160,
|
||||||
BlockIdSinglePhaseMeter = 201,
|
ModelIdSinglePhaseMeter = 201,
|
||||||
BlockIdSplitSinglePhaseMeter = 202,
|
ModelIdSplitSinglePhaseMeter = 202,
|
||||||
BlockIdWyeConnectThreePhaseMeter = 203,
|
ModelIdWyeConnectThreePhaseMeter = 203,
|
||||||
BlockIdDeltaConnectThreePhaseMeter = 204,
|
ModelIdDeltaConnectThreePhaseMeter = 204,
|
||||||
BlockIdSinglePhaseMeterFloat = 211,
|
ModelIdSinglePhaseMeterFloat = 211,
|
||||||
BlockIdSplitSinglePhaseMeterFloat = 212,
|
ModelIdSplitSinglePhaseMeterFloat = 212,
|
||||||
BlockIdWyeConnectThreePhaseMeterFloat = 213,
|
ModelIdWyeConnectThreePhaseMeterFloat = 213,
|
||||||
BlockIdDeltaConnectThreePhaseMeterFloat = 214,
|
ModelIdDeltaConnectThreePhaseMeterFloat = 214,
|
||||||
BlockIdSecureACMeterSelectedReadings = 220,
|
ModelIdSecureACMeterSelectedReadings = 220,
|
||||||
BlockIdIrradianceModel = 302,
|
ModelIdIrradianceModel = 302,
|
||||||
BlockIdBackOfModuleTemperatureModel = 303,
|
ModelIdBackOfModuleTemperatureModel = 303,
|
||||||
BlockIdInclinometerModel = 304,
|
ModelIdInclinometerModel = 304,
|
||||||
BlockIdGPS = 305,
|
ModelIdGPS = 305,
|
||||||
BlockIdReferencePointModel = 306,
|
ModelIdReferencePointModel = 306,
|
||||||
BlockIdBaseMet = 307,
|
ModelIdBaseMet = 307,
|
||||||
BlockIdMiniMetModel = 308,
|
ModelIdMiniMetModel = 308,
|
||||||
BlockIdStringCombiner = 401,
|
ModelIdStringCombiner = 401,
|
||||||
BlockIdStringCombinerAdvanced = 402,
|
ModelIdStringCombinerAdvanced = 402,
|
||||||
BlockIdStringCombinerCurrent = 403,
|
ModelIdStringCombinerCurrent = 403,
|
||||||
BlockIdStringCombinerCurrentAdvanced = 404,
|
ModelIdStringCombinerCurrentAdvanced = 404,
|
||||||
BlockIdSolarModuleFloat = 501,
|
ModelIdSolarModuleFloat = 501,
|
||||||
BlockIdSolarModule = 502,
|
ModelIdSolarModule = 502,
|
||||||
BlockIdTrackerController = 601,
|
ModelIdTrackerController = 601,
|
||||||
BlockIdEnergyStorageBaseModel = 801,
|
ModelIdEnergyStorageBaseModel = 801,
|
||||||
BlockIdBatteryBaseModel = 802,
|
ModelIdBatteryBaseModel = 802,
|
||||||
BlockIdLithiumIonBatteryModel = 803,
|
ModelIdLithiumIonBatteryModel = 803,
|
||||||
BlockIdVerisStatusConfiguration = 64001,
|
ModelIdVerisStatusConfiguration = 64001,
|
||||||
BlockIdMersenGreenString = 64020,
|
ModelIdMersenGreenString = 64020,
|
||||||
BlockIdEltekInverterExtension = 64101,
|
ModelIdEltekInverterExtension = 64101,
|
||||||
BlockIdOutBackAXSDevice = 64110,
|
ModelIdOutBackAXSDevice = 64110,
|
||||||
BlockIdBasicChargeController = 64111,
|
ModelIdBasicChargeController = 64111,
|
||||||
BlockIdOutBackFMChargeController = 64112,
|
ModelIdOutBackFMChargeController = 64112,
|
||||||
BlockIdEnd = 65535
|
ModelIdEnd = 65535
|
||||||
};
|
};
|
||||||
Q_ENUM(BlockId)
|
Q_ENUM(ModelId)
|
||||||
|
|
||||||
explicit SunSpec(const QHostAddress &hostAddress, uint port = 502, QObject *parent = 0);
|
explicit SunSpec(const QHostAddress &hostAddress, uint port = 502, uint slaveId = 1, QObject *parent = 0);
|
||||||
~SunSpec();
|
~SunSpec();
|
||||||
bool connectModbus();
|
bool connectModbus();
|
||||||
void setHostAddress(const QHostAddress &hostAddress);
|
void setHostAddress(const QHostAddress &hostAddress);
|
||||||
@ -194,14 +194,14 @@ public:
|
|||||||
QString m_manufacturer = "Unknown";
|
QString m_manufacturer = "Unknown";
|
||||||
QString m_deviceModel = "Unknown";
|
QString m_deviceModel = "Unknown";
|
||||||
QString m_serialNumber = "Unknown";
|
QString m_serialNumber = "Unknown";
|
||||||
QHash<BlockId, int> m_mapList;
|
QHash<ModelId, int> m_modelList;
|
||||||
|
|
||||||
void findBaseRegister();
|
void findBaseRegister();
|
||||||
void findModbusMap(const QList<BlockId> &mapIds, uint modbusAddressOffset = 2);
|
void findSunSpecModels(const QList<ModelId> &modelIds, uint modbusAddressOffset = 2);
|
||||||
|
|
||||||
void readCommonMap();
|
void readCommonModel();
|
||||||
void readMapHeader(uint modbusAddress);
|
void readModelHeader(uint modbusAddress);
|
||||||
void readMap(uint modbusAddress, uint modelLength); //modbusAddress = model start address, model length is without header
|
void readModelDataBlock(uint modbusAddress, uint modelLength); //modbusAddress = model start address, model length is without header
|
||||||
|
|
||||||
float convertValueWithSSF(quint32 rawValue, quint16 sunssf);
|
float convertValueWithSSF(quint32 rawValue, quint16 sunssf);
|
||||||
float convertFloatValues(quint16 rawValue0, quint16 rawValue1);
|
float convertFloatValues(quint16 rawValue0, quint16 rawValue1);
|
||||||
@ -214,20 +214,19 @@ public:
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void connectionStateChanged(bool status);
|
void connectionStateChanged(bool status);
|
||||||
void requestExecuted(QUuid requetId, bool success);
|
void requestExecuted(const QUuid &requestId, bool success);
|
||||||
|
|
||||||
void foundBaseRegister(int modbusAddress);
|
void foundBaseRegister(int modbusAddress);
|
||||||
void commonMapReceived(const QString &manufacturer, const QString &deviceModel, const QString &serialNumber);
|
void commonModelReceived(const QString &manufacturer, const QString &deviceModel, const QString &serialNumber);
|
||||||
|
|
||||||
void foundModbusMap(BlockId mapId, int modbusStartRegister);
|
void foundSunSpecModel(ModelId modelId, int modbusStartRegister);
|
||||||
void modbusMapSearchFinished(const QHash<BlockId, int> &mapIds);
|
void sunspecModelSearchFinished(const QHash<ModelId, int> &mapIds);
|
||||||
|
|
||||||
void mapHeaderReceived(uint modbusAddress, BlockId mapId, uint mapLength);
|
void modelHeaderReceived(uint modbusAddress, ModelId mapId, uint mapLength);
|
||||||
void mapReceived(BlockId mapId, uint mapLength, QVector<quint16> data);
|
void modelDataBlockReceived(ModelId id, uint ength, QVector<quint16> data);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onModbusStateChanged(QModbusDevice::State state);
|
void onModbusStateChanged(QModbusDevice::State state);
|
||||||
void onReceivedHoldingRegister(quint32 slaveAddress, quint32 modbusRegister, const QVector<quint16> &values);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SUNSPEC_H
|
#endif // SUNSPEC_H
|
||||||
|
|||||||
@ -33,17 +33,17 @@
|
|||||||
|
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
SunSpecInverter::SunSpecInverter(SunSpec *sunspec, SunSpec::BlockId mapId, int modbusAddress) :
|
SunSpecInverter::SunSpecInverter(SunSpec *sunspec, SunSpec::ModelId modelId, int modbusAddress) :
|
||||||
QObject(sunspec),
|
QObject(sunspec),
|
||||||
m_connection(sunspec),
|
m_connection(sunspec),
|
||||||
m_id(mapId),
|
m_id(modelId),
|
||||||
m_mapModbusStartRegister(modbusAddress)
|
m_modelModbusStartRegister(modbusAddress)
|
||||||
{
|
{
|
||||||
qCDebug(dcSunSpec()) << "SunSpecInverter: Setting up inverter";
|
qCDebug(dcSunSpec()) << "SunSpecInverter: Setting up inverter";
|
||||||
connect(m_connection, &SunSpec::mapReceived, this, &SunSpecInverter::onModbusMapReceived);
|
connect(m_connection, &SunSpec::modelDataBlockReceived, this, &SunSpecInverter::onModelDataBlockReceived);
|
||||||
}
|
}
|
||||||
|
|
||||||
SunSpec::BlockId SunSpecInverter::blockId()
|
SunSpec::ModelId SunSpecInverter::modelId()
|
||||||
{
|
{
|
||||||
return m_id;
|
return m_id;
|
||||||
}
|
}
|
||||||
@ -51,10 +51,10 @@ SunSpec::BlockId SunSpecInverter::blockId()
|
|||||||
void SunSpecInverter::init()
|
void SunSpecInverter::init()
|
||||||
{
|
{
|
||||||
qCDebug(dcSunSpec()) << "SunSpecInverter: Init";
|
qCDebug(dcSunSpec()) << "SunSpecInverter: Init";
|
||||||
m_connection->readMapHeader(m_mapModbusStartRegister);
|
m_connection->readModelHeader(m_modelModbusStartRegister);
|
||||||
connect(m_connection, &SunSpec::mapHeaderReceived, this, [this] (uint modbusAddress, SunSpec::BlockId mapId, uint mapLength) {
|
connect(m_connection, &SunSpec::modelHeaderReceived, this, [this] (uint modbusAddress, SunSpec::ModelId modelId, uint length) {
|
||||||
qCDebug(dcSunSpec()) << "SunSpecInverter: Map Header received, modbus address:" << modbusAddress << "map Id:" << mapId << "map length:" << mapLength;
|
qCDebug(dcSunSpec()) << "SunSpecInverter: Model Header received, modbus address:" << modbusAddress << "model Id:" << modelId << "length:" << length;
|
||||||
m_mapLength = mapLength;
|
m_modelLength = length;
|
||||||
emit initFinished(true);
|
emit initFinished(true);
|
||||||
m_initFinishedSuccess = true;
|
m_initFinishedSuccess = true;
|
||||||
});
|
});
|
||||||
@ -65,33 +65,33 @@ void SunSpecInverter::init()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void SunSpecInverter::getInverterMap()
|
void SunSpecInverter::getInverterModelDataBlock()
|
||||||
{
|
{
|
||||||
// TODO check map length to modbus max value
|
// TODO check map length to modbus max value
|
||||||
m_connection->readMap(m_mapModbusStartRegister, m_mapLength);
|
m_connection->readModelDataBlock(m_modelModbusStartRegister, m_modelLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SunSpecInverter::readInverterBlockHeader()
|
void SunSpecInverter::getInverterModelHeader()
|
||||||
{
|
{
|
||||||
m_connection->readMapHeader(m_mapModbusStartRegister);
|
m_connection->readModelHeader(m_modelModbusStartRegister);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SunSpecInverter::onModbusMapReceived(SunSpec::BlockId mapId, uint mapLength, QVector<quint16> data)
|
void SunSpecInverter::onModelDataBlockReceived(SunSpec::ModelId mapId, uint mapLength, QVector<quint16> data)
|
||||||
{
|
{
|
||||||
Q_UNUSED(mapLength)
|
Q_UNUSED(mapLength)
|
||||||
if (mapId != m_id) {
|
if (mapId != m_id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mapLength < m_mapLength) {
|
if (mapLength < m_modelLength) {
|
||||||
qCDebug(dcSunSpec()) << "SunSpecInverter: on modbus map received, map length ist too short" << mapLength;
|
qCDebug(dcSunSpec()) << "SunSpecInverter: on modbus map received, map length ist too short" << mapLength;
|
||||||
//return;
|
//return;
|
||||||
}
|
}
|
||||||
InverterData inverterData;
|
InverterData inverterData;
|
||||||
|
|
||||||
switch (mapId) {
|
switch (mapId) {
|
||||||
case SunSpec::BlockIdInverterSinglePhase:
|
case SunSpec::ModelIdInverterSinglePhase:
|
||||||
case SunSpec::BlockIdInverterSplitPhase:
|
case SunSpec::ModelIdInverterSplitPhase:
|
||||||
case SunSpec::BlockIdInverterThreePhase: {
|
case SunSpec::ModelIdInverterThreePhase: {
|
||||||
|
|
||||||
inverterData.acCurrent= m_connection->convertValueWithSSF(data[Model10X::Model10XAcCurrent], data[Model10X::Model10XAmpereScaleFactor]);
|
inverterData.acCurrent= m_connection->convertValueWithSSF(data[Model10X::Model10XAcCurrent], data[Model10X::Model10XAmpereScaleFactor]);
|
||||||
inverterData.acPower = m_connection->convertValueWithSSF(data[Model10X::Model10XACPower], data[Model10X::Model10XWattScaleFactor]);
|
inverterData.acPower = m_connection->convertValueWithSSF(data[Model10X::Model10XACPower], data[Model10X::Model10XWattScaleFactor]);
|
||||||
@ -105,14 +105,7 @@ void SunSpecInverter::onModbusMapReceived(SunSpec::BlockId mapId, uint mapLength
|
|||||||
inverterData.phaseVoltageBN = m_connection->convertValueWithSSF(data[Model10X::Model10XPhaseVoltageBN], data[Model10X::Model10XVoltageScaleFactor]);
|
inverterData.phaseVoltageBN = m_connection->convertValueWithSSF(data[Model10X::Model10XPhaseVoltageBN], data[Model10X::Model10XVoltageScaleFactor]);
|
||||||
inverterData.phaseVoltageCN = m_connection->convertValueWithSSF(data[Model10X::Model10XPhaseVoltageCN], data[Model10X::Model10XVoltageScaleFactor]);
|
inverterData.phaseVoltageCN = m_connection->convertValueWithSSF(data[Model10X::Model10XPhaseVoltageCN], data[Model10X::Model10XVoltageScaleFactor]);
|
||||||
|
|
||||||
|
|
||||||
qCDebug(dcSunSpec()) << "Energy with SSF values:";
|
|
||||||
qCDebug(dcSunSpec()) << " - AC Energy 1:" << data[Model10X::Model10XAcEnergy];
|
|
||||||
qCDebug(dcSunSpec()) << " - AC Energy 2" << data[Model10X::Model10XAcEnergy+1];
|
|
||||||
quint32 acEnergy = ((static_cast<quint32>(data.value(Model10X::Model10XAcEnergy))<<16)|static_cast<quint32>(data.value(Model10X::Model10XAcEnergy+1)));
|
quint32 acEnergy = ((static_cast<quint32>(data.value(Model10X::Model10XAcEnergy))<<16)|static_cast<quint32>(data.value(Model10X::Model10XAcEnergy+1)));
|
||||||
qCDebug(dcSunSpec()) << " - AC Energy combined" << acEnergy;
|
|
||||||
qCDebug(dcSunSpec()) << " - Scale factor:" << data[Model10X::Model10XWattHoursScaleFactor];
|
|
||||||
|
|
||||||
inverterData.acEnergy = m_connection->convertValueWithSSF(acEnergy, data[Model10X::Model10XWattHoursScaleFactor]);
|
inverterData.acEnergy = m_connection->convertValueWithSSF(acEnergy, data[Model10X::Model10XWattHoursScaleFactor]);
|
||||||
|
|
||||||
inverterData.cabinetTemperature = m_connection->convertValueWithSSF(data[Model10X::Model10XCabinetTemperature], data[Model10X::Model10XTemperatureScaleFactor]);
|
inverterData.cabinetTemperature = m_connection->convertValueWithSSF(data[Model10X::Model10XCabinetTemperature], data[Model10X::Model10XTemperatureScaleFactor]);
|
||||||
@ -121,9 +114,9 @@ void SunSpecInverter::onModbusMapReceived(SunSpec::BlockId mapId, uint mapLength
|
|||||||
emit inverterDataReceived(inverterData);
|
emit inverterDataReceived(inverterData);
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case SunSpec::BlockIdInverterThreePhaseFloat:
|
case SunSpec::ModelIdInverterThreePhaseFloat:
|
||||||
case SunSpec::BlockIdInverterSplitPhaseFloat:
|
case SunSpec::ModelIdInverterSplitPhaseFloat:
|
||||||
case SunSpec::BlockIdInverterSinglePhaseFloat: {
|
case SunSpec::ModelIdInverterSinglePhaseFloat: {
|
||||||
|
|
||||||
inverterData.acCurrent = m_connection->convertFloatValues(data[Model11X::Model11XAcCurrent], data[Model11X::Model11XAcCurrent+1]);
|
inverterData.acCurrent = m_connection->convertFloatValues(data[Model11X::Model11XAcCurrent], data[Model11X::Model11XAcCurrent+1]);
|
||||||
|
|
||||||
|
|||||||
@ -96,22 +96,22 @@ public:
|
|||||||
SunSpec::SunSpecOperatingState operatingState;
|
SunSpec::SunSpecOperatingState operatingState;
|
||||||
};
|
};
|
||||||
|
|
||||||
SunSpecInverter(SunSpec *sunspec, SunSpec::BlockId blockId, int modbusAddress);
|
SunSpecInverter(SunSpec *sunspec, SunSpec::ModelId modelId, int modbusAddress);
|
||||||
SunSpec::BlockId blockId();
|
SunSpec::ModelId modelId();
|
||||||
void init();
|
void init();
|
||||||
void getInverterMap();
|
void getInverterModelDataBlock();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SunSpec *m_connection = nullptr;
|
SunSpec *m_connection = nullptr;
|
||||||
SunSpec::BlockId m_id; //e.g. 103 for three phase inverter, 113 for three phase inverter with floating point representation
|
SunSpec::ModelId m_id; //e.g. 103 for three phase inverter, 113 for three phase inverter with floating point representation
|
||||||
uint m_mapLength = 0;
|
uint m_modelLength = 0;
|
||||||
uint m_mapModbusStartRegister = 40000;
|
uint m_modelModbusStartRegister = 40000;
|
||||||
bool m_initFinishedSuccess = false;
|
bool m_initFinishedSuccess = false;
|
||||||
|
|
||||||
void readInverterBlockHeader();
|
void getInverterModelHeader();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onModbusMapReceived(SunSpec::BlockId mapId, uint mapLength, QVector<quint16> data);
|
void onModelDataBlockReceived(SunSpec::ModelId mapId, uint mapLength, QVector<quint16> data);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void initFinished(bool success);
|
void initFinished(bool success);
|
||||||
|
|||||||
@ -31,28 +31,29 @@
|
|||||||
#include "sunspecmeter.h"
|
#include "sunspecmeter.h"
|
||||||
#include "extern-plugininfo.h"
|
#include "extern-plugininfo.h"
|
||||||
|
|
||||||
SunSpecMeter::SunSpecMeter(SunSpec *sunspec, SunSpec::BlockId blockId, int modbusAddress) :
|
SunSpecMeter::SunSpecMeter(SunSpec *sunspec, SunSpec::ModelId modelId, int modbusAddress) :
|
||||||
QObject(sunspec),
|
QObject(sunspec),
|
||||||
m_connection(sunspec),
|
m_connection(sunspec),
|
||||||
m_id(blockId),
|
m_id(modelId),
|
||||||
m_mapModbusStartRegister(modbusAddress)
|
m_modelModbusStartRegister(modbusAddress)
|
||||||
{
|
{
|
||||||
qCDebug(dcSunSpec()) << "SunSpecMeter: Setting up meter";
|
qCDebug(dcSunSpec()) << "SunSpecMeter: Setting up meter";
|
||||||
connect(m_connection, &SunSpec::mapReceived, this, &SunSpecMeter::onModbusMapReceived);
|
connect(m_connection, &SunSpec::modelDataBlockReceived, this, &SunSpecMeter::onModelDataBlockReceived);
|
||||||
}
|
}
|
||||||
|
|
||||||
SunSpec::BlockId SunSpecMeter::blockId()
|
SunSpec::ModelId SunSpecMeter::modelId()
|
||||||
{
|
{
|
||||||
|
|
||||||
return m_id;
|
return m_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SunSpecMeter::init()
|
void SunSpecMeter::init()
|
||||||
{
|
{
|
||||||
qCDebug(dcSunSpec()) << "SunSpecInverter: Init";
|
qCDebug(dcSunSpec()) << "SunSpecMeter: Init";
|
||||||
m_connection->readMapHeader(m_mapModbusStartRegister);
|
m_connection->readModelHeader(m_modelModbusStartRegister);
|
||||||
connect(m_connection, &SunSpec::mapHeaderReceived, this, [this] (uint modbusAddress, SunSpec::BlockId mapId, uint mapLength) {
|
connect(m_connection, &SunSpec::modelHeaderReceived, this, [this] (uint modbusAddress, SunSpec::ModelId modelId, uint length) {
|
||||||
qCDebug(dcSunSpec()) << "SunSpecInverter: Map Header received, modbus address:" << modbusAddress << "map Id:" << mapId << "map length:" << mapLength;
|
qCDebug(dcSunSpec()) << "SunSpecMeter: Model Header received, modbus address:" << modbusAddress << "model Id:" << modelId << "length:" << length;
|
||||||
m_mapLength = mapLength;
|
m_modelLength = length;
|
||||||
emit initFinished(true);
|
emit initFinished(true);
|
||||||
m_initFinishedSuccess = true;
|
m_initFinishedSuccess = true;
|
||||||
});
|
});
|
||||||
@ -63,21 +64,37 @@ void SunSpecMeter::init()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void SunSpecMeter::getMeterMap()
|
void SunSpecMeter::getMeterModelDataBlock()
|
||||||
{
|
{
|
||||||
m_connection->readMap(m_mapModbusStartRegister, m_mapLength);
|
m_connection->readModelDataBlock(m_modelModbusStartRegister, m_modelLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SunSpecMeter::readMeterBlockHeader()
|
void SunSpecMeter::getMeterModelHeader()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SunSpecMeter::onModbusMapReceived(SunSpec::BlockId mapId, uint mapLength, QVector<quint16> data)
|
void SunSpecMeter::onModelDataBlockReceived(SunSpec::ModelId modelId, uint length, QVector<quint16> data)
|
||||||
{
|
{
|
||||||
Q_UNUSED(mapLength)
|
if (modelId != m_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Q_UNUSED(length)
|
||||||
Q_UNUSED(data)
|
Q_UNUSED(data)
|
||||||
switch (mapId) {
|
switch (modelId) {
|
||||||
|
|
||||||
|
case SunSpec::ModelIdSinglePhaseMeter:
|
||||||
|
case SunSpec::ModelIdSinglePhaseMeterFloat: {
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case SunSpec::ModelIdSplitSinglePhaseMeter:
|
||||||
|
case SunSpec::ModelIdSplitSinglePhaseMeterFloat: {
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case SunSpec::ModelIdWyeConnectThreePhaseMeterFloat:
|
||||||
|
case SunSpec::ModelIdDeltaConnectThreePhaseMeterFloat: {
|
||||||
|
|
||||||
|
} break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -68,22 +68,21 @@ public:
|
|||||||
SunSpec::SunSpecOperatingState operatingState;
|
SunSpec::SunSpecOperatingState operatingState;
|
||||||
};
|
};
|
||||||
|
|
||||||
SunSpecMeter(SunSpec *sunspec, SunSpec::BlockId blockId, int modbusAddress);
|
SunSpecMeter(SunSpec *sunspec, SunSpec::ModelId modelId, int modbusAddress);
|
||||||
SunSpec::BlockId blockId();
|
SunSpec::ModelId modelId();
|
||||||
void init();
|
void init();
|
||||||
void getMeterMap();
|
void getMeterModelHeader();
|
||||||
|
void getMeterModelDataBlock();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SunSpec *m_connection = nullptr;
|
SunSpec *m_connection = nullptr;
|
||||||
SunSpec::BlockId m_id = SunSpec::BlockIdDeltaConnectThreePhaseMeter;
|
SunSpec::ModelId m_id = SunSpec::ModelIdDeltaConnectThreePhaseMeter;
|
||||||
uint m_mapLength = 0;
|
uint m_modelLength = 0;
|
||||||
uint m_mapModbusStartRegister = 40000;
|
uint m_modelModbusStartRegister = 40000;
|
||||||
bool m_initFinishedSuccess = false;
|
bool m_initFinishedSuccess = false;
|
||||||
|
|
||||||
void readMeterBlockHeader();
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onModbusMapReceived(SunSpec::BlockId mapId, uint mapLength, QVector<quint16> data);
|
void onModelDataBlockReceived(SunSpec::ModelId modelId, uint length, QVector<quint16> data);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void initFinished(bool success);
|
void initFinished(bool success);
|
||||||
|
|||||||
@ -31,29 +31,28 @@
|
|||||||
#include "sunspecstorage.h"
|
#include "sunspecstorage.h"
|
||||||
#include "extern-plugininfo.h"
|
#include "extern-plugininfo.h"
|
||||||
|
|
||||||
SunSpecStorage::SunSpecStorage(SunSpec *sunspec, SunSpec::BlockId blockId, int modbusAddress) :
|
SunSpecStorage::SunSpecStorage(SunSpec *sunspec, SunSpec::ModelId modelId, int modbusAddress) :
|
||||||
QObject(sunspec),
|
QObject(sunspec),
|
||||||
m_connection(sunspec),
|
m_connection(sunspec),
|
||||||
m_id(blockId),
|
m_id(modelId),
|
||||||
m_mapModbusStartRegister(modbusAddress)
|
m_modelModbusStartRegister(modbusAddress)
|
||||||
{
|
{
|
||||||
qCDebug(dcSunSpec()) << "SunSpecStorage: Setting up storage";
|
qCDebug(dcSunSpec()) << "SunSpecStorage: Setting up storage";
|
||||||
connect(m_connection, &SunSpec::mapReceived, this, &SunSpecStorage::onModbusMapReceived);
|
connect(m_connection, &SunSpec::modelDataBlockReceived, this, &SunSpecStorage::onModelDataBlockReceived);
|
||||||
}
|
}
|
||||||
|
|
||||||
SunSpec::BlockId SunSpecStorage::blockId()
|
SunSpec::ModelId SunSpecStorage::modelId()
|
||||||
{
|
{
|
||||||
return m_id;
|
return m_id;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SunSpecStorage::init()
|
void SunSpecStorage::init()
|
||||||
{
|
{
|
||||||
qCDebug(dcSunSpec()) << "SunSpecInverter: Init";
|
qCDebug(dcSunSpec()) << "SunSpecStorage: Init";
|
||||||
m_connection->readMapHeader(m_mapModbusStartRegister);
|
m_connection->readModelHeader(m_modelModbusStartRegister);
|
||||||
connect(m_connection, &SunSpec::mapHeaderReceived, this, [this] (uint modbusAddress, SunSpec::BlockId mapId, uint mapLength) {
|
connect(m_connection, &SunSpec::modelHeaderReceived, this, [this] (uint modbusAddress, SunSpec::ModelId modelId, uint length) {
|
||||||
qCDebug(dcSunSpec()) << "SunSpecInverter: Map Header received, modbus address:" << modbusAddress << "map Id:" << mapId << "map length:" << mapLength;
|
qCDebug(dcSunSpec()) << "SunSpecStorager: Model header received, modbus address:" << modbusAddress << "model Id:" << modelId << "length:" << length;
|
||||||
m_mapLength = mapLength;
|
m_modelLength = length;
|
||||||
emit initFinished(true);
|
emit initFinished(true);
|
||||||
m_initFinishedSuccess = true;
|
m_initFinishedSuccess = true;
|
||||||
});
|
});
|
||||||
@ -64,14 +63,14 @@ void SunSpecStorage::init()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void SunSpecStorage::getStorageMap()
|
void SunSpecStorage::getStorageModelDataBlock()
|
||||||
{
|
{
|
||||||
m_connection->readMap(m_mapModbusStartRegister, m_mapLength);
|
m_connection->readModelDataBlock(m_modelModbusStartRegister, m_modelLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SunSpecStorage::readStorageBlockHeader()
|
void SunSpecStorage::getStorageModelHeader()
|
||||||
{
|
{
|
||||||
m_connection->readMapHeader(m_mapModbusStartRegister);
|
m_connection->readModelHeader(m_modelModbusStartRegister);
|
||||||
}
|
}
|
||||||
|
|
||||||
QUuid SunSpecStorage::setGridCharging(bool enabled)
|
QUuid SunSpecStorage::setGridCharging(bool enabled)
|
||||||
@ -82,7 +81,7 @@ QUuid SunSpecStorage::setGridCharging(bool enabled)
|
|||||||
PV (charging from grid 0 disabled)
|
PV (charging from grid 0 disabled)
|
||||||
GRID (charging from 1 grid enabled*/
|
GRID (charging from 1 grid enabled*/
|
||||||
|
|
||||||
uint registerAddress = m_mapModbusStartRegister + Model124::Model124ChaGriSet;
|
uint registerAddress = m_modelModbusStartRegister + Model124::Model124ChaGriSet;
|
||||||
quint16 value = enabled;
|
quint16 value = enabled;
|
||||||
return m_connection->writeHoldingRegister(registerAddress, value);
|
return m_connection->writeHoldingRegister(registerAddress, value);
|
||||||
}
|
}
|
||||||
@ -93,7 +92,7 @@ QUuid SunSpecStorage::setStorageControlMode(bool chargingEnabled, bool dischargi
|
|||||||
quint16 value = ((static_cast<quint16>(chargingEnabled) << StorageControlBitFieldCharge) |
|
quint16 value = ((static_cast<quint16>(chargingEnabled) << StorageControlBitFieldCharge) |
|
||||||
(static_cast<quint16>(dischargingEnabled) << StorageControlBitFieldDischarge)) ;
|
(static_cast<quint16>(dischargingEnabled) << StorageControlBitFieldDischarge)) ;
|
||||||
|
|
||||||
uint modbusRegister = m_mapModbusStartRegister + Model124::Model124ActivateStorageControlMode;
|
uint modbusRegister = m_modelModbusStartRegister + Model124::Model124ActivateStorageControlMode;
|
||||||
return m_connection->writeHoldingRegister(modbusRegister, value);
|
return m_connection->writeHoldingRegister(modbusRegister, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +101,7 @@ QUuid SunSpecStorage::setChargingRate(int rate)
|
|||||||
//Register Name InWRte
|
//Register Name InWRte
|
||||||
/* Defines the maximum charge rate (charge limit). Default is 100% */
|
/* Defines the maximum charge rate (charge limit). Default is 100% */
|
||||||
|
|
||||||
uint modbusRegister = m_mapModbusStartRegister + Model124::Model124SetpointMaximumChargingRate;
|
uint modbusRegister = m_modelModbusStartRegister + Model124::Model124SetpointMaximumChargingRate;
|
||||||
int16_t value = rate * 100;
|
int16_t value = rate * 100;
|
||||||
return m_connection->writeHoldingRegister(modbusRegister, value);
|
return m_connection->writeHoldingRegister(modbusRegister, value);
|
||||||
}
|
}
|
||||||
@ -111,20 +110,37 @@ QUuid SunSpecStorage::setDischargingRate(int charging)
|
|||||||
{
|
{
|
||||||
//Register Name OutWRte
|
//Register Name OutWRte
|
||||||
/* Defines the maximum discharge rate (discharge limit). Default is 100% */
|
/* Defines the maximum discharge rate (discharge limit). Default is 100% */
|
||||||
uint modbusRegister = m_mapModbusStartRegister + Model124::Model124SetpointMaximumDischargeRate;
|
uint modbusRegister = m_modelModbusStartRegister + Model124::Model124SetpointMaximumDischargeRate;
|
||||||
quint16 value = charging * 100;
|
quint16 value = charging * 100;
|
||||||
return m_connection->writeHoldingRegister(modbusRegister, value);
|
return m_connection->writeHoldingRegister(modbusRegister, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SunSpecStorage::onModbusMapReceived(SunSpec::BlockId mapId, uint mapLength, const QVector<quint16> &data)
|
void SunSpecStorage::onModelDataBlockReceived(SunSpec::ModelId modelId, uint length, const QVector<quint16> &data)
|
||||||
{
|
{
|
||||||
Q_UNUSED(mapLength)
|
Q_UNUSED(length)
|
||||||
switch (mapId) {
|
if (modelId != m_id) {
|
||||||
case SunSpec::BlockIdStorage: {
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (modelId) {
|
||||||
|
case SunSpec::ModelIdStorage: {
|
||||||
StorageData storageData;
|
StorageData storageData;
|
||||||
|
qCDebug(dcSunSpec()) << "SunSpecStorage: Storage model received:";
|
||||||
|
qCDebug(dcSunSpec()) << " - Setpoint maximum charge" << data[Model124SetpointMaximumCharge];
|
||||||
|
qCDebug(dcSunSpec()) << " - Setpoint maximum charging rate" << data[Model124SetpointMaximumChargingRate];
|
||||||
|
qCDebug(dcSunSpec()) << " - Setpoint maximum discharge rate" << data[Model124SetpointMaximumDischargeRate];
|
||||||
|
qCDebug(dcSunSpec()) << " - Active storage control mode" << data[Model124ActivateStorageControlMode];
|
||||||
|
qCDebug(dcSunSpec()) << " - Currently available energy" << data[Model124CurrentlyAvailableEnergy];
|
||||||
storageData.chargingState = ChargingState(data[Model124::Model124ChargeStatus]);
|
storageData.chargingState = ChargingState(data[Model124::Model124ChargeStatus]);
|
||||||
|
qCDebug(dcSunSpec()) << " - Setpoint maximum charging rate" << data[Model124ChaGriSet];
|
||||||
|
qCDebug(dcSunSpec()) << " - Setpoint maximum charging rate" << data[Model124ScaleFactorMaximumCharge];
|
||||||
|
qCDebug(dcSunSpec()) << " - Setpoint maximum charging rate" << data[Model124ScaleFactorMaximumChargeDischargeRate];
|
||||||
|
qCDebug(dcSunSpec()) << " - Setpoint maximum charging rate" << data[Model124ScaleFactorAvailableEnergyPercent];
|
||||||
emit storageDataReceived(storageData);
|
emit storageDataReceived(storageData);
|
||||||
} break;
|
} break;
|
||||||
|
case SunSpec::ModelIdBatteryBaseModel:
|
||||||
|
case SunSpec::ModelIdLithiumIonBatteryModel: {
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,11 +38,12 @@ class SunSpecStorage : public QObject
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
SunSpecStorage(SunSpec *sunspec, SunSpec::BlockId blockId, int modbusAddress);
|
SunSpecStorage(SunSpec *sunspec, SunSpec::ModelId modelId, int modbusAddress);
|
||||||
|
|
||||||
SunSpec::BlockId blockId();
|
SunSpec::ModelId modelId();
|
||||||
void init();
|
void init();
|
||||||
void getStorageMap();
|
void getStorageModelHeader();
|
||||||
|
void getStorageModelDataBlock();
|
||||||
|
|
||||||
QUuid setGridCharging(bool enabled);
|
QUuid setGridCharging(bool enabled);
|
||||||
QUuid setDischargingRate(int rate);
|
QUuid setDischargingRate(int rate);
|
||||||
@ -93,15 +94,13 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
SunSpec *m_connection = nullptr;
|
SunSpec *m_connection = nullptr;
|
||||||
SunSpec::BlockId m_id = SunSpec::BlockIdEnergyStorageBaseModel;
|
SunSpec::ModelId m_id = SunSpec::ModelIdEnergyStorageBaseModel;
|
||||||
uint m_mapLength = 0;
|
uint m_modelLength = 0;
|
||||||
uint m_mapModbusStartRegister = 40000;
|
uint m_modelModbusStartRegister = 40000;
|
||||||
bool m_initFinishedSuccess = false;
|
bool m_initFinishedSuccess = false;
|
||||||
|
|
||||||
void readStorageBlockHeader();
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onModbusMapReceived(SunSpec::BlockId mapId, uint mapLength, const QVector<quint16> &data);
|
void onModelDataBlockReceived(SunSpec::ModelId modelId, uint length, const QVector<quint16> &data);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void initFinished(bool success);
|
void initFinished(bool success);
|
||||||
|
|||||||
@ -60,7 +60,7 @@ public:
|
|||||||
void getTrackerMap();
|
void getTrackerMap();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BlockId m_id = BlockIdTrackerController;
|
ModelId m_id = ModelIdTrackerController;
|
||||||
uint m_mapLength = 0;
|
uint m_mapLength = 0;
|
||||||
uint m_mapModbusStartRegister = 40000;
|
uint m_mapModbusStartRegister = 40000;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user