improved sunspec storage
This commit is contained in:
parent
b536b1b16e
commit
c112e1e6a0
@ -140,81 +140,37 @@ void IntegrationPluginSunSpec::setupThing(ThingSetupInfo *info)
|
|||||||
thing->thingClassId() == sunspecSplitPhaseInverterThingClassId ||
|
thing->thingClassId() == sunspecSplitPhaseInverterThingClassId ||
|
||||||
thing->thingClassId() == sunspecSinglePhaseInverterThingClassId ) {
|
thing->thingClassId() == sunspecSinglePhaseInverterThingClassId ) {
|
||||||
|
|
||||||
uint modelId = thing->paramValue(m_modelIdParamTypeIds.value(thing->thingClassId())).toInt();
|
Thing *parent = myThings().findById(thing->parentId());
|
||||||
int modbusAddress = thing->paramValue(m_modbusAddressParamTypeIds.value(thing->thingClassId())).toInt();
|
if (parent->setupStatus() == Thing::ThingSetupStatusComplete) {
|
||||||
SunSpec *connection = m_sunSpecConnections.value(thing->parentId());
|
setupInverter(info);
|
||||||
if (!connection) {
|
} else {
|
||||||
qCWarning(dcSunSpec()) << "Could not find SunSpec connection";
|
connect(parent, &Thing::setupStatusChanged, info, [this, info] {
|
||||||
return info->finish(Thing::ThingErrorHardwareNotAvailable);
|
setupInverter(info);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
SunSpecInverter *sunSpecInverter = new SunSpecInverter(connection, SunSpec::ModelId(modelId), modbusAddress);
|
|
||||||
sunSpecInverter->init();
|
|
||||||
connect(sunSpecInverter, &SunSpecInverter::initFinished, info, [this, sunSpecInverter, info] (bool success){
|
|
||||||
qCDebug(dcSunSpec()) << "Modbus Inverter init finished, success:" << success;
|
|
||||||
if (success) {
|
|
||||||
m_sunSpecInverters.insert(info->thing(), sunSpecInverter);
|
|
||||||
info->finish(Thing::ThingErrorNoError);
|
|
||||||
} else {
|
|
||||||
info->finish(Thing::ThingErrorHardwareNotAvailable);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(info, &ThingSetupInfo::aborted, sunSpecInverter, &SunSpecInverter::deleteLater);
|
|
||||||
connect(sunSpecInverter, &SunSpecInverter::destroyed, thing, [thing, this] {m_sunSpecInverters.remove(thing);});
|
|
||||||
connect(sunSpecInverter, &SunSpecInverter::inverterDataReceived, this, &IntegrationPluginSunSpec::onInverterDataReceived);
|
|
||||||
|
|
||||||
} else if (thing->thingClassId() == sunspecSinglePhaseMeterThingClassId ||
|
} else if (thing->thingClassId() == sunspecSinglePhaseMeterThingClassId ||
|
||||||
thing->thingClassId() == sunspecSplitPhaseMeterThingClassId ||
|
thing->thingClassId() == sunspecSplitPhaseMeterThingClassId ||
|
||||||
thing->thingClassId() == sunspecThreePhaseMeterThingClassId) {
|
thing->thingClassId() == sunspecThreePhaseMeterThingClassId) {
|
||||||
|
|
||||||
uint modelId = thing->paramValue(m_modelIdParamTypeIds.value(thing->thingClassId())).toInt();
|
Thing *parent = myThings().findById(thing->parentId());
|
||||||
int modbusAddress = thing->paramValue(m_modbusAddressParamTypeIds.value(thing->thingClassId())).toInt();
|
if (parent->setupStatus() == Thing::ThingSetupStatusComplete) {
|
||||||
SunSpec *connection = m_sunSpecConnections.value(thing->parentId());
|
setupMeter(info);
|
||||||
if (!connection) {
|
} else {
|
||||||
qCWarning(dcSunSpec()) << "Could not find SunSpec connection";
|
connect(parent, &Thing::setupStatusChanged, info, [this, info] {
|
||||||
return info->finish(Thing::ThingErrorHardwareNotAvailable);
|
setupMeter(info);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
SunSpecMeter *sunSpecMeter = new SunSpecMeter(connection, SunSpec::ModelId(modelId), modbusAddress);
|
|
||||||
sunSpecMeter->init();
|
|
||||||
connect(sunSpecMeter, &SunSpecMeter::initFinished, info, [this, sunSpecMeter, info] (bool success){
|
|
||||||
qCDebug(dcSunSpec()) << "Modbus meter init finished, success:" << success;
|
|
||||||
if (success) {
|
|
||||||
m_sunSpecMeters.insert(info->thing(), sunSpecMeter);
|
|
||||||
info->finish(Thing::ThingErrorNoError);
|
|
||||||
} else {
|
|
||||||
info->finish(Thing::ThingErrorHardwareNotAvailable);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(info, &ThingSetupInfo::aborted, sunSpecMeter, &SunSpecMeter::deleteLater);
|
|
||||||
connect(sunSpecMeter, &SunSpecMeter::destroyed, thing, [thing, this] {m_sunSpecMeters.remove(thing);});
|
|
||||||
connect(sunSpecMeter, &SunSpecMeter::meterDataReceived, this, &IntegrationPluginSunSpec::onMeterDataReceived);
|
|
||||||
|
|
||||||
} else if (info->thing()->thingClassId() == sunspecStorageThingClassId) {
|
} else if (info->thing()->thingClassId() == sunspecStorageThingClassId) {
|
||||||
|
|
||||||
uint modelId = thing->paramValue(m_modelIdParamTypeIds.value(thing->thingClassId())).toInt();
|
Thing *parent = myThings().findById(thing->parentId());
|
||||||
int modbusAddress = thing->paramValue(m_modbusAddressParamTypeIds.value(thing->thingClassId())).toInt();
|
if (parent->setupStatus() == Thing::ThingSetupStatusComplete) {
|
||||||
SunSpec *connection = m_sunSpecConnections.value(thing->parentId());
|
setupStorage(info);
|
||||||
if (!connection) {
|
} else {
|
||||||
qCWarning(dcSunSpec()) << "Could not find SunSpec connection";
|
connect(parent, &Thing::setupStatusChanged, info, [this, info] {
|
||||||
return info->finish(Thing::ThingErrorHardwareNotAvailable);
|
setupStorage(info);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
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());
|
||||||
}
|
}
|
||||||
@ -353,15 +309,16 @@ void IntegrationPluginSunSpec::executeAction(ThingActionInfo *info)
|
|||||||
m_asyncActions.insert(requestId, info);
|
m_asyncActions.insert(requestId, info);
|
||||||
connect(info, &ThingActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);});
|
connect(info, &ThingActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);});
|
||||||
}
|
}
|
||||||
} else if (action.actionTypeId() == sunspecStorageEnableChargingLimitActionTypeId) {
|
} else if (action.actionTypeId() == sunspecStorageEnableChargingActionTypeId) {
|
||||||
/*int value = (action.param(sunspecStorageEnableChargingLimitActionEnableChargingLimitParamTypeId).value().toBool() << 1) | thing->stateValue(sunspecStorageEnableDischargingLimitStateTypeId).toBool();
|
bool charging = action.param(sunspecStorageEnableChargingActionEnableChargingParamTypeId).value().toBool();
|
||||||
QUuid requestId = sunSpecStorage->setStorageControlMode(value);
|
bool discharging = thing->stateValue(sunspecStorageEnableDischargingStateTypeId).toBool();
|
||||||
|
QUuid requestId = sunSpecStorage->setStorageControlMode(charging, discharging);
|
||||||
if (requestId.isNull()) {
|
if (requestId.isNull()) {
|
||||||
info->finish(Thing::ThingErrorHardwareFailure);
|
info->finish(Thing::ThingErrorHardwareFailure);
|
||||||
} else {
|
} else {
|
||||||
m_asyncActions.insert(requestId, info);
|
m_asyncActions.insert(requestId, info);
|
||||||
connect(info, &ThingActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);});
|
connect(info, &ThingActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);});
|
||||||
}*/
|
}
|
||||||
} else if (action.actionTypeId() == sunspecStorageChargingRateActionTypeId) {
|
} else if (action.actionTypeId() == sunspecStorageChargingRateActionTypeId) {
|
||||||
QUuid requestId = sunSpecStorage->setChargingRate(action.param(sunspecStorageChargingRateActionChargingRateParamTypeId).value().toInt());
|
QUuid requestId = sunSpecStorage->setChargingRate(action.param(sunspecStorageChargingRateActionChargingRateParamTypeId).value().toInt());
|
||||||
if (requestId.isNull()) {
|
if (requestId.isNull()) {
|
||||||
@ -370,15 +327,16 @@ void IntegrationPluginSunSpec::executeAction(ThingActionInfo *info)
|
|||||||
m_asyncActions.insert(requestId, info);
|
m_asyncActions.insert(requestId, info);
|
||||||
connect(info, &ThingActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);});
|
connect(info, &ThingActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);});
|
||||||
}
|
}
|
||||||
} else if (action.actionTypeId() == sunspecStorageEnableDischargingLimitActionTypeId) {
|
} else if (action.actionTypeId() == sunspecStorageEnableDischargingActionTypeId) {
|
||||||
/*int value = (action.param(sunspecStorageEnableDischargingLimitActionEnableDischargingLimitParamTypeId).value().toBool() << 1) | thing->stateValue(sunspecStorageEnableChargingLimitStateTypeId).toBool();
|
bool discharging = action.param(sunspecStorageEnableDischargingActionEnableDischargingParamTypeId).value().toBool();
|
||||||
QUuid requestId = sunSpecStorage->setStorageControlMode(value);
|
bool charging = thing->stateValue(sunspecStorageEnableChargingStateTypeId).toBool();
|
||||||
|
QUuid requestId = sunSpecStorage->setStorageControlMode(charging, discharging);
|
||||||
if (requestId.isNull()) {
|
if (requestId.isNull()) {
|
||||||
info->finish(Thing::ThingErrorHardwareFailure);
|
info->finish(Thing::ThingErrorHardwareFailure);
|
||||||
} else {
|
} else {
|
||||||
m_asyncActions.insert(requestId, info);
|
m_asyncActions.insert(requestId, info);
|
||||||
connect(info, &ThingActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);});
|
connect(info, &ThingActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);});
|
||||||
}*/
|
}
|
||||||
} else if (action.actionTypeId() == sunspecStorageDischargingRateActionTypeId) {
|
} else if (action.actionTypeId() == sunspecStorageDischargingRateActionTypeId) {
|
||||||
QUuid requestId = sunSpecStorage->setDischargingRate(action.param(sunspecStorageDischargingRateActionDischargingRateParamTypeId).value().toInt());
|
QUuid requestId = sunSpecStorage->setDischargingRate(action.param(sunspecStorageDischargingRateActionDischargingRateParamTypeId).value().toInt());
|
||||||
if (requestId.isNull()) {
|
if (requestId.isNull()) {
|
||||||
@ -406,6 +364,88 @@ bool IntegrationPluginSunSpec::checkIfThingExists(uint modelId, uint modbusAddre
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IntegrationPluginSunSpec::setupInverter(ThingSetupInfo *info)
|
||||||
|
{
|
||||||
|
Thing *thing = info->thing();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
SunSpecInverter *sunSpecInverter = new SunSpecInverter(connection, SunSpec::ModelId(modelId), modbusAddress);
|
||||||
|
sunSpecInverter->init();
|
||||||
|
connect(sunSpecInverter, &SunSpecInverter::initFinished, info, [this, sunSpecInverter, info] (bool success){
|
||||||
|
qCDebug(dcSunSpec()) << "Modbus Inverter init finished, success:" << success;
|
||||||
|
if (success) {
|
||||||
|
m_sunSpecInverters.insert(info->thing(), sunSpecInverter);
|
||||||
|
info->finish(Thing::ThingErrorNoError);
|
||||||
|
} else {
|
||||||
|
info->finish(Thing::ThingErrorHardwareNotAvailable);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(info, &ThingSetupInfo::aborted, sunSpecInverter, &SunSpecInverter::deleteLater);
|
||||||
|
connect(sunSpecInverter, &SunSpecInverter::destroyed, thing, [thing, this] {m_sunSpecInverters.remove(thing);});
|
||||||
|
connect(sunSpecInverter, &SunSpecInverter::inverterDataReceived, this, &IntegrationPluginSunSpec::onInverterDataReceived);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IntegrationPluginSunSpec::setupMeter(ThingSetupInfo *info)
|
||||||
|
{
|
||||||
|
Thing *thing = info->thing();
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
SunSpecMeter *sunSpecMeter = new SunSpecMeter(connection, SunSpec::ModelId(modelId), modbusAddress);
|
||||||
|
sunSpecMeter->init();
|
||||||
|
connect(sunSpecMeter, &SunSpecMeter::initFinished, info, [this, sunSpecMeter, info] (bool success){
|
||||||
|
qCDebug(dcSunSpec()) << "Modbus meter init finished, success:" << success;
|
||||||
|
if (success) {
|
||||||
|
m_sunSpecMeters.insert(info->thing(), sunSpecMeter);
|
||||||
|
info->finish(Thing::ThingErrorNoError);
|
||||||
|
} else {
|
||||||
|
info->finish(Thing::ThingErrorHardwareNotAvailable);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(info, &ThingSetupInfo::aborted, sunSpecMeter, &SunSpecMeter::deleteLater);
|
||||||
|
connect(sunSpecMeter, &SunSpecMeter::destroyed, thing, [thing, this] {m_sunSpecMeters.remove(thing);});
|
||||||
|
connect(sunSpecMeter, &SunSpecMeter::meterDataReceived, this, &IntegrationPluginSunSpec::onMeterDataReceived);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IntegrationPluginSunSpec::setupStorage(ThingSetupInfo *info)
|
||||||
|
{
|
||||||
|
Thing *thing = info->thing();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
void IntegrationPluginSunSpec::onRefreshTimer()
|
void IntegrationPluginSunSpec::onRefreshTimer()
|
||||||
{
|
{
|
||||||
foreach (SunSpec *connection, m_sunSpecConnections) {
|
foreach (SunSpec *connection, m_sunSpecConnections) {
|
||||||
@ -437,13 +477,11 @@ void IntegrationPluginSunSpec::onPluginConfigurationChanged(const ParamTypeId &p
|
|||||||
Q_FOREACH(SunSpec *connection, m_sunSpecConnections) {
|
Q_FOREACH(SunSpec *connection, m_sunSpecConnections) {
|
||||||
connection->setNumberOfRetries(value.toUInt());
|
connection->setNumberOfRetries(value.toUInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (paramTypeId == sunSpecPluginTimeoutParamTypeId) {
|
} else if (paramTypeId == sunSpecPluginTimeoutParamTypeId) {
|
||||||
qCDebug(dcSunSpec()) << "Updating timeout" << value.toUInt() << "[ms]";
|
qCDebug(dcSunSpec()) << "Updating timeout" << value.toUInt() << "[ms]";
|
||||||
Q_FOREACH(SunSpec *connection, m_sunSpecConnections) {
|
Q_FOREACH(SunSpec *connection, m_sunSpecConnections) {
|
||||||
connection->setTimeout(value.toUInt());
|
connection->setTimeout(value.toUInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcSunSpec()) << "Unknown plugin configuration" << paramTypeId << "Value" << value;
|
qCWarning(dcSunSpec()) << "Unknown plugin configuration" << paramTypeId << "Value" << value;
|
||||||
}
|
}
|
||||||
@ -474,7 +512,7 @@ void IntegrationPluginSunSpec::onFoundSunSpecModel(SunSpec::ModelId modelId, int
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qCDebug(dcSunSpec()) << "On model received" << modelId << "length" << modbusStartRegister << "Thing:" << thing->name();
|
qCDebug(dcSunSpec()) << "On model received" << modelId << "start register" << modbusStartRegister << "Thing:" << thing->name();
|
||||||
if (checkIfThingExists(modelId, modbusStartRegister)) {
|
if (checkIfThingExists(modelId, modbusStartRegister)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -510,7 +548,7 @@ void IntegrationPluginSunSpec::onFoundSunSpecModel(SunSpec::ModelId modelId, int
|
|||||||
|
|
||||||
case SunSpec::ModelIdSinglePhaseMeter:
|
case SunSpec::ModelIdSinglePhaseMeter:
|
||||||
case SunSpec::ModelIdSinglePhaseMeterFloat: {
|
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(sunspecSinglePhaseMeterThingModelIdParamTypeId, modelId));
|
params.append(Param(sunspecSinglePhaseMeterThingModelIdParamTypeId, modelId));
|
||||||
params.append(Param(sunspecSinglePhaseMeterThingModbusAddressParamTypeId, modbusStartRegister));
|
params.append(Param(sunspecSinglePhaseMeterThingModbusAddressParamTypeId, modbusStartRegister));
|
||||||
@ -519,7 +557,7 @@ void IntegrationPluginSunSpec::onFoundSunSpecModel(SunSpec::ModelId modelId, int
|
|||||||
} break;
|
} break;
|
||||||
case SunSpec::ModelIdSplitSinglePhaseMeter:
|
case SunSpec::ModelIdSplitSinglePhaseMeter:
|
||||||
case SunSpec::ModelIdSplitSinglePhaseMeterFloat: {
|
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(sunspecSplitPhaseMeterThingModelIdParamTypeId, modelId));
|
params.append(Param(sunspecSplitPhaseMeterThingModelIdParamTypeId, modelId));
|
||||||
params.append(Param(sunspecSplitPhaseMeterThingModbusAddressParamTypeId, modbusStartRegister));
|
params.append(Param(sunspecSplitPhaseMeterThingModbusAddressParamTypeId, modbusStartRegister));
|
||||||
@ -528,7 +566,7 @@ void IntegrationPluginSunSpec::onFoundSunSpecModel(SunSpec::ModelId modelId, int
|
|||||||
} break;
|
} break;
|
||||||
case SunSpec::ModelIdWyeConnectThreePhaseMeterFloat:
|
case SunSpec::ModelIdWyeConnectThreePhaseMeterFloat:
|
||||||
case SunSpec::ModelIdDeltaConnectThreePhaseMeterFloat: {
|
case SunSpec::ModelIdDeltaConnectThreePhaseMeterFloat: {
|
||||||
ThingDescriptor descriptor(sunspecThreePhaseMeterThingClassId, model+" Meter", "", thing->id());
|
ThingDescriptor descriptor(sunspecThreePhaseMeterThingClassId, model+" meter", "", thing->id());
|
||||||
ParamList params;
|
ParamList params;
|
||||||
params.append(Param(sunspecThreePhaseMeterThingModelIdParamTypeId, modelId));
|
params.append(Param(sunspecThreePhaseMeterThingModelIdParamTypeId, modelId));
|
||||||
params.append(Param(sunspecThreePhaseMeterThingModbusAddressParamTypeId, modbusStartRegister));
|
params.append(Param(sunspecThreePhaseMeterThingModbusAddressParamTypeId, modbusStartRegister));
|
||||||
@ -536,10 +574,10 @@ void IntegrationPluginSunSpec::onFoundSunSpecModel(SunSpec::ModelId modelId, int
|
|||||||
emit autoThingsAppeared({descriptor});
|
emit autoThingsAppeared({descriptor});
|
||||||
} break;
|
} break;
|
||||||
case SunSpec::ModelIdStorage: {
|
case SunSpec::ModelIdStorage: {
|
||||||
ThingDescriptor descriptor(sunspecStorageThingClassId, model+" Storage", "", thing->id());
|
ThingDescriptor descriptor(sunspecStorageThingClassId, model+" storage", "", thing->id());
|
||||||
ParamList params;
|
ParamList params;
|
||||||
params.append(Param(sunspecStorageThingModelIdParamTypeId, modelId));
|
params.append(Param(sunspecStorageThingModelIdParamTypeId, modelId));
|
||||||
params.append(Param(sunspecThreePhaseInverterThingModbusAddressParamTypeId, modbusStartRegister));
|
params.append(Param(sunspecStorageThingModbusAddressParamTypeId, modbusStartRegister));
|
||||||
descriptor.setParams(params);
|
descriptor.setParams(params);
|
||||||
emit autoThingsAppeared({descriptor});
|
emit autoThingsAppeared({descriptor});
|
||||||
} break;
|
} break;
|
||||||
@ -556,9 +594,7 @@ void IntegrationPluginSunSpec::onSunSpecModelSearchFinished(const QHash<SunSpec:
|
|||||||
qCWarning(dcSunSpec()) << "Thing not found for SunSpec connection" << connection->deviceModel() << connection->serialNumber();
|
qCWarning(dcSunSpec()) << "Thing not found for SunSpec connection" << connection->deviceModel() << connection->serialNumber();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qCDebug(dcSunSpec()) << "On sunspec model search finished, models:" << modelIds.count();
|
qCDebug(dcSunSpec()) << "On sunspec model search finished, models:" << modelIds.count();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntegrationPluginSunSpec::onWriteRequestExecuted(QUuid requestId, bool success)
|
void IntegrationPluginSunSpec::onWriteRequestExecuted(QUuid requestId, bool success)
|
||||||
@ -589,7 +625,6 @@ void IntegrationPluginSunSpec::onInverterDataReceived(const SunSpecInverter::Inv
|
|||||||
thing->setStateValue(sunspecThreePhaseInverterTotalCurrentStateTypeId, inverterData.acCurrent);
|
thing->setStateValue(sunspecThreePhaseInverterTotalCurrentStateTypeId, inverterData.acCurrent);
|
||||||
thing->setStateValue(sunspecThreePhaseInverterCabinetTemperatureStateTypeId, inverterData.cabinetTemperature);
|
thing->setStateValue(sunspecThreePhaseInverterCabinetTemperatureStateTypeId, inverterData.cabinetTemperature);
|
||||||
|
|
||||||
|
|
||||||
if (thing->thingClassId() == sunspecSplitPhaseMeterThingClassId) {
|
if (thing->thingClassId() == sunspecSplitPhaseMeterThingClassId) {
|
||||||
|
|
||||||
thing->setStateValue(sunspecSplitPhaseInverterPhaseANVoltageStateTypeId, inverterData.phaseVoltageAN);
|
thing->setStateValue(sunspecSplitPhaseInverterPhaseANVoltageStateTypeId, inverterData.phaseVoltageAN);
|
||||||
@ -609,7 +644,6 @@ void IntegrationPluginSunSpec::onInverterDataReceived(const SunSpecInverter::Inv
|
|||||||
thing->setStateValue(sunspecThreePhaseInverterPhaseCCurrentStateTypeId, inverterData.phaseCCurrent);
|
thing->setStateValue(sunspecThreePhaseInverterPhaseCCurrentStateTypeId, inverterData.phaseCCurrent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
switch(inverterData.operatingState) {
|
switch(inverterData.operatingState) {
|
||||||
case SunSpec::SunSpecOperatingState::Off:
|
case SunSpec::SunSpecOperatingState::Off:
|
||||||
thing->setStateValue(sunspecThreePhaseInverterOperatingStateStateTypeId, "Off");
|
thing->setStateValue(sunspecThreePhaseInverterOperatingStateStateTypeId, "Off");
|
||||||
@ -689,7 +723,7 @@ void IntegrationPluginSunSpec::onInverterDataReceived(const SunSpecInverter::Inv
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntegrationPluginSunSpec::onStorageDataReceived(const SunSpecStorage::StorageData &storageData)
|
void IntegrationPluginSunSpec::onStorageDataReceived(const SunSpecStorage::StorageData &mandatory, const SunSpecStorage::StorageDataOptional &optional)
|
||||||
{
|
{
|
||||||
SunSpecStorage *storage = static_cast<SunSpecStorage *>(sender());
|
SunSpecStorage *storage = static_cast<SunSpecStorage *>(sender());
|
||||||
Thing *thing = m_sunSpecStorages.key(storage);
|
Thing *thing = m_sunSpecStorages.key(storage);
|
||||||
@ -698,7 +732,37 @@ void IntegrationPluginSunSpec::onStorageDataReceived(const SunSpecStorage::Stora
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), true);
|
thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), true);
|
||||||
thing->setStateValue(sunspecStorageStorageStateStateTypeId, storageData.chargingState);
|
|
||||||
|
thing->setStateValue(sunspecStorageChargingRateStateTypeId, mandatory.maxChargeRate);
|
||||||
|
thing->setStateValue(sunspecStorageDischargingRateStateTypeId, mandatory.maxDischargeRate);
|
||||||
|
|
||||||
|
bool charging = false;
|
||||||
|
switch (optional.chargeSatus) {
|
||||||
|
case SunSpecStorage::ChargingStatusOff:
|
||||||
|
thing->setStateValue(sunspecStorageStorageStatusStateTypeId, "Off");
|
||||||
|
break;
|
||||||
|
case SunSpecStorage::ChargingStatusFull:
|
||||||
|
thing->setStateValue(sunspecStorageStorageStatusStateTypeId, "Full");
|
||||||
|
break;
|
||||||
|
case SunSpecStorage::ChargingStatusEmpty:
|
||||||
|
thing->setStateValue(sunspecStorageStorageStatusStateTypeId, "Empty");
|
||||||
|
break;
|
||||||
|
case SunSpecStorage::ChargingStatusHolding:
|
||||||
|
thing->setStateValue(sunspecStorageStorageStatusStateTypeId, "Holding");
|
||||||
|
break;
|
||||||
|
case SunSpecStorage::ChargingStatusTesting:
|
||||||
|
thing->setStateValue(sunspecStorageStorageStatusStateTypeId, "Testing");
|
||||||
|
break;
|
||||||
|
case SunSpecStorage::ChargingStatusCharging:
|
||||||
|
thing->setStateValue(sunspecStorageStorageStatusStateTypeId, "Charging");
|
||||||
|
break;
|
||||||
|
case SunSpecStorage::ChargingStatusDischarging:
|
||||||
|
thing->setStateValue(sunspecStorageStorageStatusStateTypeId, "Discharging");
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
double batteryLevel = optional.currentlyAvailableEnergy;
|
||||||
|
thing->setStateValue(sunspecStorageBatteryLevelStateTypeId, batteryLevel);
|
||||||
|
thing->setStateValue(sunspecStorageBatteryCriticalStateTypeId, (batteryLevel < 5 && !charging));
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntegrationPluginSunSpec::onMeterDataReceived(const SunSpecMeter::MeterData &meterData)
|
void IntegrationPluginSunSpec::onMeterDataReceived(const SunSpecMeter::MeterData &meterData)
|
||||||
|
|||||||
@ -79,6 +79,10 @@ private:
|
|||||||
|
|
||||||
bool checkIfThingExists(uint modelId, uint modbusAddress);
|
bool checkIfThingExists(uint modelId, uint modbusAddress);
|
||||||
|
|
||||||
|
void setupInverter(ThingSetupInfo *info);
|
||||||
|
void setupMeter(ThingSetupInfo *info);
|
||||||
|
void setupStorage(ThingSetupInfo *info);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onRefreshTimer();
|
void onRefreshTimer();
|
||||||
|
|
||||||
@ -93,7 +97,7 @@ private slots:
|
|||||||
void onWriteRequestError(QUuid requestId, const QString &error);
|
void onWriteRequestError(QUuid requestId, const QString &error);
|
||||||
|
|
||||||
void onInverterDataReceived(const SunSpecInverter::InverterData &inverterData);
|
void onInverterDataReceived(const SunSpecInverter::InverterData &inverterData);
|
||||||
void onStorageDataReceived(const SunSpecStorage::StorageData &storageData);
|
void onStorageDataReceived(const SunSpecStorage::StorageData &mandatory, const SunSpecStorage::StorageDataOptional &optional);
|
||||||
void onMeterDataReceived(const SunSpecMeter::MeterData &meterData);
|
void onMeterDataReceived(const SunSpecMeter::MeterData &meterData);
|
||||||
};
|
};
|
||||||
#endif // INTEGRATIONPLUGINSUNSPEC_H
|
#endif // INTEGRATIONPLUGINSUNSPEC_H
|
||||||
|
|||||||
@ -998,9 +998,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "da2b19c5-0f48-49d1-93f0-abdc0051407d",
|
"id": "da2b19c5-0f48-49d1-93f0-abdc0051407d",
|
||||||
"name": "storageState",
|
"name": "storageStatus",
|
||||||
"displayName": "State",
|
"displayName": "Status",
|
||||||
"displayNameEvent": "State changed",
|
"displayNameEvent": "Status changed",
|
||||||
"type": "QString",
|
"type": "QString",
|
||||||
"possibleValues": [
|
"possibleValues": [
|
||||||
"Off",
|
"Off",
|
||||||
@ -1025,13 +1025,23 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "1f530f79-c0d2-466b-90e1-79149e34d92f",
|
"id": "1f530f79-c0d2-466b-90e1-79149e34d92f",
|
||||||
"name": "enableChargingLimit",
|
"name": "enableCharging",
|
||||||
"displayName": "Charging limit",
|
"displayName": "Charging",
|
||||||
"displayNameEvent": "Charging limit changed",
|
"displayNameEvent": "Charging changed",
|
||||||
|
"displayNameAction": "Enable charging",
|
||||||
"type": "bool",
|
"type": "bool",
|
||||||
"defaultValue": false,
|
"defaultValue": false,
|
||||||
"writable": true,
|
"writable": true
|
||||||
"displayNameAction": "Enable Charging Limit"
|
},
|
||||||
|
{
|
||||||
|
"id": "bc99a159-815a-40ab-a6e8-b46f315305f7",
|
||||||
|
"name": "enableDischarging",
|
||||||
|
"displayName": "Discharging",
|
||||||
|
"displayNameEvent": "Discharging changed",
|
||||||
|
"displayNameAction": "Enable discharging",
|
||||||
|
"type": "bool",
|
||||||
|
"defaultValue": false,
|
||||||
|
"writable": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "7f469bbc-64a5-4045-8d5f-9a1a85039851",
|
"id": "7f469bbc-64a5-4045-8d5f-9a1a85039851",
|
||||||
@ -1039,30 +1049,20 @@
|
|||||||
"displayName": "Charging rate",
|
"displayName": "Charging rate",
|
||||||
"displayNameEvent": "Charging rate changed",
|
"displayNameEvent": "Charging rate changed",
|
||||||
"type": "int",
|
"type": "int",
|
||||||
"minValue": -100,
|
"minValue": 0,
|
||||||
"maxValue": 100,
|
"maxValue": 100,
|
||||||
"unit": "Percentage",
|
"unit": "Percentage",
|
||||||
"defaultValue": false,
|
"defaultValue": false,
|
||||||
"writable": true,
|
"writable": true,
|
||||||
"displayNameAction": "Set charging rate"
|
"displayNameAction": "Set charging rate"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "bc99a159-815a-40ab-a6e8-b46f315305f7",
|
|
||||||
"name": "enableDischargingLimit",
|
|
||||||
"displayName": "Discharging limit",
|
|
||||||
"displayNameEvent": "Discharging limit changed",
|
|
||||||
"displayNameAction": "Enable Discharging Limit",
|
|
||||||
"type": "bool",
|
|
||||||
"defaultValue": false,
|
|
||||||
"writable": true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "6068f030-acce-44a2-b95f-bd00dd5ca760",
|
"id": "6068f030-acce-44a2-b95f-bd00dd5ca760",
|
||||||
"name": "dischargingRate",
|
"name": "dischargingRate",
|
||||||
"displayName": "Discharging rate",
|
"displayName": "Discharging rate",
|
||||||
"displayNameEvent": "Discharging rate changed",
|
"displayNameEvent": "Discharging rate changed",
|
||||||
"type": "int",
|
"type": "int",
|
||||||
"minValue": -100,
|
"minValue": 0,
|
||||||
"maxValue": 100,
|
"maxValue": 100,
|
||||||
"unit": "Percentage",
|
"unit": "Percentage",
|
||||||
"defaultValue": false,
|
"defaultValue": false,
|
||||||
|
|||||||
@ -226,20 +226,20 @@ void SunSpec::readModelHeader(uint modbusAddress)
|
|||||||
qCDebug(dcSunSpec()) << "SunSpec: Received model header response. Model ID:" << modelId << "length" << length;
|
qCDebug(dcSunSpec()) << "SunSpec: Received model header response. Model ID:" << modelId << "length" << length;
|
||||||
modelHeaderReceived(modbusAddress, modelId, length);
|
modelHeaderReceived(modbusAddress, modelId, length);
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcSunSpec()) << "SunSpec: Read response error:" << reply->error();
|
qCWarning(dcSunSpec()) << "SunSpec: Read model header response error:" << reply->error();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
connect(reply, &QModbusReply::errorOccurred, this, [reply] (QModbusDevice::Error error) {
|
connect(reply, &QModbusReply::errorOccurred, this, [reply] (QModbusDevice::Error error) {
|
||||||
qCWarning(dcSunSpec()) << "SunSpec: Modbus reply error:" << error;
|
qCWarning(dcSunSpec()) << "SunSpec: Read model header, 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()) << "SunSpec: Read error: " << m_modbusTcpClient->errorString();
|
qCWarning(dcSunSpec()) << "SunSpec: Read model header error: " << m_modbusTcpClient->errorString();
|
||||||
delete reply; // broadcast replies return immediately
|
delete reply; // broadcast replies return immediately
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qCWarning(dcSunSpec()) << "SunSpec: Read error: " << m_modbusTcpClient->errorString();
|
qCWarning(dcSunSpec()) << "SunSpec: Read model header error: " << m_modbusTcpClient->errorString();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -248,6 +248,11 @@ void SunSpec::readModelDataBlock(uint modbusAddress, uint length)
|
|||||||
{
|
{
|
||||||
qCDebug(dcSunSpec()) << "SunSpec: Read model, modbus address" << modbusAddress << "length" << length << ", Slave ID" << m_slaveId;
|
qCDebug(dcSunSpec()) << "SunSpec: Read model, modbus address" << modbusAddress << "length" << length << ", Slave ID" << m_slaveId;
|
||||||
|
|
||||||
|
if (length > 125) { //Modbus register limit is 125
|
||||||
|
qCWarning(dcSunSpec()) << "SunSpec: Data block length is too long, max 125 register";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, modbusAddress, length+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)) {
|
||||||
|
|||||||
@ -53,10 +53,12 @@ void SunSpecInverter::init()
|
|||||||
qCDebug(dcSunSpec()) << "SunSpecInverter: Init";
|
qCDebug(dcSunSpec()) << "SunSpecInverter: Init";
|
||||||
m_connection->readModelHeader(m_modelModbusStartRegister);
|
m_connection->readModelHeader(m_modelModbusStartRegister);
|
||||||
connect(m_connection, &SunSpec::modelHeaderReceived, this, [this] (uint modbusAddress, SunSpec::ModelId modelId, uint length) {
|
connect(m_connection, &SunSpec::modelHeaderReceived, this, [this] (uint modbusAddress, SunSpec::ModelId modelId, uint length) {
|
||||||
qCDebug(dcSunSpec()) << "SunSpecInverter: Model Header received, modbus address:" << modbusAddress << "model Id:" << modelId << "length:" << length;
|
if (modelId == m_id) {
|
||||||
m_modelLength = length;
|
qCDebug(dcSunSpec()) << "SunSpecInverter: Model Header received, modbus address:" << modbusAddress << "model Id:" << modelId << "length:" << length;
|
||||||
emit initFinished(true);
|
m_modelLength = length;
|
||||||
m_initFinishedSuccess = true;
|
emit initFinished(true);
|
||||||
|
m_initFinishedSuccess = true;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
QTimer::singleShot(10000, this,[this] {
|
QTimer::singleShot(10000, this,[this] {
|
||||||
if (!m_initFinishedSuccess) {
|
if (!m_initFinishedSuccess) {
|
||||||
@ -67,12 +69,13 @@ void SunSpecInverter::init()
|
|||||||
|
|
||||||
void SunSpecInverter::getInverterModelDataBlock()
|
void SunSpecInverter::getInverterModelDataBlock()
|
||||||
{
|
{
|
||||||
// TODO check map length to modbus max value
|
qCDebug(dcSunSpec()) << "SunSpecInverter: get inverter model data block, modbus register" << m_modelModbusStartRegister << "length" << m_modelLength;
|
||||||
m_connection->readModelDataBlock(m_modelModbusStartRegister, m_modelLength);
|
m_connection->readModelDataBlock(m_modelModbusStartRegister, m_modelLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SunSpecInverter::getInverterModelHeader()
|
void SunSpecInverter::getInverterModelHeader()
|
||||||
{
|
{
|
||||||
|
qCDebug(dcSunSpec()) << "SunSpecInverter: get inverter model header, modbus register" << m_modelModbusStartRegister;
|
||||||
m_connection->readModelHeader(m_modelModbusStartRegister);
|
m_connection->readModelHeader(m_modelModbusStartRegister);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +86,7 @@ void SunSpecInverter::onModelDataBlockReceived(SunSpec::ModelId mapId, uint mapL
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mapLength < m_modelLength) {
|
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 is too short" << mapLength;
|
||||||
//return;
|
//return;
|
||||||
}
|
}
|
||||||
InverterData inverterData;
|
InverterData inverterData;
|
||||||
|
|||||||
@ -52,26 +52,30 @@ void SunSpecMeter::init()
|
|||||||
qCDebug(dcSunSpec()) << "SunSpecMeter: Init";
|
qCDebug(dcSunSpec()) << "SunSpecMeter: Init";
|
||||||
m_connection->readModelHeader(m_modelModbusStartRegister);
|
m_connection->readModelHeader(m_modelModbusStartRegister);
|
||||||
connect(m_connection, &SunSpec::modelHeaderReceived, this, [this] (uint modbusAddress, SunSpec::ModelId modelId, uint length) {
|
connect(m_connection, &SunSpec::modelHeaderReceived, this, [this] (uint modbusAddress, SunSpec::ModelId modelId, uint length) {
|
||||||
qCDebug(dcSunSpec()) << "SunSpecMeter: Model Header received, modbus address:" << modbusAddress << "model Id:" << modelId << "length:" << length;
|
if (modelId == m_id) {
|
||||||
m_modelLength = length;
|
qCDebug(dcSunSpec()) << "SunSpecMeter: Model Header received, modbus address:" << modbusAddress << "model Id:" << modelId << "length:" << length;
|
||||||
emit initFinished(true);
|
m_modelLength = length;
|
||||||
m_initFinishedSuccess = true;
|
emit initFinished(true);
|
||||||
|
m_initFinishedSuccess = true;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
QTimer::singleShot(10000, this,[this] {
|
QTimer::singleShot(10000, this,[this] {
|
||||||
if (!m_initFinishedSuccess) {
|
if (!m_initFinishedSuccess) {
|
||||||
emit initFinished(false);
|
emit initFinished(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void SunSpecMeter::getMeterModelDataBlock()
|
void SunSpecMeter::getMeterModelDataBlock()
|
||||||
{
|
{
|
||||||
m_connection->readModelDataBlock(m_modelModbusStartRegister, m_modelLength);
|
qCDebug(dcSunSpec()) << "SunSpecMeter: get meter model data block, modbus register" << m_modelModbusStartRegister << "length" << m_modelLength;
|
||||||
|
m_connection->readModelDataBlock(m_modelModbusStartRegister, m_modelLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SunSpecMeter::getMeterModelHeader()
|
void SunSpecMeter::getMeterModelHeader()
|
||||||
{
|
{
|
||||||
|
qCDebug(dcSunSpec()) << "SunSpecMeter: get meter model header, modbus register" << m_modelModbusStartRegister << "length" << m_modelLength;
|
||||||
|
m_connection->readModelHeader(m_modelModbusStartRegister);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SunSpecMeter::onModelDataBlockReceived(SunSpec::ModelId modelId, uint length, QVector<quint16> data)
|
void SunSpecMeter::onModelDataBlockReceived(SunSpec::ModelId modelId, uint length, QVector<quint16> data)
|
||||||
|
|||||||
@ -49,27 +49,31 @@ SunSpec::ModelId SunSpecStorage::modelId()
|
|||||||
void SunSpecStorage::init()
|
void SunSpecStorage::init()
|
||||||
{
|
{
|
||||||
qCDebug(dcSunSpec()) << "SunSpecStorage: Init";
|
qCDebug(dcSunSpec()) << "SunSpecStorage: Init";
|
||||||
m_connection->readModelHeader(m_modelModbusStartRegister);
|
getStorageModelHeader();
|
||||||
connect(m_connection, &SunSpec::modelHeaderReceived, this, [this] (uint modbusAddress, SunSpec::ModelId modelId, uint length) {
|
connect(m_connection, &SunSpec::modelHeaderReceived, this, [this] (uint modbusAddress, SunSpec::ModelId modelId, uint length) {
|
||||||
qCDebug(dcSunSpec()) << "SunSpecStorager: Model header received, modbus address:" << modbusAddress << "model Id:" << modelId << "length:" << length;
|
if (modelId == m_id) {
|
||||||
m_modelLength = length;
|
qCDebug(dcSunSpec()) << "SunSpecStorager: Model header received, modbus address:" << modbusAddress << "model Id:" << modelId << "length:" << length;
|
||||||
emit initFinished(true);
|
m_modelLength = length;
|
||||||
m_initFinishedSuccess = true;
|
emit initFinished(true);
|
||||||
|
m_initFinishedSuccess = true;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
QTimer::singleShot(10000, this,[this] {
|
QTimer::singleShot(10000, this, [this] {
|
||||||
if (!m_initFinishedSuccess) {
|
if (!m_initFinishedSuccess) {
|
||||||
emit initFinished(false);
|
emit initFinished(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void SunSpecStorage::getStorageModelDataBlock()
|
void SunSpecStorage::getStorageModelDataBlock()
|
||||||
{
|
{
|
||||||
|
qCDebug(dcSunSpec()) << "SunSpecStorage: get storage model data block, modbus register" << m_modelModbusStartRegister << "length" << m_modelLength;
|
||||||
m_connection->readModelDataBlock(m_modelModbusStartRegister, m_modelLength);
|
m_connection->readModelDataBlock(m_modelModbusStartRegister, m_modelLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SunSpecStorage::getStorageModelHeader()
|
void SunSpecStorage::getStorageModelHeader()
|
||||||
{
|
{
|
||||||
|
qCDebug(dcSunSpec()) << "SunSpecStorage: get storage model header, modbus register" << m_modelModbusStartRegister << "length" << m_modelLength;
|
||||||
m_connection->readModelHeader(m_modelModbusStartRegister);
|
m_connection->readModelHeader(m_modelModbusStartRegister);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +85,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_modelModbusStartRegister + Model124::Model124ChaGriSet;
|
uint registerAddress = m_modelModbusStartRegister + Model124Optional::Model124ChargeGridSet;
|
||||||
quint16 value = enabled;
|
quint16 value = enabled;
|
||||||
return m_connection->writeHoldingRegister(registerAddress, value);
|
return m_connection->writeHoldingRegister(registerAddress, value);
|
||||||
}
|
}
|
||||||
@ -89,8 +93,8 @@ QUuid SunSpecStorage::setGridCharging(bool enabled)
|
|||||||
QUuid SunSpecStorage::setStorageControlMode(bool chargingEnabled, bool dischargingEnabled)
|
QUuid SunSpecStorage::setStorageControlMode(bool chargingEnabled, bool dischargingEnabled)
|
||||||
{
|
{
|
||||||
// Set charge bit to enable charge limit, set discharge bit to enable discharge limit, set both bits to enable both limits
|
// Set charge bit to enable charge limit, set discharge bit to enable discharge limit, set both bits to enable both limits
|
||||||
quint16 value = ((static_cast<quint16>(chargingEnabled) << StorageControlBitFieldCharge) |
|
quint16 value = ((static_cast<quint16>(chargingEnabled)) |
|
||||||
(static_cast<quint16>(dischargingEnabled) << StorageControlBitFieldDischarge)) ;
|
(static_cast<quint16>(dischargingEnabled) << 1)) ;
|
||||||
|
|
||||||
uint modbusRegister = m_modelModbusStartRegister + Model124::Model124ActivateStorageControlMode;
|
uint modbusRegister = m_modelModbusStartRegister + Model124::Model124ActivateStorageControlMode;
|
||||||
return m_connection->writeHoldingRegister(modbusRegister, value);
|
return m_connection->writeHoldingRegister(modbusRegister, value);
|
||||||
@ -124,22 +128,38 @@ void SunSpecStorage::onModelDataBlockReceived(SunSpec::ModelId modelId, uint len
|
|||||||
|
|
||||||
switch (modelId) {
|
switch (modelId) {
|
||||||
case SunSpec::ModelIdStorage: {
|
case SunSpec::ModelIdStorage: {
|
||||||
StorageData storageData;
|
StorageData mandatory;
|
||||||
qCDebug(dcSunSpec()) << "SunSpecStorage: Storage model received:";
|
qCDebug(dcSunSpec()) << "SunSpecStorage: Storage model received:";
|
||||||
qCDebug(dcSunSpec()) << " - Setpoint maximum charge" << data[Model124SetpointMaximumCharge];
|
qCDebug(dcSunSpec()) << " - Setpoint maximum charge" << data[Model124SetpointMaximumCharge];
|
||||||
qCDebug(dcSunSpec()) << " - Setpoint maximum charging rate" << data[Model124SetpointMaximumChargingRate];
|
qCDebug(dcSunSpec()) << " - Setpoint maximum charging rate" << data[Model124SetpointMaximumChargingRate];
|
||||||
qCDebug(dcSunSpec()) << " - Setpoint maximum discharge rate" << data[Model124SetpointMaximumDischargeRate];
|
qCDebug(dcSunSpec()) << " - Setpoint maximum discharge rate" << data[Model124SetpointMaximumDischargeRate];
|
||||||
qCDebug(dcSunSpec()) << " - Active storage control mode" << data[Model124ActivateStorageControlMode];
|
qCDebug(dcSunSpec()) << " - Active storage control mode" << data[Model124ActivateStorageControlMode];
|
||||||
qCDebug(dcSunSpec()) << " - Currently available energy" << data[Model124CurrentlyAvailableEnergy];
|
qCDebug(dcSunSpec()) << " - ChaGriSet" << data[Model124ChargeGridSet];
|
||||||
storageData.chargingState = ChargingState(data[Model124::Model124ChargeStatus]);
|
qCDebug(dcSunSpec()) << " - Scale factor max charge" << data[Model124ScaleFactorMaximumCharge];
|
||||||
qCDebug(dcSunSpec()) << " - Setpoint maximum charging rate" << data[Model124ChaGriSet];
|
qCDebug(dcSunSpec()) << " - Scale factor max charge/discharge rate" << data[Model124ScaleFactorMaximumChargeDischargeRate];
|
||||||
qCDebug(dcSunSpec()) << " - Setpoint maximum charging rate" << data[Model124ScaleFactorMaximumCharge];
|
qCDebug(dcSunSpec()) << " - Scale factor" << data[Model124ScaleFactorAvailableEnergyPercent];
|
||||||
qCDebug(dcSunSpec()) << " - Setpoint maximum charging rate" << data[Model124ScaleFactorMaximumChargeDischargeRate];
|
mandatory.maxCharge = m_connection->convertValueWithSSF(data[Model124SetpointMaximumCharge], data[Model124ScaleFactorMaximumChargeDischargeRate]);
|
||||||
qCDebug(dcSunSpec()) << " - Setpoint maximum charging rate" << data[Model124ScaleFactorAvailableEnergyPercent];
|
mandatory.maxChargeRate = m_connection->convertValueWithSSF(data[Model124SetpointMaximumChargingRate], data[Model124ScaleFactorPercentChargeDischargeRate]);
|
||||||
emit storageDataReceived(storageData);
|
mandatory.chargingEnabled = data[Model124ActivateStorageControlMode]&0x01;
|
||||||
|
mandatory.dischargingEnabled = data[Model124ActivateStorageControlMode]&0x02;
|
||||||
|
mandatory.maxDischargeRate = m_connection->convertValueWithSSF(data[Model124SetpointMaximumDischargeRate], data[Model124ScaleFactorPercentChargeDischargeRate]);
|
||||||
|
|
||||||
|
StorageDataOptional optional;
|
||||||
|
optional.chargeSatus = ChargingStatus(data[Model124ChargeStatus]);
|
||||||
|
optional.batteryVoltage = m_connection->convertValueWithSSF(data[Model124InternalBatteryVoltage], data[Model124ScaleFactorBatteryVoltage]);
|
||||||
|
optional.storageAvailable = m_connection->convertValueWithSSF(data[Model124StorageAvailableAH], data[Model124ScaleFactorMaximumChargingVA]);
|
||||||
|
optional.gridChargingEnabled = (data[Model124ChargeGridSet] == 1);
|
||||||
|
optional.currentlyAvailableEnergy = m_connection->convertValueWithSSF(data[Model124CurrentlyAvailableEnergyPercent], data[Model124ScaleFactorAvailableEnergyPercent]);
|
||||||
|
//qCDebug(dcSunSpec()) << " - Currently available energy" << data[Model124CurrentlyAvailableEnergy];
|
||||||
|
//mandatory.chargingState = ChargingStatus(data[Model124ChargeStatus]);
|
||||||
|
//qCDebug(dcSunSpec()) << " - Charging state" << mandatory.chargingState;
|
||||||
|
|
||||||
|
emit storageDataReceived(mandatory, optional);
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case SunSpec::ModelIdBatteryBaseModel:
|
case SunSpec::ModelIdBatteryBaseModel:
|
||||||
case SunSpec::ModelIdLithiumIonBatteryModel: {
|
case SunSpec::ModelIdLithiumIonBatteryModel: {
|
||||||
|
qCDebug(dcSunSpec()) << "Model not yet supported";
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -50,11 +50,12 @@ public:
|
|||||||
QUuid setChargingRate(int rate);
|
QUuid setChargingRate(int rate);
|
||||||
QUuid setStorageControlMode(bool chargingEnabled, bool dischargingEnabled);
|
QUuid setStorageControlMode(bool chargingEnabled, bool dischargingEnabled);
|
||||||
|
|
||||||
enum StorageControlBitField {
|
enum StorageControl {
|
||||||
StorageControlBitFieldCharge = 0,
|
StorageControlHold = 0,
|
||||||
StorageControlBitFieldDischarge = 1
|
StorageControlCharge = 1,
|
||||||
|
StorageControlDischarge = 2,
|
||||||
};
|
};
|
||||||
Q_ENUM(StorageControlBitField)
|
Q_ENUM(StorageControl)
|
||||||
|
|
||||||
enum GridCharge {
|
enum GridCharge {
|
||||||
PV = 0,
|
PV = 0,
|
||||||
@ -62,33 +63,69 @@ public:
|
|||||||
};
|
};
|
||||||
Q_ENUM(GridCharge)
|
Q_ENUM(GridCharge)
|
||||||
|
|
||||||
enum ChargingState {
|
enum ChargingStatus {
|
||||||
ChargingStateOff,
|
ChargingStatusOff,
|
||||||
ChargingStateEmpty,
|
ChargingStatusEmpty,
|
||||||
ChargingStateDischarging,
|
ChargingStatusDischarging,
|
||||||
ChargingStateCharging,
|
ChargingStatusCharging,
|
||||||
ChargingStateFull,
|
ChargingStatusFull,
|
||||||
ChargingStateHolding,
|
ChargingStatusHolding,
|
||||||
ChargingStateTesting
|
ChargingStatusTesting
|
||||||
};
|
};
|
||||||
Q_ENUM(ChargingState)
|
Q_ENUM(ChargingStatus)
|
||||||
|
|
||||||
enum Model124 { // Mandatory register
|
enum Model124 { // Mandatory registers
|
||||||
Model124SetpointMaximumCharge = 0,
|
Model124SetpointMaximumCharge = 0,
|
||||||
Model124SetpointMaximumChargingRate = 1,
|
Model124SetpointMaximumChargingRate = 1,
|
||||||
Model124SetpointMaximumDischargeRate = 2,
|
Model124SetpointMaximumDischargeRate = 2,
|
||||||
Model124ActivateStorageControlMode = 3,
|
Model124ActivateStorageControlMode = 3,
|
||||||
Model124CurrentlyAvailableEnergy = 6,
|
|
||||||
Model124ChargeStatus = 9,
|
|
||||||
Model124ChaGriSet = 15,
|
|
||||||
Model124ScaleFactorMaximumCharge = 16,
|
Model124ScaleFactorMaximumCharge = 16,
|
||||||
Model124ScaleFactorMaximumChargeDischargeRate = 17,
|
Model124ScaleFactorMaximumChargeDischargeRate = 17,
|
||||||
Model124ScaleFactorAvailableEnergyPercent = 20
|
|
||||||
};
|
};
|
||||||
Q_ENUM(Model124)
|
Q_ENUM(Model124)
|
||||||
|
|
||||||
|
enum Model124Optional { // Optional registers
|
||||||
|
Model124MaximumChargingVA = 4, // VAChaMax
|
||||||
|
Model124MinimumReserveStoragePercent = 5, // MinRsvPct
|
||||||
|
Model124CurrentlyAvailableEnergyPercent = 6, // ChaState
|
||||||
|
Model124StorageAvailableAH = 7, // StorAval
|
||||||
|
Model124InternalBatteryVoltage = 8, // InBatV
|
||||||
|
Model124ChargeStatus = 9, // ChaSt
|
||||||
|
Model124MaxDischargingRatePercent = 10, // OutWRte
|
||||||
|
Model124MaxChargingRatePercent = 11,
|
||||||
|
Model124ChargeDischargeTimeWindow = 12,
|
||||||
|
Model124ChargeDischargeTimeout = 13,
|
||||||
|
Model124RampTime = 14, // InOutWRte_RmpTms
|
||||||
|
Model124ChargeGridSet = 15, // ChGriSet
|
||||||
|
Model124ScaleFactorMaximumChargingVA = 18,
|
||||||
|
Model124ScaleFactorMinimumReservePercentage = 19,
|
||||||
|
Model124ScaleFactorAvailableEnergyPercent = 20,
|
||||||
|
Model124ScaleFactorStateCharge = 21,
|
||||||
|
Model124ScaleFactorBatteryVoltage = 22,
|
||||||
|
Model124ScaleFactorPercentChargeDischargeRate = 23
|
||||||
|
};
|
||||||
|
Q_ENUM(Model124Optional)
|
||||||
|
|
||||||
struct StorageData {
|
struct StorageData {
|
||||||
ChargingState chargingState;
|
double maxCharge; // [W] Setpoint for maximum charge.
|
||||||
|
double maxChargeRate; // [%] Setpoint for maximum charging rate. Default is MaxChaRte.
|
||||||
|
double maxDischargeRate; // [%] Setpoint for maximum discharge rate. Default is MaxDisChaRte.
|
||||||
|
bool chargingEnabled;
|
||||||
|
bool dischargingEnabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StorageDataOptional {
|
||||||
|
// [VA] Setpoint for maximum charging VA.
|
||||||
|
// [& ]Setpoint for minimum reserve for storage as a percentage of the nominal maximum storage.
|
||||||
|
double currentlyAvailableEnergy; // [%] Currently available energy as a percent of the capacity rating.
|
||||||
|
double storageAvailable; // [Ah] State of charge (ChaState) minus storage reserve (MinRsvPct) times capacity rating (AhrRtg).
|
||||||
|
double batteryVoltage; // [V] Internal battery voltage.
|
||||||
|
ChargingStatus chargeSatus; // Charge status of storage device. Enumerated value.
|
||||||
|
// [%] Percent of max discharge rate.
|
||||||
|
// [%] Percent of max charging rate.
|
||||||
|
// [s] Time window for charge/discharge rate change.
|
||||||
|
// [s] Timeout period for charge/discharge rate.
|
||||||
|
// [s] Ramp time for moving from current setpoint to new setpoint.
|
||||||
bool gridChargingEnabled;
|
bool gridChargingEnabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -104,7 +141,7 @@ private slots:
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void initFinished(bool success);
|
void initFinished(bool success);
|
||||||
void storageDataReceived(const StorageData &data);
|
void storageDataReceived(const StorageData &mandatory, const StorageDataOptional &optional);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SUNSPECSTORAGE_H
|
#endif // SUNSPECSTORAGE_H
|
||||||
|
|||||||
Reference in New Issue
Block a user