improved sunspec storage

This commit is contained in:
Boernsman 2021-01-22 14:21:23 +01:00
parent b536b1b16e
commit c112e1e6a0
8 changed files with 305 additions and 168 deletions

View File

@ -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)

View File

@ -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

View File

@ -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,

View File

@ -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)) {

View File

@ -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;

View File

@ -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)

View File

@ -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;

View File

@ -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