nymea-plugins-modbus/libnymea-sunspec/models/sunspecstringcombinercurren...

544 lines
20 KiB
C++

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2021, nymea GmbH
* Contact: contact@nymea.io
*
* This fileDescriptor 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 "sunspecstringcombinercurrentmodel.h"
#include "sunspecconnection.h"
SunSpecStringCombinerCurrentModelRepeatingBlock::SunSpecStringCombinerCurrentModelRepeatingBlock(quint16 blockIndex, quint16 blockSize, quint16 modbusStartRegister, SunSpecStringCombinerCurrentModel *parent) :
SunSpecModelRepeatingBlock(blockIndex, blockSize, modbusStartRegister, parent)
{
m_byteOrder = parent->byteOrder();
initDataPoints();
}
QString SunSpecStringCombinerCurrentModelRepeatingBlock::name() const
{
return "string";
}
SunSpecStringCombinerCurrentModel *SunSpecStringCombinerCurrentModelRepeatingBlock::parentModel() const
{
return m_parentModel;
}
quint16 SunSpecStringCombinerCurrentModelRepeatingBlock::id() const
{
return m_id;
}
SunSpecStringCombinerCurrentModelRepeatingBlock::InevtFlags SunSpecStringCombinerCurrentModelRepeatingBlock::inputEvent() const
{
return m_inputEvent;
}
quint32 SunSpecStringCombinerCurrentModelRepeatingBlock::inputEventVendor() const
{
return m_inputEventVendor;
}
float SunSpecStringCombinerCurrentModelRepeatingBlock::amps() const
{
return m_amps;
}
quint32 SunSpecStringCombinerCurrentModelRepeatingBlock::ampHours() const
{
return m_ampHours;
}
void SunSpecStringCombinerCurrentModelRepeatingBlock::initDataPoints()
{
SunSpecDataPoint idDataPoint;
idDataPoint.setName("InID");
idDataPoint.setLabel("ID");
idDataPoint.setDescription("Uniquely identifies this input set");
idDataPoint.setMandatory(true);
idDataPoint.setSize(1);
idDataPoint.setAddressOffset(0);
idDataPoint.setSunSpecDataType("uint16");
idDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(idDataPoint.name(), idDataPoint);
SunSpecDataPoint inputEventDataPoint;
inputEventDataPoint.setName("InEvt");
inputEventDataPoint.setLabel("Input Event");
inputEventDataPoint.setDescription("String Input Event Flags");
inputEventDataPoint.setMandatory(true);
inputEventDataPoint.setSize(2);
inputEventDataPoint.setAddressOffset(1);
inputEventDataPoint.setSunSpecDataType("bitfield32");
inputEventDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(inputEventDataPoint.name(), inputEventDataPoint);
SunSpecDataPoint inputEventVendorDataPoint;
inputEventVendorDataPoint.setName("InEvtVnd");
inputEventVendorDataPoint.setLabel("Input Event Vendor");
inputEventVendorDataPoint.setDescription("String Input Vendor Event Flags");
inputEventVendorDataPoint.setSize(2);
inputEventVendorDataPoint.setAddressOffset(3);
inputEventVendorDataPoint.setBlockOffset(1);
inputEventVendorDataPoint.setSunSpecDataType("bitfield32");
inputEventVendorDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(inputEventVendorDataPoint.name(), inputEventVendorDataPoint);
SunSpecDataPoint ampsDataPoint;
ampsDataPoint.setName("InDCA");
ampsDataPoint.setLabel("Amps");
ampsDataPoint.setDescription("String Input Current");
ampsDataPoint.setUnits("A");
ampsDataPoint.setMandatory(true);
ampsDataPoint.setSize(1);
ampsDataPoint.setAddressOffset(5);
ampsDataPoint.setBlockOffset(3);
ampsDataPoint.setScaleFactorName("InDCA_SF");
ampsDataPoint.setSunSpecDataType("int16");
ampsDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(ampsDataPoint.name(), ampsDataPoint);
SunSpecDataPoint ampHoursDataPoint;
ampHoursDataPoint.setName("InDCAhr");
ampHoursDataPoint.setLabel("Amp-hours");
ampHoursDataPoint.setDescription("String Input Amp-Hours");
ampHoursDataPoint.setUnits("Ah");
ampHoursDataPoint.setSize(2);
ampHoursDataPoint.setAddressOffset(6);
ampHoursDataPoint.setBlockOffset(4);
ampHoursDataPoint.setScaleFactorName("InDCAhr_SF");
ampHoursDataPoint.setSunSpecDataType("acc32");
ampHoursDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(ampHoursDataPoint.name(), ampHoursDataPoint);
}
void SunSpecStringCombinerCurrentModelRepeatingBlock::processBlockData(const QVector<quint16> blockData)
{
m_blockData = blockData;
// Update properties according to the data point type
if (m_dataPoints.value("InID").isValid())
m_id = m_dataPoints.value("InID").toUInt16();
if (m_dataPoints.value("InEvt").isValid())
m_inputEvent = static_cast<InevtFlags>(m_dataPoints.value("InEvt").toUInt32());
if (m_dataPoints.value("InEvtVnd").isValid())
m_inputEventVendor = m_dataPoints.value("InEvtVnd").toUInt32();
if (m_dataPoints.value("InDCA").isValid())
m_amps = m_dataPoints.value("InDCA").toFloatWithSSF(m_parentModel->inDCA_SF());
if (m_dataPoints.value("InDCAhr").isValid())
m_ampHours = m_dataPoints.value("InDCAhr").toFloatWithSSF(m_parentModel->inDCAhr_SF());
qCDebug(dcSunSpecModelData()) << this;
}
SunSpecStringCombinerCurrentModel::SunSpecStringCombinerCurrentModel(SunSpecConnection *connection, quint16 modbusStartRegister, quint16 modelLength, SunSpecDataPoint::ByteOrder byteOrder, QObject *parent) :
SunSpecModel(connection, modbusStartRegister, 403, modelLength, byteOrder, parent)
{
m_modelBlockType = SunSpecModel::ModelBlockTypeFixedAndRepeating;
initDataPoints();
}
SunSpecStringCombinerCurrentModel::~SunSpecStringCombinerCurrentModel()
{
}
QString SunSpecStringCombinerCurrentModel::name() const
{
return "string_combiner";
}
QString SunSpecStringCombinerCurrentModel::description() const
{
return "A basic string combiner model";
}
QString SunSpecStringCombinerCurrentModel::label() const
{
return "String Combiner (Current)";
}
qint16 SunSpecStringCombinerCurrentModel::dCA_SF() const
{
return m_dCA_SF;
}
qint16 SunSpecStringCombinerCurrentModel::dCAhr_SF() const
{
return m_dCAhr_SF;
}
qint16 SunSpecStringCombinerCurrentModel::dCV_SF() const
{
return m_dCV_SF;
}
float SunSpecStringCombinerCurrentModel::rating() const
{
return m_rating;
}
int SunSpecStringCombinerCurrentModel::n() const
{
return m_n;
}
SunSpecStringCombinerCurrentModel::EvtFlags SunSpecStringCombinerCurrentModel::eventFlags() const
{
return m_eventFlags;
}
quint32 SunSpecStringCombinerCurrentModel::vendorEvent() const
{
return m_vendorEvent;
}
float SunSpecStringCombinerCurrentModel::amps() const
{
return m_amps;
}
quint32 SunSpecStringCombinerCurrentModel::ampHours() const
{
return m_ampHours;
}
float SunSpecStringCombinerCurrentModel::voltage() const
{
return m_voltage;
}
qint16 SunSpecStringCombinerCurrentModel::temp() const
{
return m_temp;
}
qint16 SunSpecStringCombinerCurrentModel::inDCA_SF() const
{
return m_inDCA_SF;
}
qint16 SunSpecStringCombinerCurrentModel::inDCAhr_SF() const
{
return m_inDCAhr_SF;
}
void SunSpecStringCombinerCurrentModel::initDataPoints()
{
SunSpecDataPoint modelIdDataPoint;
modelIdDataPoint.setName("ID");
modelIdDataPoint.setLabel("Model ID");
modelIdDataPoint.setDescription("Model identifier");
modelIdDataPoint.setMandatory(true);
modelIdDataPoint.setSize(1);
modelIdDataPoint.setAddressOffset(0);
modelIdDataPoint.setSunSpecDataType("uint16");
modelIdDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(modelIdDataPoint.name(), modelIdDataPoint);
SunSpecDataPoint modelLengthDataPoint;
modelLengthDataPoint.setName("L");
modelLengthDataPoint.setLabel("Model Length");
modelLengthDataPoint.setDescription("Model length");
modelLengthDataPoint.setMandatory(true);
modelLengthDataPoint.setSize(1);
modelLengthDataPoint.setAddressOffset(1);
modelLengthDataPoint.setSunSpecDataType("uint16");
modelLengthDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(modelLengthDataPoint.name(), modelLengthDataPoint);
SunSpecDataPoint dCA_SFDataPoint;
dCA_SFDataPoint.setName("DCA_SF");
dCA_SFDataPoint.setDescription("Current scale factor");
dCA_SFDataPoint.setMandatory(true);
dCA_SFDataPoint.setSize(1);
dCA_SFDataPoint.setAddressOffset(2);
dCA_SFDataPoint.setBlockOffset(0);
dCA_SFDataPoint.setSunSpecDataType("sunssf");
dCA_SFDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(dCA_SFDataPoint.name(), dCA_SFDataPoint);
SunSpecDataPoint dCAhr_SFDataPoint;
dCAhr_SFDataPoint.setName("DCAhr_SF");
dCAhr_SFDataPoint.setDescription("Amp-hour scale factor");
dCAhr_SFDataPoint.setSize(1);
dCAhr_SFDataPoint.setAddressOffset(3);
dCAhr_SFDataPoint.setBlockOffset(1);
dCAhr_SFDataPoint.setSunSpecDataType("sunssf");
dCAhr_SFDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(dCAhr_SFDataPoint.name(), dCAhr_SFDataPoint);
SunSpecDataPoint dCV_SFDataPoint;
dCV_SFDataPoint.setName("DCV_SF");
dCV_SFDataPoint.setDescription("Voltage scale factor");
dCV_SFDataPoint.setSize(1);
dCV_SFDataPoint.setAddressOffset(4);
dCV_SFDataPoint.setBlockOffset(2);
dCV_SFDataPoint.setSunSpecDataType("sunssf");
dCV_SFDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(dCV_SFDataPoint.name(), dCV_SFDataPoint);
SunSpecDataPoint ratingDataPoint;
ratingDataPoint.setName("DCAMax");
ratingDataPoint.setLabel("Rating");
ratingDataPoint.setDescription("Maximum DC Current Rating");
ratingDataPoint.setUnits("A");
ratingDataPoint.setMandatory(true);
ratingDataPoint.setSize(1);
ratingDataPoint.setAddressOffset(5);
ratingDataPoint.setBlockOffset(3);
ratingDataPoint.setScaleFactorName("DCA_SF");
ratingDataPoint.setSunSpecDataType("uint16");
ratingDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(ratingDataPoint.name(), ratingDataPoint);
SunSpecDataPoint nDataPoint;
nDataPoint.setName("N");
nDataPoint.setLabel("N");
nDataPoint.setDescription("Number of Inputs");
nDataPoint.setMandatory(true);
nDataPoint.setSize(1);
nDataPoint.setAddressOffset(6);
nDataPoint.setBlockOffset(4);
nDataPoint.setSunSpecDataType("count");
nDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(nDataPoint.name(), nDataPoint);
SunSpecDataPoint eventFlagsDataPoint;
eventFlagsDataPoint.setName("Evt");
eventFlagsDataPoint.setLabel("Event");
eventFlagsDataPoint.setDescription("Bitmask value. Events");
eventFlagsDataPoint.setMandatory(true);
eventFlagsDataPoint.setSize(2);
eventFlagsDataPoint.setAddressOffset(7);
eventFlagsDataPoint.setBlockOffset(5);
eventFlagsDataPoint.setSunSpecDataType("bitfield32");
eventFlagsDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(eventFlagsDataPoint.name(), eventFlagsDataPoint);
SunSpecDataPoint vendorEventDataPoint;
vendorEventDataPoint.setName("EvtVnd");
vendorEventDataPoint.setLabel("Vendor Event");
vendorEventDataPoint.setDescription("Bitmask value. Vendor defined events");
vendorEventDataPoint.setSize(2);
vendorEventDataPoint.setAddressOffset(9);
vendorEventDataPoint.setBlockOffset(7);
vendorEventDataPoint.setSunSpecDataType("bitfield32");
vendorEventDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(vendorEventDataPoint.name(), vendorEventDataPoint);
SunSpecDataPoint ampsDataPoint;
ampsDataPoint.setName("DCA");
ampsDataPoint.setLabel("Amps");
ampsDataPoint.setDescription("Total measured current");
ampsDataPoint.setUnits("A");
ampsDataPoint.setMandatory(true);
ampsDataPoint.setSize(1);
ampsDataPoint.setAddressOffset(11);
ampsDataPoint.setBlockOffset(9);
ampsDataPoint.setScaleFactorName("DCA_SF");
ampsDataPoint.setSunSpecDataType("int16");
ampsDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(ampsDataPoint.name(), ampsDataPoint);
SunSpecDataPoint ampHoursDataPoint;
ampHoursDataPoint.setName("DCAhr");
ampHoursDataPoint.setLabel("Amp-hours");
ampHoursDataPoint.setDescription("Total metered Amp-hours");
ampHoursDataPoint.setUnits("Ah");
ampHoursDataPoint.setSize(2);
ampHoursDataPoint.setAddressOffset(12);
ampHoursDataPoint.setBlockOffset(10);
ampHoursDataPoint.setScaleFactorName("DCAhr_SF");
ampHoursDataPoint.setSunSpecDataType("acc32");
ampHoursDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(ampHoursDataPoint.name(), ampHoursDataPoint);
SunSpecDataPoint voltageDataPoint;
voltageDataPoint.setName("DCV");
voltageDataPoint.setLabel("Voltage");
voltageDataPoint.setDescription("Output Voltage");
voltageDataPoint.setUnits("V");
voltageDataPoint.setSize(1);
voltageDataPoint.setAddressOffset(14);
voltageDataPoint.setBlockOffset(12);
voltageDataPoint.setScaleFactorName("DCV_SF");
voltageDataPoint.setSunSpecDataType("int16");
voltageDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(voltageDataPoint.name(), voltageDataPoint);
SunSpecDataPoint tempDataPoint;
tempDataPoint.setName("Tmp");
tempDataPoint.setLabel("Temp");
tempDataPoint.setDescription("Internal operating temperature");
tempDataPoint.setUnits("C");
tempDataPoint.setSize(1);
tempDataPoint.setAddressOffset(15);
tempDataPoint.setBlockOffset(13);
tempDataPoint.setSunSpecDataType("int16");
tempDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(tempDataPoint.name(), tempDataPoint);
SunSpecDataPoint inDCA_SFDataPoint;
inDCA_SFDataPoint.setName("InDCA_SF");
inDCA_SFDataPoint.setDescription("Current scale factor for inputs");
inDCA_SFDataPoint.setSize(1);
inDCA_SFDataPoint.setAddressOffset(16);
inDCA_SFDataPoint.setBlockOffset(14);
inDCA_SFDataPoint.setSunSpecDataType("sunssf");
inDCA_SFDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(inDCA_SFDataPoint.name(), inDCA_SFDataPoint);
SunSpecDataPoint inDCAhr_SFDataPoint;
inDCAhr_SFDataPoint.setName("InDCAhr_SF");
inDCAhr_SFDataPoint.setDescription("Amp-hour scale factor for inputs");
inDCAhr_SFDataPoint.setSize(1);
inDCAhr_SFDataPoint.setAddressOffset(17);
inDCAhr_SFDataPoint.setBlockOffset(15);
inDCAhr_SFDataPoint.setSunSpecDataType("sunssf");
inDCAhr_SFDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(inDCAhr_SFDataPoint.name(), inDCAhr_SFDataPoint);
}
void SunSpecStringCombinerCurrentModel::processBlockData()
{
// Scale factors
if (m_dataPoints.value("DCA_SF").isValid())
m_dCA_SF = m_dataPoints.value("DCA_SF").toInt16();
if (m_dataPoints.value("DCAhr_SF").isValid())
m_dCAhr_SF = m_dataPoints.value("DCAhr_SF").toInt16();
if (m_dataPoints.value("DCV_SF").isValid())
m_dCV_SF = m_dataPoints.value("DCV_SF").toInt16();
if (m_dataPoints.value("InDCA_SF").isValid())
m_inDCA_SF = m_dataPoints.value("InDCA_SF").toInt16();
if (m_dataPoints.value("InDCAhr_SF").isValid())
m_inDCAhr_SF = m_dataPoints.value("InDCAhr_SF").toInt16();
// Update properties according to the data point type
if (m_dataPoints.value("DCA_SF").isValid())
m_dCA_SF = m_dataPoints.value("DCA_SF").toInt16();
if (m_dataPoints.value("DCAhr_SF").isValid())
m_dCAhr_SF = m_dataPoints.value("DCAhr_SF").toInt16();
if (m_dataPoints.value("DCV_SF").isValid())
m_dCV_SF = m_dataPoints.value("DCV_SF").toInt16();
if (m_dataPoints.value("DCAMax").isValid())
m_rating = m_dataPoints.value("DCAMax").toFloatWithSSF(m_dCA_SF);
if (m_dataPoints.value("N").isValid())
m_n = m_dataPoints.value("N").toUInt16();
if (m_dataPoints.value("Evt").isValid())
m_eventFlags = static_cast<EvtFlags>(m_dataPoints.value("Evt").toUInt32());
if (m_dataPoints.value("EvtVnd").isValid())
m_vendorEvent = m_dataPoints.value("EvtVnd").toUInt32();
if (m_dataPoints.value("DCA").isValid())
m_amps = m_dataPoints.value("DCA").toFloatWithSSF(m_dCA_SF);
if (m_dataPoints.value("DCAhr").isValid())
m_ampHours = m_dataPoints.value("DCAhr").toFloatWithSSF(m_dCAhr_SF);
if (m_dataPoints.value("DCV").isValid())
m_voltage = m_dataPoints.value("DCV").toFloatWithSSF(m_dCV_SF);
if (m_dataPoints.value("Tmp").isValid())
m_temp = m_dataPoints.value("Tmp").toInt16();
if (m_dataPoints.value("InDCA_SF").isValid())
m_inDCA_SF = m_dataPoints.value("InDCA_SF").toInt16();
if (m_dataPoints.value("InDCAhr_SF").isValid())
m_inDCAhr_SF = m_dataPoints.value("InDCAhr_SF").toInt16();
qCDebug(dcSunSpecModelData()) << this;
}
QDebug operator<<(QDebug debug, SunSpecStringCombinerCurrentModel *model)
{
debug.nospace().noquote() << "SunSpecStringCombinerCurrentModel(Model: " << model->modelId() << ", Register: " << model->modbusStartRegister() << ", Length: " << model->modelLength() << ")\n";
debug.nospace().noquote() << " - " << model->dataPoints().value("DCAMax") << "-->";
if (model->dataPoints().value("DCAMax").isValid()) {
debug.nospace().noquote() << model->rating() << "\n";
} else {
debug.nospace().noquote() << "NaN\n";
}
debug.nospace().noquote() << " - " << model->dataPoints().value("N") << "-->";
if (model->dataPoints().value("N").isValid()) {
debug.nospace().noquote() << model->n() << "\n";
} else {
debug.nospace().noquote() << "NaN\n";
}
debug.nospace().noquote() << " - " << model->dataPoints().value("Evt") << "-->";
if (model->dataPoints().value("Evt").isValid()) {
debug.nospace().noquote() << model->eventFlags() << "\n";
} else {
debug.nospace().noquote() << "NaN\n";
}
debug.nospace().noquote() << " - " << model->dataPoints().value("EvtVnd") << "-->";
if (model->dataPoints().value("EvtVnd").isValid()) {
debug.nospace().noquote() << model->vendorEvent() << "\n";
} else {
debug.nospace().noquote() << "NaN\n";
}
debug.nospace().noquote() << " - " << model->dataPoints().value("DCA") << "-->";
if (model->dataPoints().value("DCA").isValid()) {
debug.nospace().noquote() << model->amps() << "\n";
} else {
debug.nospace().noquote() << "NaN\n";
}
debug.nospace().noquote() << " - " << model->dataPoints().value("DCAhr") << "-->";
if (model->dataPoints().value("DCAhr").isValid()) {
debug.nospace().noquote() << model->ampHours() << "\n";
} else {
debug.nospace().noquote() << "NaN\n";
}
debug.nospace().noquote() << " - " << model->dataPoints().value("DCV") << "-->";
if (model->dataPoints().value("DCV").isValid()) {
debug.nospace().noquote() << model->voltage() << "\n";
} else {
debug.nospace().noquote() << "NaN\n";
}
debug.nospace().noquote() << " - " << model->dataPoints().value("Tmp") << "-->";
if (model->dataPoints().value("Tmp").isValid()) {
debug.nospace().noquote() << model->temp() << "\n";
} else {
debug.nospace().noquote() << "NaN\n";
}
return debug.space().quote();
}