/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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 . * * 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 "sunspecstatusmodel.h" #include "sunspecconnection.h" SunSpecStatusModel::SunSpecStatusModel(SunSpecConnection *connection, quint16 modbusStartRegister, quint16 modelLength, SunSpecDataPoint::ByteOrder byteOrder, QObject *parent) : SunSpecModel(connection, modbusStartRegister, 122, modelLength, byteOrder, parent) { m_modelBlockType = SunSpecModel::ModelBlockTypeFixed; initDataPoints(); } SunSpecStatusModel::~SunSpecStatusModel() { } QString SunSpecStatusModel::name() const { return "status"; } QString SunSpecStatusModel::description() const { return "Inverter Controls Extended Measurements and Status "; } QString SunSpecStatusModel::label() const { return "Measurements_Status"; } SunSpecStatusModel::PvconnFlags SunSpecStatusModel::pvConn() const { return m_pvConn; } SunSpecStatusModel::StorconnFlags SunSpecStatusModel::storConn() const { return m_storConn; } SunSpecStatusModel::EcpconnFlags SunSpecStatusModel::ecpConn() const { return m_ecpConn; } quint64 SunSpecStatusModel::actWh() const { return m_actWh; } quint64 SunSpecStatusModel::actVAh() const { return m_actVAh; } quint64 SunSpecStatusModel::actVArhQ1() const { return m_actVArhQ1; } quint64 SunSpecStatusModel::actVArhQ2() const { return m_actVArhQ2; } quint64 SunSpecStatusModel::actVArhQ3() const { return m_actVArhQ3; } quint64 SunSpecStatusModel::actVArhQ4() const { return m_actVArhQ4; } float SunSpecStatusModel::vArAval() const { return m_vArAval; } qint16 SunSpecStatusModel::vArAvalSf() const { return m_vArAvalSf; } float SunSpecStatusModel::wAval() const { return m_wAval; } qint16 SunSpecStatusModel::wAvalSf() const { return m_wAvalSf; } SunSpecStatusModel::StsetlimmskFlags SunSpecStatusModel::stSetLimMsk() const { return m_stSetLimMsk; } SunSpecStatusModel::StactctlFlags SunSpecStatusModel::stActCtl() const { return m_stActCtl; } QString SunSpecStatusModel::tmSrc() const { return m_tmSrc; } quint32 SunSpecStatusModel::tms() const { return m_tms; } SunSpecStatusModel::RtstFlags SunSpecStatusModel::rtSt() const { return m_rtSt; } float SunSpecStatusModel::ris() const { return m_ris; } qint16 SunSpecStatusModel::risSf() const { return m_risSf; } void SunSpecStatusModel::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 pvConnDataPoint; pvConnDataPoint.setName("PVConn"); pvConnDataPoint.setLabel("PVConn"); pvConnDataPoint.setDescription("PV inverter present/available status. Enumerated value."); pvConnDataPoint.setMandatory(true); pvConnDataPoint.setSize(1); pvConnDataPoint.setAddressOffset(2); pvConnDataPoint.setBlockOffset(0); pvConnDataPoint.setSunSpecDataType("bitfield16"); pvConnDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(pvConnDataPoint.name(), pvConnDataPoint); SunSpecDataPoint storConnDataPoint; storConnDataPoint.setName("StorConn"); storConnDataPoint.setLabel("StorConn"); storConnDataPoint.setDescription("Storage inverter present/available status. Enumerated value."); storConnDataPoint.setMandatory(true); storConnDataPoint.setSize(1); storConnDataPoint.setAddressOffset(3); storConnDataPoint.setBlockOffset(1); storConnDataPoint.setSunSpecDataType("bitfield16"); storConnDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(storConnDataPoint.name(), storConnDataPoint); SunSpecDataPoint ecpConnDataPoint; ecpConnDataPoint.setName("ECPConn"); ecpConnDataPoint.setLabel("ECPConn"); ecpConnDataPoint.setDescription("ECP connection status: disconnected=0 connected=1."); ecpConnDataPoint.setMandatory(true); ecpConnDataPoint.setSize(1); ecpConnDataPoint.setAddressOffset(4); ecpConnDataPoint.setBlockOffset(2); ecpConnDataPoint.setSunSpecDataType("bitfield16"); ecpConnDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(ecpConnDataPoint.name(), ecpConnDataPoint); SunSpecDataPoint actWhDataPoint; actWhDataPoint.setName("ActWh"); actWhDataPoint.setLabel("ActWh"); actWhDataPoint.setDescription("AC lifetime active (real) energy output."); actWhDataPoint.setUnits("Wh"); actWhDataPoint.setSize(4); actWhDataPoint.setAddressOffset(5); actWhDataPoint.setBlockOffset(3); actWhDataPoint.setSunSpecDataType("acc64"); actWhDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(actWhDataPoint.name(), actWhDataPoint); SunSpecDataPoint actVAhDataPoint; actVAhDataPoint.setName("ActVAh"); actVAhDataPoint.setLabel("ActVAh"); actVAhDataPoint.setDescription("AC lifetime apparent energy output."); actVAhDataPoint.setUnits("VAh"); actVAhDataPoint.setSize(4); actVAhDataPoint.setAddressOffset(9); actVAhDataPoint.setBlockOffset(7); actVAhDataPoint.setSunSpecDataType("acc64"); actVAhDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(actVAhDataPoint.name(), actVAhDataPoint); SunSpecDataPoint actVArhQ1DataPoint; actVArhQ1DataPoint.setName("ActVArhQ1"); actVArhQ1DataPoint.setLabel("ActVArhQ1"); actVArhQ1DataPoint.setDescription("AC lifetime reactive energy output in quadrant 1."); actVArhQ1DataPoint.setUnits("varh"); actVArhQ1DataPoint.setSize(4); actVArhQ1DataPoint.setAddressOffset(13); actVArhQ1DataPoint.setBlockOffset(11); actVArhQ1DataPoint.setSunSpecDataType("acc64"); actVArhQ1DataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(actVArhQ1DataPoint.name(), actVArhQ1DataPoint); SunSpecDataPoint actVArhQ2DataPoint; actVArhQ2DataPoint.setName("ActVArhQ2"); actVArhQ2DataPoint.setLabel("ActVArhQ2"); actVArhQ2DataPoint.setDescription("AC lifetime reactive energy output in quadrant 2."); actVArhQ2DataPoint.setUnits("varh"); actVArhQ2DataPoint.setSize(4); actVArhQ2DataPoint.setAddressOffset(17); actVArhQ2DataPoint.setBlockOffset(15); actVArhQ2DataPoint.setSunSpecDataType("acc64"); actVArhQ2DataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(actVArhQ2DataPoint.name(), actVArhQ2DataPoint); SunSpecDataPoint actVArhQ3DataPoint; actVArhQ3DataPoint.setName("ActVArhQ3"); actVArhQ3DataPoint.setLabel("ActVArhQ3"); actVArhQ3DataPoint.setDescription("AC lifetime negative energy output in quadrant 3."); actVArhQ3DataPoint.setUnits("varh"); actVArhQ3DataPoint.setSize(4); actVArhQ3DataPoint.setAddressOffset(21); actVArhQ3DataPoint.setBlockOffset(19); actVArhQ3DataPoint.setSunSpecDataType("acc64"); actVArhQ3DataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(actVArhQ3DataPoint.name(), actVArhQ3DataPoint); SunSpecDataPoint actVArhQ4DataPoint; actVArhQ4DataPoint.setName("ActVArhQ4"); actVArhQ4DataPoint.setLabel("ActVArhQ4"); actVArhQ4DataPoint.setDescription("AC lifetime reactive energy output in quadrant 4."); actVArhQ4DataPoint.setUnits("varh"); actVArhQ4DataPoint.setSize(4); actVArhQ4DataPoint.setAddressOffset(25); actVArhQ4DataPoint.setBlockOffset(23); actVArhQ4DataPoint.setSunSpecDataType("acc64"); actVArhQ4DataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(actVArhQ4DataPoint.name(), actVArhQ4DataPoint); SunSpecDataPoint vArAvalDataPoint; vArAvalDataPoint.setName("VArAval"); vArAvalDataPoint.setLabel("VArAval"); vArAvalDataPoint.setDescription("Amount of VARs available without impacting watts output."); vArAvalDataPoint.setUnits("var"); vArAvalDataPoint.setSize(1); vArAvalDataPoint.setAddressOffset(29); vArAvalDataPoint.setBlockOffset(27); vArAvalDataPoint.setScaleFactorName("VArAval_SF"); vArAvalDataPoint.setSunSpecDataType("int16"); vArAvalDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(vArAvalDataPoint.name(), vArAvalDataPoint); SunSpecDataPoint vArAvalSfDataPoint; vArAvalSfDataPoint.setName("VArAval_SF"); vArAvalSfDataPoint.setLabel("VArAval_SF"); vArAvalSfDataPoint.setDescription("Scale factor for available VARs."); vArAvalSfDataPoint.setSize(1); vArAvalSfDataPoint.setAddressOffset(30); vArAvalSfDataPoint.setBlockOffset(28); vArAvalSfDataPoint.setSunSpecDataType("sunssf"); vArAvalSfDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(vArAvalSfDataPoint.name(), vArAvalSfDataPoint); SunSpecDataPoint wAvalDataPoint; wAvalDataPoint.setName("WAval"); wAvalDataPoint.setLabel("WAval"); wAvalDataPoint.setDescription("Amount of Watts available."); wAvalDataPoint.setUnits("var"); wAvalDataPoint.setSize(1); wAvalDataPoint.setAddressOffset(31); wAvalDataPoint.setBlockOffset(29); wAvalDataPoint.setScaleFactorName("WAval_SF"); wAvalDataPoint.setSunSpecDataType("uint16"); wAvalDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(wAvalDataPoint.name(), wAvalDataPoint); SunSpecDataPoint wAvalSfDataPoint; wAvalSfDataPoint.setName("WAval_SF"); wAvalSfDataPoint.setLabel("WAval_SF"); wAvalSfDataPoint.setDescription("Scale factor for available Watts."); wAvalSfDataPoint.setSize(1); wAvalSfDataPoint.setAddressOffset(32); wAvalSfDataPoint.setBlockOffset(30); wAvalSfDataPoint.setSunSpecDataType("sunssf"); wAvalSfDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(wAvalSfDataPoint.name(), wAvalSfDataPoint); SunSpecDataPoint stSetLimMskDataPoint; stSetLimMskDataPoint.setName("StSetLimMsk"); stSetLimMskDataPoint.setLabel("StSetLimMsk"); stSetLimMskDataPoint.setDescription("Bit Mask indicating setpoint limit(s) reached."); stSetLimMskDataPoint.setSize(2); stSetLimMskDataPoint.setAddressOffset(33); stSetLimMskDataPoint.setBlockOffset(31); stSetLimMskDataPoint.setSunSpecDataType("bitfield32"); stSetLimMskDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(stSetLimMskDataPoint.name(), stSetLimMskDataPoint); SunSpecDataPoint stActCtlDataPoint; stActCtlDataPoint.setName("StActCtl"); stActCtlDataPoint.setLabel("StActCtl"); stActCtlDataPoint.setDescription("Bit Mask indicating which inverter controls are currently active."); stActCtlDataPoint.setSize(2); stActCtlDataPoint.setAddressOffset(35); stActCtlDataPoint.setBlockOffset(33); stActCtlDataPoint.setSunSpecDataType("bitfield32"); stActCtlDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(stActCtlDataPoint.name(), stActCtlDataPoint); SunSpecDataPoint tmSrcDataPoint; tmSrcDataPoint.setName("TmSrc"); tmSrcDataPoint.setLabel("TmSrc"); tmSrcDataPoint.setDescription("Source of time synchronization."); tmSrcDataPoint.setSize(4); tmSrcDataPoint.setAddressOffset(37); tmSrcDataPoint.setBlockOffset(35); tmSrcDataPoint.setSunSpecDataType("string"); tmSrcDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(tmSrcDataPoint.name(), tmSrcDataPoint); SunSpecDataPoint tmsDataPoint; tmsDataPoint.setName("Tms"); tmsDataPoint.setLabel("Tms"); tmsDataPoint.setDescription("Seconds since 01-01-2000 00:00 UTC"); tmsDataPoint.setUnits("Secs"); tmsDataPoint.setSize(2); tmsDataPoint.setAddressOffset(41); tmsDataPoint.setBlockOffset(39); tmsDataPoint.setSunSpecDataType("uint32"); tmsDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(tmsDataPoint.name(), tmsDataPoint); SunSpecDataPoint rtStDataPoint; rtStDataPoint.setName("RtSt"); rtStDataPoint.setLabel("RtSt"); rtStDataPoint.setDescription("Bit Mask indicating active ride-through status."); rtStDataPoint.setSize(1); rtStDataPoint.setAddressOffset(43); rtStDataPoint.setBlockOffset(41); rtStDataPoint.setSunSpecDataType("bitfield16"); rtStDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(rtStDataPoint.name(), rtStDataPoint); SunSpecDataPoint risDataPoint; risDataPoint.setName("Ris"); risDataPoint.setLabel("Ris"); risDataPoint.setDescription("Isolation resistance."); risDataPoint.setUnits("ohms"); risDataPoint.setSize(1); risDataPoint.setAddressOffset(44); risDataPoint.setBlockOffset(42); risDataPoint.setScaleFactorName("Ris_SF"); risDataPoint.setSunSpecDataType("uint16"); risDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(risDataPoint.name(), risDataPoint); SunSpecDataPoint risSfDataPoint; risSfDataPoint.setName("Ris_SF"); risSfDataPoint.setLabel("Ris_SF"); risSfDataPoint.setDescription("Scale factor for isolation resistance."); risSfDataPoint.setSize(1); risSfDataPoint.setAddressOffset(45); risSfDataPoint.setBlockOffset(43); risSfDataPoint.setSunSpecDataType("sunssf"); risSfDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(risSfDataPoint.name(), risSfDataPoint); } void SunSpecStatusModel::processBlockData() { // Scale factors if (m_dataPoints.value("VArAval_SF").isValid()) m_vArAvalSf = m_dataPoints.value("VArAval_SF").toInt16(); if (m_dataPoints.value("WAval_SF").isValid()) m_wAvalSf = m_dataPoints.value("WAval_SF").toInt16(); if (m_dataPoints.value("Ris_SF").isValid()) m_risSf = m_dataPoints.value("Ris_SF").toInt16(); // Update properties according to the data point type if (m_dataPoints.value("PVConn").isValid()) m_pvConn = static_cast(m_dataPoints.value("PVConn").toUInt16()); if (m_dataPoints.value("StorConn").isValid()) m_storConn = static_cast(m_dataPoints.value("StorConn").toUInt16()); if (m_dataPoints.value("ECPConn").isValid()) m_ecpConn = static_cast(m_dataPoints.value("ECPConn").toUInt16()); if (m_dataPoints.value("ActWh").isValid()) m_actWh = m_dataPoints.value("ActWh").toInt64(); if (m_dataPoints.value("ActVAh").isValid()) m_actVAh = m_dataPoints.value("ActVAh").toInt64(); if (m_dataPoints.value("ActVArhQ1").isValid()) m_actVArhQ1 = m_dataPoints.value("ActVArhQ1").toInt64(); if (m_dataPoints.value("ActVArhQ2").isValid()) m_actVArhQ2 = m_dataPoints.value("ActVArhQ2").toInt64(); if (m_dataPoints.value("ActVArhQ3").isValid()) m_actVArhQ3 = m_dataPoints.value("ActVArhQ3").toInt64(); if (m_dataPoints.value("ActVArhQ4").isValid()) m_actVArhQ4 = m_dataPoints.value("ActVArhQ4").toInt64(); if (m_dataPoints.value("VArAval").isValid()) m_vArAval = m_dataPoints.value("VArAval").toFloatWithSSF(m_vArAvalSf); if (m_dataPoints.value("VArAval_SF").isValid()) m_vArAvalSf = m_dataPoints.value("VArAval_SF").toInt16(); if (m_dataPoints.value("WAval").isValid()) m_wAval = m_dataPoints.value("WAval").toFloatWithSSF(m_wAvalSf); if (m_dataPoints.value("WAval_SF").isValid()) m_wAvalSf = m_dataPoints.value("WAval_SF").toInt16(); if (m_dataPoints.value("StSetLimMsk").isValid()) m_stSetLimMsk = static_cast(m_dataPoints.value("StSetLimMsk").toUInt32()); if (m_dataPoints.value("StActCtl").isValid()) m_stActCtl = static_cast(m_dataPoints.value("StActCtl").toUInt32()); if (m_dataPoints.value("TmSrc").isValid()) m_tmSrc = m_dataPoints.value("TmSrc").toString(); if (m_dataPoints.value("Tms").isValid()) m_tms = m_dataPoints.value("Tms").toUInt32(); if (m_dataPoints.value("RtSt").isValid()) m_rtSt = static_cast(m_dataPoints.value("RtSt").toUInt16()); if (m_dataPoints.value("Ris").isValid()) m_ris = m_dataPoints.value("Ris").toFloatWithSSF(m_risSf); if (m_dataPoints.value("Ris_SF").isValid()) m_risSf = m_dataPoints.value("Ris_SF").toInt16(); qCDebug(dcSunSpecModelData()) << this; } QDebug operator<<(QDebug debug, SunSpecStatusModel *model) { debug.nospace().noquote() << "SunSpecStatusModel(Model: " << model->modelId() << ", Register: " << model->modbusStartRegister() << ", Length: " << model->modelLength() << ")\n"; debug.nospace().noquote() << " - " << model->dataPoints().value("PVConn") << "-->"; if (model->dataPoints().value("PVConn").isValid()) { debug.nospace().noquote() << model->pvConn() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("StorConn") << "-->"; if (model->dataPoints().value("StorConn").isValid()) { debug.nospace().noquote() << model->storConn() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("ECPConn") << "-->"; if (model->dataPoints().value("ECPConn").isValid()) { debug.nospace().noquote() << model->ecpConn() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("ActWh") << "-->"; if (model->dataPoints().value("ActWh").isValid()) { debug.nospace().noquote() << model->actWh() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("ActVAh") << "-->"; if (model->dataPoints().value("ActVAh").isValid()) { debug.nospace().noquote() << model->actVAh() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("ActVArhQ1") << "-->"; if (model->dataPoints().value("ActVArhQ1").isValid()) { debug.nospace().noquote() << model->actVArhQ1() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("ActVArhQ2") << "-->"; if (model->dataPoints().value("ActVArhQ2").isValid()) { debug.nospace().noquote() << model->actVArhQ2() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("ActVArhQ3") << "-->"; if (model->dataPoints().value("ActVArhQ3").isValid()) { debug.nospace().noquote() << model->actVArhQ3() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("ActVArhQ4") << "-->"; if (model->dataPoints().value("ActVArhQ4").isValid()) { debug.nospace().noquote() << model->actVArhQ4() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("VArAval") << "-->"; if (model->dataPoints().value("VArAval").isValid()) { debug.nospace().noquote() << model->vArAval() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("WAval") << "-->"; if (model->dataPoints().value("WAval").isValid()) { debug.nospace().noquote() << model->wAval() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("StSetLimMsk") << "-->"; if (model->dataPoints().value("StSetLimMsk").isValid()) { debug.nospace().noquote() << model->stSetLimMsk() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("StActCtl") << "-->"; if (model->dataPoints().value("StActCtl").isValid()) { debug.nospace().noquote() << model->stActCtl() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("TmSrc") << "-->"; if (model->dataPoints().value("TmSrc").isValid()) { debug.nospace().noquote() << model->tmSrc() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("Tms") << "-->"; if (model->dataPoints().value("Tms").isValid()) { debug.nospace().noquote() << model->tms() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("RtSt") << "-->"; if (model->dataPoints().value("RtSt").isValid()) { debug.nospace().noquote() << model->rtSt() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("Ris") << "-->"; if (model->dataPoints().value("Ris").isValid()) { debug.nospace().noquote() << model->ris() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } return debug.space().quote(); }