fixed sunspec inverter event state

This commit is contained in:
Boernsman 2021-02-03 16:34:19 +01:00
parent c112e1e6a0
commit 1020dd90a4
12 changed files with 349 additions and 459 deletions

View File

@ -564,6 +564,8 @@ void IntegrationPluginSunSpec::onFoundSunSpecModel(SunSpec::ModelId modelId, int
descriptor.setParams(params);
emit autoThingsAppeared({descriptor});
} break;
case SunSpec::ModelIdWyeConnectThreePhaseMeter:
case SunSpec::ModelIdDeltaConnectThreePhaseMeter:
case SunSpec::ModelIdWyeConnectThreePhaseMeterFloat:
case SunSpec::ModelIdDeltaConnectThreePhaseMeterFloat: {
ThingDescriptor descriptor(sunspecThreePhaseMeterThingClassId, model+" meter", "", thing->id());
@ -617,6 +619,24 @@ void IntegrationPluginSunSpec::onInverterDataReceived(const SunSpecInverter::Inv
if(!thing) {
return;
}
qCDebug(dcSunSpec()) << "Inverter data received";
qCDebug(dcSunSpec()) << " - Total AC Current" << inverterData.acCurrent << "[A]";
qCDebug(dcSunSpec()) << " - Phase A Current" << inverterData.phaseACurrent << "[A]";
qCDebug(dcSunSpec()) << " - Phase B Current" << inverterData.phaseBCurrent << "[A]";
qCDebug(dcSunSpec()) << " - Phase C Current" << inverterData.phaseCCurrent << "[A]";
qCDebug(dcSunSpec()) << " - Phase voltage AB" << inverterData.phaseVoltageAB << "[V]";
qCDebug(dcSunSpec()) << " - Phase voltage BC" << inverterData.phaseVoltageBC << "[V]";
qCDebug(dcSunSpec()) << " - Phase voltage CA" << inverterData.phaseVoltageCA << "[V]";
qCDebug(dcSunSpec()) << " - Phase voltage AN" << inverterData.phaseVoltageAN << "[V]";
qCDebug(dcSunSpec()) << " - Phase voltage BN" << inverterData.phaseVoltageBN << "[V]";
qCDebug(dcSunSpec()) << " - Phase voltage CN" << inverterData.phaseVoltageCN << "[V]";
qCDebug(dcSunSpec()) << " - AC Power" << inverterData.acPower << "[W]";
qCDebug(dcSunSpec()) << " - Line frequency" << inverterData.lineFrequency << "[Hz]";
qCDebug(dcSunSpec()) << " - AC energy" << inverterData.acEnergy << "[Wh]";
qCDebug(dcSunSpec()) << " - Cabinet temperature" << inverterData.cabinetTemperature << "[°C]";
qCDebug(dcSunSpec()) << " - Operating state" << inverterData.operatingState;
thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), true);
thing->setStateValue(m_acPowerStateTypeIds.value(thing->thingClassId()), inverterData.acPower/1000.00);
thing->setStateValue(m_acEnergyStateTypeIds.value(thing->thingClassId()), inverterData.acEnergy/1000.00);
@ -625,7 +645,7 @@ void IntegrationPluginSunSpec::onInverterDataReceived(const SunSpecInverter::Inv
thing->setStateValue(sunspecThreePhaseInverterTotalCurrentStateTypeId, inverterData.acCurrent);
thing->setStateValue(sunspecThreePhaseInverterCabinetTemperatureStateTypeId, inverterData.cabinetTemperature);
if (thing->thingClassId() == sunspecSplitPhaseMeterThingClassId) {
if (thing->thingClassId() == sunspecSplitPhaseInverterThingClassId) {
thing->setStateValue(sunspecSplitPhaseInverterPhaseANVoltageStateTypeId, inverterData.phaseVoltageAN);
thing->setStateValue(sunspecSplitPhaseInverterPhaseBNVoltageStateTypeId, inverterData.phaseVoltageBN);
@ -633,7 +653,7 @@ void IntegrationPluginSunSpec::onInverterDataReceived(const SunSpecInverter::Inv
thing->setStateValue(sunspecSplitPhaseInverterPhaseACurrentStateTypeId, inverterData.phaseACurrent);
thing->setStateValue(sunspecSplitPhaseInverterPhaseBCurrentStateTypeId, inverterData.phaseBCurrent);
} else if (thing->thingClassId() == sunspecThreePhaseMeterThingClassId) {
} else if (thing->thingClassId() == sunspecThreePhaseInverterThingClassId) {
thing->setStateValue(sunspecThreePhaseInverterPhaseANVoltageStateTypeId, inverterData.phaseVoltageAN);
thing->setStateValue(sunspecThreePhaseInverterPhaseBNVoltageStateTypeId, inverterData.phaseVoltageBN);
@ -671,55 +691,41 @@ void IntegrationPluginSunSpec::onInverterDataReceived(const SunSpecInverter::Inv
break;
}
switch(inverterData.event) {
case SunSpec::SunSpecEvent1::OVER_TEMP:
//FIXME: Event1 may have multiple states at once. Only one is stated in nymea
if (inverterData.event1.overTemperature) {
thing->setStateValue(sunspecThreePhaseInverterErrorStateTypeId, "Over temperature");
break;
case SunSpec::SunSpecEvent1::UNDER_TEMP:
} else if (inverterData.event1.underTemperature) {
thing->setStateValue(sunspecThreePhaseInverterErrorStateTypeId, "Under temperature");
break;
case SunSpec::SunSpecEvent1::GroundFault:
} else if (inverterData.event1.groundFault) {
thing->setStateValue(sunspecThreePhaseInverterErrorStateTypeId, "Ground fault");
break;
case SunSpec::SunSpecEvent1::MEMORY_LOSS:
} else if (inverterData.event1.memoryLoss) {
thing->setStateValue(sunspecThreePhaseInverterErrorStateTypeId, "Memory loss");
break;
case SunSpec::SunSpecEvent1::AC_OVER_VOLT:
} else if (inverterData.event1.acOverVolt) {
thing->setStateValue(sunspecThreePhaseInverterErrorStateTypeId, "AC voltage above limit");
break;
case SunSpec::SunSpecEvent1::CABINET_OPEN:
} else if (inverterData.event1.cabinetOpen) {
thing->setStateValue(sunspecThreePhaseInverterErrorStateTypeId, "Cabinet open");
break;
case SunSpec::SunSpecEvent1::AC_DISCONNECT:
} else if (inverterData.event1.acDisconnect) {
thing->setStateValue(sunspecThreePhaseInverterErrorStateTypeId, "AC disconnect open");
break;
case SunSpec::SunSpecEvent1::AC_UNDER_VOLT:
} else if (inverterData.event1.acUnderVolt) {
thing->setStateValue(sunspecThreePhaseInverterErrorStateTypeId, "AC voltage under limit");
break;
case SunSpec::SunSpecEvent1::DC_DISCONNECT:
} else if (inverterData.event1.dcDicconnect) {
thing->setStateValue(sunspecThreePhaseInverterErrorStateTypeId, "DC disconnect open");
break;
case SunSpec::SunSpecEvent1::DcOverVolatage:
} else if (inverterData.event1.dcOverVoltage) {
thing->setStateValue(sunspecThreePhaseInverterErrorStateTypeId, "DC over voltage");
break;
case SunSpec::SunSpecEvent1::OVER_FREQUENCY:
} else if (inverterData.event1.overFrequency) {
thing->setStateValue(sunspecThreePhaseInverterErrorStateTypeId, "Frequency above limit");
break;
case SunSpec::SunSpecEvent1::GRID_DISCONNECT:
} else if (inverterData.event1.gridDisconnect) {
thing->setStateValue(sunspecThreePhaseInverterErrorStateTypeId, "Grid disconnect");
break;
case SunSpec::SunSpecEvent1::HW_TEST_FAILURE:
} else if (inverterData.event1.hwTestFailure) {
thing->setStateValue(sunspecThreePhaseInverterErrorStateTypeId, "Hardware test failure");
break;
case SunSpec::SunSpecEvent1::MANUAL_SHUTDOWN:
} else if (inverterData.event1.manualShutdown) {
thing->setStateValue(sunspecThreePhaseInverterErrorStateTypeId, "Manual shutdown");
break;
case SunSpec::SunSpecEvent1::UNDER_FREQUENCY:
} else if (inverterData.event1.underFrequency) {
thing->setStateValue(sunspecThreePhaseInverterErrorStateTypeId, "Frequency under limit");
break;
case SunSpec::SunSpecEvent1::BLOWN_STRING_FUSE:
} else if (inverterData.event1.blownStringFuse) {
thing->setStateValue(sunspecThreePhaseInverterErrorStateTypeId, "Blown string fuse on input");
break;
} else {
thing->setStateValue(sunspecThreePhaseInverterErrorStateTypeId, "None");
}
}
@ -774,5 +780,34 @@ void IntegrationPluginSunSpec::onMeterDataReceived(const SunSpecMeter::MeterData
if (!thing) {
return;
}
thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), true);
qCDebug(dcSunSpec()) << "Meter data received";
qCDebug(dcSunSpec()) << " - Total AC Current" << meterData.totalAcCurrent << "[A]";
qCDebug(dcSunSpec()) << " - Phase A current" << meterData.phaseACurrent << "[A]";
qCDebug(dcSunSpec()) << " - Phase B current" << meterData.phaseBCurrent << "[A]";
qCDebug(dcSunSpec()) << " - Phase C current" << meterData.phaseCCurrent << "[A]";
qCDebug(dcSunSpec()) << " - Voltage LN" << meterData.voltageLN << "[V]";
qCDebug(dcSunSpec()) << " - Phase voltage AN" << meterData.phaseVoltageAN << "[V]";
qCDebug(dcSunSpec()) << " - Phase voltage BN" << meterData.phaseVoltageBN << "[V]";
qCDebug(dcSunSpec()) << " - Phase voltage CN" << meterData.phaseVoltageCN<< "[V]";
qCDebug(dcSunSpec()) << " - Voltage LL" << meterData.voltageLL << "[V]";
qCDebug(dcSunSpec()) << " - Phase voltage AB" << meterData.phaseVoltageAB << "[V]";
qCDebug(dcSunSpec()) << " - Phase voltage BC" << meterData.phaseVoltageBC << "[V]";
qCDebug(dcSunSpec()) << " - Phase voltage CA" << meterData.phaseVoltageCA<< "[V]";
qCDebug(dcSunSpec()) << " - Frequency" << meterData.frequency << "[Hz]";
qCDebug(dcSunSpec()) << " - Total real power" << meterData.totalRealPower << "[W]";
qCDebug(dcSunSpec()) << " - Total real energy exported" << meterData.totalRealEnergyExported<< "[kWH]";
qCDebug(dcSunSpec()) << " - Total real energy imported" << meterData.totalRealEnergyImported<< "[kWH]";
thing->setStateValue(sunspecThreePhaseMeterTotalCurrentStateTypeId, meterData.totalAcCurrent);
thing->setStateValue(sunspecThreePhaseMeterPhaseACurrentStateTypeId, meterData.phaseACurrent);
thing->setStateValue(sunspecThreePhaseMeterPhaseBCurrentStateTypeId, meterData.phaseBCurrent);
thing->setStateValue(sunspecThreePhaseMeterPhaseCCurrentStateTypeId, meterData.phaseCCurrent);
thing->setStateValue(sunspecThreePhaseMeterLnACVoltageStateTypeId, meterData.voltageLN);
thing->setStateValue(sunspecThreePhaseMeterTotalRealPowerEventTypeId, meterData.totalRealPower);
thing->setStateValue(sunspecThreePhaseMeterEnergyExportedStateTypeId, meterData.totalRealEnergyExported);
thing->setStateValue(sunspecThreePhaseMeterEnergyImportedStateTypeId, meterData.totalRealEnergyImported);
thing->setStateValue(m_frequencyStateTypeIds.value(thing->thingClassId()), meterData.frequency);
}

View File

@ -39,7 +39,6 @@
#include "sunspecinverter.h"
#include "sunspecstorage.h"
#include "sunspecmeter.h"
#include "sunspectracker.h"
#include <QUuid>

View File

@ -67,25 +67,6 @@ public:
};
Q_ENUM(SunSpecOperatingState)
enum SunSpecEvent1 {
GroundFault = 0,
DcOverVolatage,
AC_DISCONNECT,
DC_DISCONNECT,
GRID_DISCONNECT,
CABINET_OPEN,
MANUAL_SHUTDOWN,
OVER_TEMP,
OVER_FREQUENCY,
UNDER_FREQUENCY,
AC_OVER_VOLT,
AC_UNDER_VOLT,
BLOWN_STRING_FUSE,
UNDER_TEMP,
MEMORY_LOSS,
HW_TEST_FAILURE
};
Q_ENUM(SunSpecEvent1)
enum ModelId {
ModelIdCommon = 1,

View File

@ -73,46 +73,70 @@ void SunSpecInverter::getInverterModelDataBlock()
m_connection->readModelDataBlock(m_modelModbusStartRegister, m_modelLength);
}
SunSpecInverter::SunSpecEvent1 SunSpecInverter::bitfieldToSunSpecEvent1(quint16 register1, quint16 register2)
{
SunSpecEvent1 event1;
Q_UNUSED(register2);
event1.groundFault = ((register1 & (0x01 << 0)) != 0);
event1.dcOverVoltage = ((register1 & (0x01 << 1)) != 0);
event1.acDisconnect = ((register1 & (0x01 << 2)) != 0);
event1.dcDicconnect = ((register1 & (0x01 << 3)) != 0);
event1.gridDisconnect = ((register1 & (0x01 << 4)) != 0);
event1.cabinetOpen = ((register1 & (0x01 << 5)) != 0);
event1.manualShutdown = ((register1 & (0x01 << 6)) != 0);
event1.overTemperature = ((register1 & (0x01 << 7)) != 0);
event1.overFrequency = ((register1 & (0x01 << 8)) != 0);
event1.underFrequency = ((register1 & (0x01 << 9)) != 0);
event1.acOverVolt = ((register1 & (0x01 << 10)) != 0);
event1.acUnderVolt = ((register1 & (0x01 << 11)) != 0);
event1.blownStringFuse = ((register1 & (0x01 << 12)) != 0);
event1.underTemperature = ((register1 & (0x01 << 13)) != 0);
event1.memoryLoss = ((register1 & (0x01 << 14)) != 0);
event1.hwTestFailure = ((register1 & (0x01 << 15)) != 0);
return event1;
}
void SunSpecInverter::getInverterModelHeader()
{
qCDebug(dcSunSpec()) << "SunSpecInverter: get inverter model header, modbus register" << m_modelModbusStartRegister;
m_connection->readModelHeader(m_modelModbusStartRegister);
}
void SunSpecInverter::onModelDataBlockReceived(SunSpec::ModelId mapId, uint mapLength, QVector<quint16> data)
void SunSpecInverter::onModelDataBlockReceived(SunSpec::ModelId modelId, uint length, QVector<quint16> data)
{
Q_UNUSED(mapLength)
if (mapId != m_id) {
Q_UNUSED(length)
if (modelId != m_id) {
return;
}
if (mapLength < m_modelLength) {
qCDebug(dcSunSpec()) << "SunSpecInverter: on modbus map received, map length is too short" << mapLength;
//return;
if (length < m_modelLength) {
qCDebug(dcSunSpec()) << "SunSpecInverter: on model data block received, model length is too short" << length;
return;
}
InverterData inverterData;
switch (mapId) {
qCDebug(dcSunSpec()) << "SunSpecInverter: Received" << modelId;
switch (modelId) {
case SunSpec::ModelIdInverterSinglePhase:
case SunSpec::ModelIdInverterSplitPhase:
case SunSpec::ModelIdInverterThreePhase: {
inverterData.acCurrent= m_connection->convertValueWithSSF(data[Model10X::Model10XAcCurrent], data[Model10X::Model10XAmpereScaleFactor]);
inverterData.acPower = m_connection->convertValueWithSSF(data[Model10X::Model10XACPower], data[Model10X::Model10XWattScaleFactor]);
inverterData.lineFrequency = m_connection->convertValueWithSSF(data[Model10X::Model10XLineFrequency], data[Model10X::Model10XHerzScaleFactor]);
inverterData.phaseACurrent = m_connection->convertValueWithSSF(data[Model10X::Model10XPhaseACurrent], data[Model10X::Model10XAmpereScaleFactor]);
inverterData.phaseBCurrent = m_connection->convertValueWithSSF(data[Model10X::Model10XPhaseBCurrent], data[Model10X::Model10XAmpereScaleFactor]);
inverterData.phaseCCurrent = m_connection->convertValueWithSSF(data[Model10X::Model10XPhaseCCurrent], data[Model10X::Model10XAmpereScaleFactor]);
inverterData.phaseVoltageAN = m_connection->convertValueWithSSF(data[Model10X::Model10XPhaseVoltageAN], data[Model10X::Model10XVoltageScaleFactor]);
inverterData.phaseVoltageBN = m_connection->convertValueWithSSF(data[Model10X::Model10XPhaseVoltageBN], data[Model10X::Model10XVoltageScaleFactor]);
inverterData.phaseVoltageCN = m_connection->convertValueWithSSF(data[Model10X::Model10XPhaseVoltageCN], data[Model10X::Model10XVoltageScaleFactor]);
quint16 ampereScaleFactor = data[Model10X::Model10XAmpereScaleFactor];
inverterData.phaseACurrent = m_connection->convertValueWithSSF(data[Model10X::Model10XPhaseACurrent], ampereScaleFactor);
inverterData.phaseBCurrent = m_connection->convertValueWithSSF(data[Model10X::Model10XPhaseBCurrent], ampereScaleFactor);
inverterData.phaseCCurrent = m_connection->convertValueWithSSF(data[Model10X::Model10XPhaseCCurrent], ampereScaleFactor);
quint16 voltageScaleFactor = data[Model10X::Model10XVoltageScaleFactor];
inverterData.phaseVoltageAN = m_connection->convertValueWithSSF(data[Model10X::Model10XPhaseVoltageAN], voltageScaleFactor);
inverterData.phaseVoltageBN = m_connection->convertValueWithSSF(data[Model10X::Model10XPhaseVoltageBN], voltageScaleFactor);
inverterData.phaseVoltageCN = m_connection->convertValueWithSSF(data[Model10X::Model10XPhaseVoltageCN], voltageScaleFactor);
quint32 acEnergy = ((static_cast<quint32>(data.value(Model10X::Model10XAcEnergy))<<16)|static_cast<quint32>(data.value(Model10X::Model10XAcEnergy+1)));
inverterData.acEnergy = m_connection->convertValueWithSSF(acEnergy, data[Model10X::Model10XWattHoursScaleFactor]);
inverterData.cabinetTemperature = m_connection->convertValueWithSSF(data[Model10X::Model10XCabinetTemperature], data[Model10X::Model10XTemperatureScaleFactor]);
inverterData.event = SunSpec::SunSpecEvent1(data[Model10X::Model10XEvent1]);
inverterData.event1 = bitfieldToSunSpecEvent1(data[Model10X::Model10XEvent1], data[Model10X::Model10XEvent1+1]);
inverterData.operatingState = SunSpec::SunSpecOperatingState(data[Model10X::Model10XOperatingState]);
emit inverterDataReceived(inverterData);
@ -123,21 +147,20 @@ void SunSpecInverter::onModelDataBlockReceived(SunSpec::ModelId mapId, uint mapL
inverterData.acCurrent = m_connection->convertFloatValues(data[Model11X::Model11XAcCurrent], data[Model11X::Model11XAcCurrent+1]);
inverterData.phaseCCurrent = m_connection->convertFloatValues(data[Model11X::Model11XPhaseCCurrent], data[Model11X::Model11XPhaseCCurrent+1]);
inverterData.phaseVoltageAN = m_connection->convertFloatValues(data[Model11X::Model11XPhaseVoltageAN], data[Model11X::Model11XPhaseVoltageAN+1]);
inverterData.phaseVoltageBN = m_connection->convertFloatValues(data[Model11X::Model11XPhaseVoltageBN], data[Model11X::Model11XPhaseVoltageBN+1]);
inverterData.phaseVoltageCN = m_connection->convertFloatValues(data[Model11X::Model11XPhaseVoltageCN], data[Model11X::Model11XPhaseVoltageCN+1]);
inverterData.phaseBCurrent = m_connection->convertFloatValues(data[Model11X::Model11XPhaseBCurrent], data[Model11X::Model11XPhaseBCurrent+1]);
inverterData.phaseVoltageBN = m_connection->convertFloatValues(data[Model11X::Model11XPhaseVoltageBN], data[Model11X::Model11XPhaseVoltageBN+1]);
inverterData.phaseACurrent = m_connection->convertFloatValues(data[Model11X::Model11XPhaseACurrent], data[Model11X::Model11XPhaseACurrent+1]);
inverterData.phaseBCurrent = m_connection->convertFloatValues(data[Model11X::Model11XPhaseBCurrent], data[Model11X::Model11XPhaseBCurrent+1]);
inverterData.phaseCCurrent = m_connection->convertFloatValues(data[Model11X::Model11XPhaseCCurrent], data[Model11X::Model11XPhaseCCurrent+1]);
inverterData.phaseACurrent = m_connection->convertFloatValues(data[Model11X::Model11XPhaseACurrent], data[Model11X::Model11XPhaseACurrent+1]);
inverterData.phaseVoltageAN = m_connection->convertFloatValues(data[Model11X::Model11XPhaseVoltageAN], data[Model11X::Model11XPhaseVoltageAN+1]);
inverterData.acPower = m_connection->convertFloatValues(data[Model11X::Model11XACPower], data[Model11X::Model11XACPower+1]);
inverterData.lineFrequency = m_connection->convertFloatValues(data[Model11X::Model11XLineFrequency], data[Model11X::Model11XLineFrequency+1]);
inverterData.acPower = m_connection->convertFloatValues(data[Model11X::Model11XACPower], data[Model11X::Model11XACPower+1]);
inverterData.lineFrequency = m_connection->convertFloatValues(data[Model11X::Model11XLineFrequency], data[Model11X::Model11XLineFrequency+1]);
inverterData.acEnergy = m_connection->convertFloatValues(data[Model11X::Model11XAcEnergy], data[Model11X::Model11XAcEnergy+1]);
inverterData.cabinetTemperature =m_connection->convertFloatValues(data[Model11X::Model11XCabinetTemperature], data[Model11X::Model11XCabinetTemperature+1]);
inverterData.event = SunSpec::SunSpecEvent1(data[Model11X::Model11XEvent1]);
inverterData.acEnergy = m_connection->convertFloatValues(data[Model11X::Model11XAcEnergy], data[Model11X::Model11XAcEnergy+1]);
inverterData.cabinetTemperature = m_connection->convertFloatValues(data[Model11X::Model11XCabinetTemperature], data[Model11X::Model11XCabinetTemperature+1]);
inverterData.event1 = bitfieldToSunSpecEvent1(data[Model11X::Model11XEvent1], data[Model11X::Model11XEvent1+1]);
inverterData.operatingState = SunSpec::SunSpecOperatingState(data[Model11X::Model11XOperatingState]);
emit inverterDataReceived(inverterData);
} break;

View File

@ -77,6 +77,71 @@ public:
Model11XEvent1 = 48
};
enum Model10XOptional { // Optional register
Model10XPhaseVoltageAB = 5,
Model10XPhaseVoltageBC = 6,
Model10XPhaseVoltageCA = 7,
Model10XACApparentPower = 16,
Model10XACApparentPowerSF = 17,
Model10XACReactivePower = 18,
Model10XACReactivePowerSF = 19,
Model10XACPowerFactor = 20,
Model10XACPowerFactorSF = 21,
Model10XDCCurrent = 25,
Model10XDCCurrentSF = 26,
Model10XDCVoltage = 27,
Model10XDCVoltageSF = 28,
Model10XDCPower = 29,
Model10XDCPowerSF = 30,
Model10XHeatSinkTemperature = 32,
Model10XTransformerTemperature = 33,
Model10XOtherTemperature = 34,
Model10XVendorOperatingState = 37,
Model10XVendorEventBitfield1 = 42,
Model10XVendorEventBitfield2 = 44,
Model10XVendorEventBitfield3 = 46,
Model10XVendorEventBitfield4 = 48
};
enum Model11XOptional { // Optinal registers
Model11XPhaseVoltageAB = 8,
Model11XPhaseVoltageBC = 10,
Model11XPhaseVoltageCA = 12,
Model11XACApparentPower = 24,
Model11XACReactivePower = 26,
Model11XACPowerFactor = 28,
Model11XDCCurrent = 32,
Model11XDCVoltage = 34,
Model11XDCPower = 36,
Model11XHeatSinkTemperature = 40,
Model11XTransformerTemperature = 42,
Model11XOtherTemperature = 44,
Model11XVendorOperatingState = 47,
Model11XVendorEventBitfield1 = 52,
Model11XVendorEventBitfield2 = 54,
Model11XVendorEventBitfield3 = 56,
Model11XVendorEventBitfield4 = 58
};
struct SunSpecEvent1 {
bool groundFault;
bool dcOverVoltage;
bool acDisconnect;
bool dcDicconnect;
bool gridDisconnect;
bool cabinetOpen;
bool manualShutdown;
bool overTemperature;
bool overFrequency;
bool underFrequency;
bool acOverVolt;
bool acUnderVolt;
bool blownStringFuse;
bool underTemperature;
bool memoryLoss;
bool hwTestFailure;
};
struct InverterData {
float acCurrent; //in ampere
float phaseACurrent;
@ -92,7 +157,7 @@ public:
float lineFrequency;
float acEnergy;
float cabinetTemperature; // in degree Celsius
SunSpec::SunSpecEvent1 event;
SunSpecEvent1 event1;
SunSpec::SunSpecOperatingState operatingState;
};
@ -108,6 +173,7 @@ private:
uint m_modelModbusStartRegister = 40000;
bool m_initFinishedSuccess = false;
SunSpecEvent1 bitfieldToSunSpecEvent1(quint16 register1, quint16 register2);
void getInverterModelHeader();
private slots:

View File

@ -83,20 +83,67 @@ void SunSpecMeter::onModelDataBlockReceived(SunSpec::ModelId modelId, uint lengt
if (modelId != m_id) {
return;
}
Q_UNUSED(length)
Q_UNUSED(data)
if (length < m_modelLength) {
qCDebug(dcSunSpec()) << "SunSpecMeter: on model data block received, model length is too short" << length;
return;
}
qCDebug(dcSunSpec()) << "SunSpecMeter: Received" << modelId;
switch (modelId) {
case SunSpec::ModelIdSinglePhaseMeter:
case SunSpec::ModelIdSinglePhaseMeterFloat: {
} break;
case SunSpec::ModelIdSplitSinglePhaseMeter:
case SunSpec::ModelIdSplitSinglePhaseMeterFloat: {
case SunSpec::ModelIdDeltaConnectThreePhaseMeter:
case SunSpec::ModelIdWyeConnectThreePhaseMeter: {
MeterData meterData;
quint16 currentScaleFactor = data[Model20XCurrentScaleFactor];
meterData.totalAcCurrent = m_connection->convertValueWithSSF(data[Model20XTotalAcCurrent], currentScaleFactor);
meterData.phaseACurrent = m_connection->convertValueWithSSF(data[Model20XPhaseACurrent], currentScaleFactor);
meterData.phaseBCurrent = m_connection->convertValueWithSSF(data[Model20XPhaseBCurrent], currentScaleFactor);
meterData.phaseCCurrent = m_connection->convertValueWithSSF(data[Model20XPhaseCCurrent], currentScaleFactor);
quint16 voltageScaleFactor = data[Model20XVoltageScaleFactor];
meterData.voltageLN = m_connection->convertValueWithSSF(data[Model20XVoltageLN], voltageScaleFactor);
meterData.phaseVoltageAN = m_connection->convertValueWithSSF(data[Model20XPhaseVoltageAN], voltageScaleFactor);
meterData.phaseVoltageBN = m_connection->convertValueWithSSF(data[Model20XPhaseVoltageBN], voltageScaleFactor);
meterData.phaseVoltageCN = m_connection->convertValueWithSSF(data[Model20XPhaseVoltageCN], voltageScaleFactor);
meterData.voltageLL = m_connection->convertValueWithSSF(data[Model20XVoltageLL], voltageScaleFactor);
meterData.phaseVoltageAB = m_connection->convertValueWithSSF(data[Model20XPhaseVoltageAB], voltageScaleFactor);
meterData.phaseVoltageBC = m_connection->convertValueWithSSF(data[Model20XPhaseVoltageBC], voltageScaleFactor);
meterData.phaseVoltageCA = m_connection->convertValueWithSSF(data[Model20XPhaseVoltageCA], voltageScaleFactor);
meterData.frequency = m_connection->convertValueWithSSF(data[Model20XFrequency], data[Model20XFrequencyScaleFactor]);
meterData.totalRealPower = m_connection->convertValueWithSSF(data[Model20XTotalRealPower], data[Model20XRealPowerScaleFactor]);
quint16 energyScaleFactor = data[Model20XRealEnergyScaleFactor];
meterData.totalRealEnergyExported = m_connection->convertValueWithSSF(data[Model20XTotalRealEnergyExported], energyScaleFactor);
meterData.totalRealEnergyImported = m_connection->convertValueWithSSF(data[Model20XTotalRealEnergyImported], energyScaleFactor);;
meterData.meterEventFlags = (static_cast<quint32>(data[Model20XMeterEventFlags]) << 16) | data[Model20XMeterEventFlags+1];
emit meterDataReceived(meterData);
} break;
case SunSpec::ModelIdWyeConnectThreePhaseMeterFloat:
case SunSpec::ModelIdDeltaConnectThreePhaseMeterFloat: {
case SunSpec::ModelIdSinglePhaseMeterFloat:
case SunSpec::ModelIdSplitSinglePhaseMeterFloat:
case SunSpec::ModelIdDeltaConnectThreePhaseMeterFloat:
case SunSpec::ModelIdWyeConnectThreePhaseMeterFloat: {
MeterData meterData;
meterData.totalAcCurrent = m_connection->convertFloatValues(data[Model21XTotalAcCurrent], data[Model21XTotalAcCurrent+1]);
meterData.phaseACurrent = m_connection->convertFloatValues(data[Model21XPhaseACurrent], data[Model21XPhaseACurrent+1]);
meterData.phaseBCurrent = m_connection->convertFloatValues(data[Model21XPhaseBCurrent], data[Model21XPhaseBCurrent+1]);
meterData.phaseCCurrent = m_connection->convertFloatValues(data[Model21XPhaseCCurrent], data[Model21XPhaseCCurrent+1]);
meterData.voltageLN = m_connection->convertFloatValues(data[Model21XVoltageLN], data[Model21XVoltageLN+1]);
meterData.phaseVoltageAN = m_connection->convertFloatValues(data[Model21XPhaseVoltageAN], data[Model21XPhaseVoltageAN+1]);
meterData.phaseVoltageBN = m_connection->convertFloatValues(data[Model21XPhaseVoltageBN], data[Model21XPhaseVoltageBN+1]);
meterData.phaseVoltageCN = m_connection->convertFloatValues(data[Model21XPhaseVoltageCN], data[Model21XPhaseVoltageCN+1]);
meterData.voltageLL = m_connection->convertFloatValues(data[Model21XVoltageLL], data[Model21XVoltageLL+1]);
meterData.phaseVoltageAB = m_connection->convertFloatValues(data[Model21XPhaseVoltageAB], data[Model21XPhaseVoltageAB+1]);
meterData.phaseVoltageBC = m_connection->convertFloatValues(data[Model21XPhaseVoltageBC], data[Model21XPhaseVoltageBC+1]);
meterData.phaseVoltageCA = m_connection->convertFloatValues(data[Model21XPhaseVoltageCA], data[Model21XPhaseVoltageCA+1]);
meterData.frequency = m_connection->convertFloatValues(data[Model21XFrequency], data[Model21XFrequency+1]);
meterData.totalRealPower = m_connection->convertFloatValues(data[Model21XTotalRealPower], data[Model21XTotalRealPower+1]);
meterData.totalRealEnergyExported = m_connection->convertFloatValues(data[Model21XTotalRealEnergyExported], data[Model21XTotalRealEnergyExported+1]);
meterData.totalRealEnergyImported = m_connection->convertFloatValues(data[Model21XTotalRealEnergyImported], data[Model21XTotalRealEnergyImported+1]);
meterData.meterEventFlags = ((static_cast<quint32>(data[Model21XMeterEventFlags]) << 16) | data[Model21XMeterEventFlags+1]);
emit meterDataReceived(meterData);
} break;
default:

View File

@ -38,34 +38,109 @@ class SunSpecMeter : public QObject
{
Q_OBJECT
public:
//Model 203 = Three phase meter
enum MandatoryRegistersModel20X {
TotalAcCurrent = 2,
PhaseACurrent = 3,
PhaseBCurrent = 4,
PhaseCCurrent = 5,
CurrentScaleFactor = 6,
VoltageLN = 7,
PhaseVoltageAN = 8,
PhaseVoltageBN = 9,
PhaseVoltageCN = 10,
VoltageLL = 11,
PhaseVoltageAB = 12,
PhaseVoltageBC = 13,
PhaseVoltageCA = 14,
VoltageScaleFactor = 15,
Frequency = 16,
TotalRealPower = 18,
RealPowerScaleFactor = 22,
TotalRealEnergyExported = 38,
TotalRealEnergyImported = 46,
RealEnergyScaleFactor = 54,
MeterEventFlags = 105
enum MeterEventFlags {
MeterEventPowerFailure = 2,
MeterEventUnderVoltage,
MeterEventLowPF,
MeterEventOverCurrent,
MeterEventOverVoltage,
MeterEventMissing_Sensor,
MeterEventReserved1,
MeterEventReserved2,
MeterEventReserved3,
MeterEventReserved4,
MeterEventReserved5,
MeterEventReserved6,
MeterEventReserved7,
MeterEventReserved8,
MeterEventOEM01,
MeterEventOEM02,
MeterEventOEM03,
MeterEventOEM04,
MeterEventOEM05,
MeterEventOEM06,
MeterEventOEM07,
MeterEventOEM08,
MeterEventOEM09,
MeterEventOEM10,
MeterEventOEM11,
MeterEventOEM12,
MeterEventOEM13,
MeterEventOEM14,
MeterEventOEM15
};
//Model 201 = Single phase meter SF
//Model 202 = Split phase meter SF
//Model 203 = Three phase meter SF
//Note: For example single phase inverters, Phase B current is optional then.
enum Model20X {
Model20XTotalAcCurrent = 0,
Model20XPhaseACurrent = 1,
Model20XPhaseBCurrent = 2,
Model20XPhaseCCurrent = 3,
Model20XCurrentScaleFactor = 4,
Model20XVoltageLN = 5,
Model20XPhaseVoltageAN = 6,
Model20XPhaseVoltageBN = 7,
Model20XPhaseVoltageCN = 8,
Model20XVoltageLL = 9,
Model20XPhaseVoltageAB = 10,
Model20XPhaseVoltageBC = 11,
Model20XPhaseVoltageCA = 12,
Model20XVoltageScaleFactor = 13,
Model20XFrequency = 14,
Model20XFrequencyScaleFactor = 15,
Model20XTotalRealPower = 16,
Model20XRealPowerScaleFactor = 20,
Model20XTotalRealEnergyExported = 36,
Model20XTotalRealEnergyImported = 44,
Model20XRealEnergyScaleFactor = 52,
Model20XMeterEventFlags = 103
};
//Model 211 = Single phase meter float
//Model 212 = Split phase meter float
//Model 213 = Three phase meter float
enum Model21X {
Model21XTotalAcCurrent = 0,
Model21XPhaseACurrent = 2,
Model21XPhaseBCurrent = 4,
Model21XPhaseCCurrent = 6,
Model21XVoltageLN = 8,
Model21XPhaseVoltageAN = 10,
Model21XPhaseVoltageBN = 12,
Model21XPhaseVoltageCN = 14,
Model21XVoltageLL = 16,
Model21XPhaseVoltageAB = 18,
Model21XPhaseVoltageBC = 20,
Model21XPhaseVoltageCA = 22,
Model21XFrequency = 24,
Model21XTotalRealPower = 26,
Model21XTotalRealEnergyExported = 58,
Model21XTotalRealEnergyImported = 66,
Model21XMeterEventFlags = 122
};
struct MeterData {
SunSpec::SunSpecEvent1 event;
SunSpec::SunSpecOperatingState operatingState;
double totalAcCurrent; // [A]
double phaseACurrent; // [A]
double phaseBCurrent; // [A]
double phaseCCurrent; // [A]
double voltageLN; // [V]
double phaseVoltageAN; // [V]
double phaseVoltageBN; // [V]
double phaseVoltageCN; // [V]
double voltageLL; // [V]
double phaseVoltageAB; // [V]
double phaseVoltageBC; // [V]
double phaseVoltageCA; // [V]
double frequency; // [Hz]
double totalRealPower; // [W]
double totalRealEnergyExported; // [kWh]
double totalRealEnergyImported; // [kWh]
quint32 meterEventFlags; // MeterEventFlags
};
SunSpecMeter(SunSpec *sunspec, SunSpec::ModelId modelId, int modbusAddress);

View File

@ -121,15 +121,19 @@ QUuid SunSpecStorage::setDischargingRate(int charging)
void SunSpecStorage::onModelDataBlockReceived(SunSpec::ModelId modelId, uint length, const QVector<quint16> &data)
{
Q_UNUSED(length)
if (modelId != m_id) {
return;
}
if (length < m_modelLength) {
qCDebug(dcSunSpec()) << "SunSpecMeter: on model data block received, model length is too short" << length;
//return;
}
qCDebug(dcSunSpec()) << "SunSpecStorage: Received" << modelId;
switch (modelId) {
case SunSpec::ModelIdStorage: {
StorageData mandatory;
qCDebug(dcSunSpec()) << "SunSpecStorage: Storage model received:";
qCDebug(dcSunSpec()) << " - Setpoint maximum charge" << data[Model124SetpointMaximumCharge];
qCDebug(dcSunSpec()) << " - Setpoint maximum charging rate" << data[Model124SetpointMaximumChargingRate];
qCDebug(dcSunSpec()) << " - Setpoint maximum discharge rate" << data[Model124SetpointMaximumDischargeRate];
@ -150,9 +154,6 @@ void SunSpecStorage::onModelDataBlockReceived(SunSpec::ModelId modelId, uint len
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);

View File

@ -1,90 +0,0 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "sunspecstringcombiner.h"
#include "extern-plugininfo.h"
SunSpecStringCombiner::SunSpecStringCombiner(const QHostAddress &hostAddress, uint port, QObject *parent) : SunSpec(hostAddress, port, parent)
{
connect(m_modbusTcpClient, &QModbusClient::stateChanged, this, [this] (QModbusDevice::State state) {
if (state == QModbusDevice::ConnectedState) {
qCDebug(dcSunSpec()) << "String combiner connected successfully";
QList<BlockId> mapIds;
mapIds.append(BlockIdStringCombiner);
mapIds.append(BlockIdStringCombinerCurrent);
mapIds.append(BlockIdStringCombinerAdvanced);
mapIds.append(BlockIdStringCombinerCurrentAdvanced);
findModbusMap(mapIds);
}
});
connect(this, &SunSpec::foundModbusMap, this, [this] (BlockId mapId, uint modbusRegisterAddress) {
qCDebug(dcSunSpec()) << "Read map header for mapId" << mapId << "and modbus register" << modbusRegisterAddress;
readMapHeader(modbusRegisterAddress);
});
connect(this, &SunSpec::mapHeaderReceived, this, [this] (uint modbusAddress, BlockId mapId, uint mapLength) {
m_id = mapId;
m_mapLength = mapLength;
m_mapModbusStartRegister = modbusAddress;
readMap(modbusAddress, mapLength);
});
connect(this, &SunSpec::mapReceived, this, &SunSpecStringCombiner::onModbusMapReceived);
}
void SunSpecStringCombiner::getStringCombinerMap()
{
}
void SunSpecStringCombiner::readStringCombinerMapHeader()
{
readMap(m_mapModbusStartRegister, m_mapLength);
}
void SunSpecStringCombiner::onModbusMapReceived(SunSpec::BlockId mapId, uint mapLength, QVector<quint16> data)
{
Q_UNUSED(data);
switch (mapId) {
case BlockIdStringCombiner: {
int rbCount = (mapLength-14)/8;
qCDebug(dcSunSpec()) << "Map" << mapId << "Repeating Block Count" << rbCount;
} break;
case BlockIdStringCombinerCurrent:
case BlockIdStringCombinerAdvanced:
case BlockIdStringCombinerCurrentAdvanced: {
//StringCombinerData stringCombinerData;
//stringCombinerData.acCurrent= convertValueWithSSF(data[Model10X::Model10XAcCurrent], data[Model10X::Model10XAmpereScaleFactor]);
} break;
default:
break;
}
}

View File

@ -1,128 +0,0 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef SUNSPECSTRINGCOMBINER_H
#define SUNSPECSTRINGCOMBINER_H
#include <QObject>
#include "sunspec.h"
class SunSpecStringCombiner : public SunSpec
{
Q_OBJECT
public:
//Map401 length: 14 + (RB Count * 8)
//Map403 length: 16 + (RB Count * 8)
enum Map401 {
Map401CurrentScaleFactor = 0,
Map401AmpHourScaleFactor = 1,
Map401VoltageScaleFactor = 2,
Map401MaximumDCCurrentRating = 3,
Map401NumberOfInputs = 4,
Map401Events = 5,
Map401VendorDefniedEvents = 7,
Map401TotalMeasuredCurrent = 9,
Map401TotalMeteredAmpHours = 10,
Map401OutputVoltage = 12,
Map401InternalOperatingTemperature = 13
};
enum Map402 {
Map402CurrentScaleFactor,
Map402AmpHourScaleFactor,
Map402VoltageScaleFactor,
Map402PowerScaleFactor,
Map402EnergyScaleFactor,
Map402MaximumDCCurrentRating,
Map402NumberOfInputs,
Map402BitmaskValueEvents,
Map402BitmaskvalueVendorDefniedEvents,
Map402TotalMeasuredCurrent,
Map402TotalMeteredAmpHours,
Map402OutputVoltage
};
enum Map401RB { //Repeating block
ID = 0,
Event = 1,
VendorEvent = 3,
Amps = 5,
AmpHours = 6
};
enum StringCombinerEvent {
LowVoltage = 0,
LowPower,
LowEfficiency,
Current,
Voltage,
Power,
Pr,
Disconnected,
FuseFault,
CombinerFuseFault,
CombinerCabinetOpen,
Temp,
Groundfault,
ReversedPolarity,
Incompatible,
CommunicationError,
InternalError,
Theft,
ArcDetected
};
Q_ENUM(StringCombinerEvent)
struct StringCombinerData {
SunSpecEvent1 event;
SunSpecOperatingState operatingState;
};
SunSpecStringCombiner(const QHostAddress &hostAddress, uint port = 502, QObject *parent = 0);
void getStringCombinerMap();
private:
BlockId m_id = BlockIdStringCombiner;
uint m_mapLength = 0;
uint m_mapModbusStartRegister = 40000;
void readStringCombinerMapHeader();
private slots:
void onModbusMapReceived(BlockId mapId, uint mapLength, QVector<quint16> data);
signals:
void initFinished();
void stringCombinerDataReceived(const StringCombinerData &data);
};
#endif // SUNSPECSTRINGCOMBINER_H

View File

@ -1,42 +0,0 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "sunspectracker.h"
#include "extern-plugininfo.h"
SunSpecTracker::SunSpecTracker(const QHostAddress &hostAddress, uint port, QObject *parent) : SunSpec(hostAddress, port, parent)
{
}
void SunSpecTracker::readTrackerBlockHeader()
{
readMap(m_mapModbusStartRegister, m_mapLength);
}

View File

@ -1,77 +0,0 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef SUNSPECTRACKER_H
#define SUNSPECTRACKER_H
#include <QObject>
#include "sunspec.h"
class SunSpecTracker : public SunSpec
{
Q_OBJECT
public:
enum TrackerType {
Unknown = 0,
Fixed = 1,
Horizontal = 2,
Tilted = 3,
Azimuth = 4,
Dual = 5,
Other = 99
};
Q_ENUM(TrackerType)
struct TrackerData {
SunSpecEvent1 event;
SunSpecOperatingState operatingState;
};
SunSpecTracker(const QHostAddress &hostAddress, uint port = 502, QObject *parent = 0);
void getTrackerMap();
private:
ModelId m_id = ModelIdTrackerController;
uint m_mapLength = 0;
uint m_mapModbusStartRegister = 40000;
void readTrackerBlockHeader();
private slots:
//void onModbusMapReceived(BlockId mapId, uint mapLength, QVector<quint16> data);
signals:
void initFinished();
void trackerDataReceived(const TrackerData &data);
};
#endif // SUNSPECTRACKER_H