/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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 "sunspecstoragemodel.h" #include "sunspecconnection.h" SunSpecStorageModel::SunSpecStorageModel(SunSpecConnection *connection, quint16 modbusStartRegister, quint16 modelLength, SunSpecDataPoint::ByteOrder byteOrder, QObject *parent) : SunSpecModel(connection, modbusStartRegister, 124, modelLength, byteOrder, parent) { m_modelBlockType = SunSpecModel::ModelBlockTypeFixed; initDataPoints(); } SunSpecStorageModel::~SunSpecStorageModel() { } QString SunSpecStorageModel::name() const { return "storage"; } QString SunSpecStorageModel::description() const { return "Basic Storage Controls "; } QString SunSpecStorageModel::label() const { return "Storage"; } float SunSpecStorageModel::wChaMax() const { return m_wChaMax; } QModbusReply *SunSpecStorageModel::setWChaMax(float wChaMax) { if (!m_initialized) return nullptr; SunSpecDataPoint dp = m_dataPoints.value("WChaMax"); QVector registers = SunSpecDataPoint::convertFromFloatWithSSF(wChaMax, m_wChaMaxSf, dp.dataType()); QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, m_modbusStartRegister + dp.addressOffset(), registers.length()); request.setValues(registers); return m_connection->modbusTcpClient()->sendWriteRequest(request, m_connection->slaveId()); } float SunSpecStorageModel::wChaGra() const { return m_wChaGra; } QModbusReply *SunSpecStorageModel::setWChaGra(float wChaGra) { if (!m_initialized) return nullptr; SunSpecDataPoint dp = m_dataPoints.value("WChaGra"); QVector registers = SunSpecDataPoint::convertFromFloatWithSSF(wChaGra, m_wChaDisChaGraSf, dp.dataType()); QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, m_modbusStartRegister + dp.addressOffset(), registers.length()); request.setValues(registers); return m_connection->modbusTcpClient()->sendWriteRequest(request, m_connection->slaveId()); } float SunSpecStorageModel::wDisChaGra() const { return m_wDisChaGra; } QModbusReply *SunSpecStorageModel::setWDisChaGra(float wDisChaGra) { if (!m_initialized) return nullptr; SunSpecDataPoint dp = m_dataPoints.value("WDisChaGra"); QVector registers = SunSpecDataPoint::convertFromFloatWithSSF(wDisChaGra, m_wChaDisChaGraSf, dp.dataType()); QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, m_modbusStartRegister + dp.addressOffset(), registers.length()); request.setValues(registers); return m_connection->modbusTcpClient()->sendWriteRequest(request, m_connection->slaveId()); } SunSpecStorageModel::Storctl_modFlags SunSpecStorageModel::storCtlMod() const { return m_storCtlMod; } QModbusReply *SunSpecStorageModel::setStorCtlMod(Storctl_modFlags storCtlMod) { if (!m_initialized) return nullptr; SunSpecDataPoint dp = m_dataPoints.value("StorCtl_Mod"); QVector registers = SunSpecDataPoint::convertFromUInt16(static_cast(storCtlMod)); QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, m_modbusStartRegister + dp.addressOffset(), registers.length()); request.setValues(registers); return m_connection->modbusTcpClient()->sendWriteRequest(request, m_connection->slaveId()); } float SunSpecStorageModel::vaChaMax() const { return m_vaChaMax; } QModbusReply *SunSpecStorageModel::setVaChaMax(float vaChaMax) { if (!m_initialized) return nullptr; SunSpecDataPoint dp = m_dataPoints.value("VAChaMax"); QVector registers = SunSpecDataPoint::convertFromFloatWithSSF(vaChaMax, m_vaChaMaxSf, dp.dataType()); QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, m_modbusStartRegister + dp.addressOffset(), registers.length()); request.setValues(registers); return m_connection->modbusTcpClient()->sendWriteRequest(request, m_connection->slaveId()); } float SunSpecStorageModel::minRsvPct() const { return m_minRsvPct; } QModbusReply *SunSpecStorageModel::setMinRsvPct(float minRsvPct) { if (!m_initialized) return nullptr; SunSpecDataPoint dp = m_dataPoints.value("MinRsvPct"); QVector registers = SunSpecDataPoint::convertFromFloatWithSSF(minRsvPct, m_minRsvPctSf, dp.dataType()); QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, m_modbusStartRegister + dp.addressOffset(), registers.length()); request.setValues(registers); return m_connection->modbusTcpClient()->sendWriteRequest(request, m_connection->slaveId()); } float SunSpecStorageModel::chaState() const { return m_chaState; } float SunSpecStorageModel::storAval() const { return m_storAval; } float SunSpecStorageModel::inBatV() const { return m_inBatV; } SunSpecStorageModel::Chast SunSpecStorageModel::chaSt() const { return m_chaSt; } float SunSpecStorageModel::outWRte() const { return m_outWRte; } QModbusReply *SunSpecStorageModel::setOutWRte(float outWRte) { if (!m_initialized) return nullptr; SunSpecDataPoint dp = m_dataPoints.value("OutWRte"); QVector registers = SunSpecDataPoint::convertFromFloatWithSSF(outWRte, m_inOutWRteSf, dp.dataType()); QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, m_modbusStartRegister + dp.addressOffset(), registers.length()); request.setValues(registers); return m_connection->modbusTcpClient()->sendWriteRequest(request, m_connection->slaveId()); } float SunSpecStorageModel::inWRte() const { return m_inWRte; } QModbusReply *SunSpecStorageModel::setInWRte(float inWRte) { if (!m_initialized) return nullptr; SunSpecDataPoint dp = m_dataPoints.value("InWRte"); QVector registers = SunSpecDataPoint::convertFromFloatWithSSF(inWRte, m_inOutWRteSf, dp.dataType()); QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, m_modbusStartRegister + dp.addressOffset(), registers.length()); request.setValues(registers); return m_connection->modbusTcpClient()->sendWriteRequest(request, m_connection->slaveId()); } quint16 SunSpecStorageModel::inOutWRteWinTms() const { return m_inOutWRteWinTms; } QModbusReply *SunSpecStorageModel::setInOutWRteWinTms(quint16 inOutWRteWinTms) { if (!m_initialized) return nullptr; SunSpecDataPoint dp = m_dataPoints.value("InOutWRte_WinTms"); QVector registers = SunSpecDataPoint::convertFromUInt16(inOutWRteWinTms); QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, m_modbusStartRegister + dp.addressOffset(), registers.length()); request.setValues(registers); return m_connection->modbusTcpClient()->sendWriteRequest(request, m_connection->slaveId()); } quint16 SunSpecStorageModel::inOutWRteRvrtTms() const { return m_inOutWRteRvrtTms; } QModbusReply *SunSpecStorageModel::setInOutWRteRvrtTms(quint16 inOutWRteRvrtTms) { if (!m_initialized) return nullptr; SunSpecDataPoint dp = m_dataPoints.value("InOutWRte_RvrtTms"); QVector registers = SunSpecDataPoint::convertFromUInt16(inOutWRteRvrtTms); QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, m_modbusStartRegister + dp.addressOffset(), registers.length()); request.setValues(registers); return m_connection->modbusTcpClient()->sendWriteRequest(request, m_connection->slaveId()); } quint16 SunSpecStorageModel::inOutWRteRmpTms() const { return m_inOutWRteRmpTms; } QModbusReply *SunSpecStorageModel::setInOutWRteRmpTms(quint16 inOutWRteRmpTms) { if (!m_initialized) return nullptr; SunSpecDataPoint dp = m_dataPoints.value("InOutWRte_RmpTms"); QVector registers = SunSpecDataPoint::convertFromUInt16(inOutWRteRmpTms); QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, m_modbusStartRegister + dp.addressOffset(), registers.length()); request.setValues(registers); return m_connection->modbusTcpClient()->sendWriteRequest(request, m_connection->slaveId()); } SunSpecStorageModel::Chagriset SunSpecStorageModel::chaGriSet() const { return m_chaGriSet; } QModbusReply *SunSpecStorageModel::setChaGriSet(Chagriset chaGriSet) { if (!m_initialized) return nullptr; SunSpecDataPoint dp = m_dataPoints.value("ChaGriSet"); QVector registers = SunSpecDataPoint::convertFromUInt16(static_cast(chaGriSet)); QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, m_modbusStartRegister + dp.addressOffset(), registers.length()); request.setValues(registers); return m_connection->modbusTcpClient()->sendWriteRequest(request, m_connection->slaveId()); } qint16 SunSpecStorageModel::wChaMaxSf() const { return m_wChaMaxSf; } qint16 SunSpecStorageModel::wChaDisChaGraSf() const { return m_wChaDisChaGraSf; } qint16 SunSpecStorageModel::vaChaMaxSf() const { return m_vaChaMaxSf; } qint16 SunSpecStorageModel::minRsvPctSf() const { return m_minRsvPctSf; } qint16 SunSpecStorageModel::chaStateSf() const { return m_chaStateSf; } qint16 SunSpecStorageModel::storAvalSf() const { return m_storAvalSf; } qint16 SunSpecStorageModel::inBatVSf() const { return m_inBatVSf; } qint16 SunSpecStorageModel::inOutWRteSf() const { return m_inOutWRteSf; } void SunSpecStorageModel::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 wChaMaxDataPoint; wChaMaxDataPoint.setName("WChaMax"); wChaMaxDataPoint.setLabel("WChaMax"); wChaMaxDataPoint.setDescription("Setpoint for maximum charge."); wChaMaxDataPoint.setUnits("W"); wChaMaxDataPoint.setMandatory(true); wChaMaxDataPoint.setSize(1); wChaMaxDataPoint.setAddressOffset(2); wChaMaxDataPoint.setBlockOffset(0); wChaMaxDataPoint.setScaleFactorName("WChaMax_SF"); wChaMaxDataPoint.setSunSpecDataType("uint16"); wChaMaxDataPoint.setAccess(SunSpecDataPoint::AccessReadWrite); wChaMaxDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(wChaMaxDataPoint.name(), wChaMaxDataPoint); SunSpecDataPoint wChaGraDataPoint; wChaGraDataPoint.setName("WChaGra"); wChaGraDataPoint.setLabel("WChaGra"); wChaGraDataPoint.setDescription("Setpoint for maximum charging rate. Default is MaxChaRte."); wChaGraDataPoint.setUnits("% WChaMax/sec"); wChaGraDataPoint.setMandatory(true); wChaGraDataPoint.setSize(1); wChaGraDataPoint.setAddressOffset(3); wChaGraDataPoint.setBlockOffset(1); wChaGraDataPoint.setScaleFactorName("WChaDisChaGra_SF"); wChaGraDataPoint.setSunSpecDataType("uint16"); wChaGraDataPoint.setAccess(SunSpecDataPoint::AccessReadWrite); wChaGraDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(wChaGraDataPoint.name(), wChaGraDataPoint); SunSpecDataPoint wDisChaGraDataPoint; wDisChaGraDataPoint.setName("WDisChaGra"); wDisChaGraDataPoint.setLabel("WDisChaGra"); wDisChaGraDataPoint.setDescription("Setpoint for maximum discharge rate. Default is MaxDisChaRte."); wDisChaGraDataPoint.setUnits("% WChaMax/sec"); wDisChaGraDataPoint.setMandatory(true); wDisChaGraDataPoint.setSize(1); wDisChaGraDataPoint.setAddressOffset(4); wDisChaGraDataPoint.setBlockOffset(2); wDisChaGraDataPoint.setScaleFactorName("WChaDisChaGra_SF"); wDisChaGraDataPoint.setSunSpecDataType("uint16"); wDisChaGraDataPoint.setAccess(SunSpecDataPoint::AccessReadWrite); wDisChaGraDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(wDisChaGraDataPoint.name(), wDisChaGraDataPoint); SunSpecDataPoint storCtlModDataPoint; storCtlModDataPoint.setName("StorCtl_Mod"); storCtlModDataPoint.setLabel("StorCtl_Mod"); storCtlModDataPoint.setDescription("Activate hold/discharge/charge storage control mode. Bitfield value."); storCtlModDataPoint.setMandatory(true); storCtlModDataPoint.setSize(1); storCtlModDataPoint.setAddressOffset(5); storCtlModDataPoint.setBlockOffset(3); storCtlModDataPoint.setSunSpecDataType("bitfield16"); storCtlModDataPoint.setAccess(SunSpecDataPoint::AccessReadWrite); storCtlModDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(storCtlModDataPoint.name(), storCtlModDataPoint); SunSpecDataPoint vaChaMaxDataPoint; vaChaMaxDataPoint.setName("VAChaMax"); vaChaMaxDataPoint.setLabel("VAChaMax"); vaChaMaxDataPoint.setDescription("Setpoint for maximum charging VA."); vaChaMaxDataPoint.setUnits("VA"); vaChaMaxDataPoint.setSize(1); vaChaMaxDataPoint.setAddressOffset(6); vaChaMaxDataPoint.setBlockOffset(4); vaChaMaxDataPoint.setScaleFactorName("VAChaMax_SF"); vaChaMaxDataPoint.setSunSpecDataType("uint16"); vaChaMaxDataPoint.setAccess(SunSpecDataPoint::AccessReadWrite); vaChaMaxDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(vaChaMaxDataPoint.name(), vaChaMaxDataPoint); SunSpecDataPoint minRsvPctDataPoint; minRsvPctDataPoint.setName("MinRsvPct"); minRsvPctDataPoint.setLabel("MinRsvPct"); minRsvPctDataPoint.setDescription("Setpoint for minimum reserve for storage as a percentage of the nominal maximum storage."); minRsvPctDataPoint.setUnits("% WChaMax"); minRsvPctDataPoint.setSize(1); minRsvPctDataPoint.setAddressOffset(7); minRsvPctDataPoint.setBlockOffset(5); minRsvPctDataPoint.setScaleFactorName("MinRsvPct_SF"); minRsvPctDataPoint.setSunSpecDataType("uint16"); minRsvPctDataPoint.setAccess(SunSpecDataPoint::AccessReadWrite); minRsvPctDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(minRsvPctDataPoint.name(), minRsvPctDataPoint); SunSpecDataPoint chaStateDataPoint; chaStateDataPoint.setName("ChaState"); chaStateDataPoint.setLabel("ChaState"); chaStateDataPoint.setDescription("Currently available energy as a percent of the capacity rating."); chaStateDataPoint.setUnits("% AhrRtg"); chaStateDataPoint.setSize(1); chaStateDataPoint.setAddressOffset(8); chaStateDataPoint.setBlockOffset(6); chaStateDataPoint.setScaleFactorName("ChaState_SF"); chaStateDataPoint.setSunSpecDataType("uint16"); chaStateDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(chaStateDataPoint.name(), chaStateDataPoint); SunSpecDataPoint storAvalDataPoint; storAvalDataPoint.setName("StorAval"); storAvalDataPoint.setLabel("StorAval"); storAvalDataPoint.setDescription("State of charge (ChaState) minus storage reserve (MinRsvPct) times capacity rating (AhrRtg)."); storAvalDataPoint.setUnits("AH"); storAvalDataPoint.setSize(1); storAvalDataPoint.setAddressOffset(9); storAvalDataPoint.setBlockOffset(7); storAvalDataPoint.setScaleFactorName("StorAval_SF"); storAvalDataPoint.setSunSpecDataType("uint16"); storAvalDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(storAvalDataPoint.name(), storAvalDataPoint); SunSpecDataPoint inBatVDataPoint; inBatVDataPoint.setName("InBatV"); inBatVDataPoint.setLabel("InBatV"); inBatVDataPoint.setDescription("Internal battery voltage."); inBatVDataPoint.setUnits("V"); inBatVDataPoint.setSize(1); inBatVDataPoint.setAddressOffset(10); inBatVDataPoint.setBlockOffset(8); inBatVDataPoint.setScaleFactorName("InBatV_SF"); inBatVDataPoint.setSunSpecDataType("uint16"); inBatVDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(inBatVDataPoint.name(), inBatVDataPoint); SunSpecDataPoint chaStDataPoint; chaStDataPoint.setName("ChaSt"); chaStDataPoint.setLabel("ChaSt"); chaStDataPoint.setDescription("Charge status of storage device. Enumerated value."); chaStDataPoint.setSize(1); chaStDataPoint.setAddressOffset(11); chaStDataPoint.setBlockOffset(9); chaStDataPoint.setSunSpecDataType("enum16"); chaStDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(chaStDataPoint.name(), chaStDataPoint); SunSpecDataPoint outWRteDataPoint; outWRteDataPoint.setName("OutWRte"); outWRteDataPoint.setLabel("OutWRte"); outWRteDataPoint.setDescription("Percent of max discharge rate."); outWRteDataPoint.setUnits("% WDisChaMax"); outWRteDataPoint.setSize(1); outWRteDataPoint.setAddressOffset(12); outWRteDataPoint.setBlockOffset(10); outWRteDataPoint.setScaleFactorName("InOutWRte_SF"); outWRteDataPoint.setSunSpecDataType("int16"); outWRteDataPoint.setAccess(SunSpecDataPoint::AccessReadWrite); outWRteDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(outWRteDataPoint.name(), outWRteDataPoint); SunSpecDataPoint inWRteDataPoint; inWRteDataPoint.setName("InWRte"); inWRteDataPoint.setLabel("InWRte"); inWRteDataPoint.setDescription("Percent of max charging rate."); inWRteDataPoint.setUnits(" % WChaMax"); inWRteDataPoint.setSize(1); inWRteDataPoint.setAddressOffset(13); inWRteDataPoint.setBlockOffset(11); inWRteDataPoint.setScaleFactorName("InOutWRte_SF"); inWRteDataPoint.setSunSpecDataType("int16"); inWRteDataPoint.setAccess(SunSpecDataPoint::AccessReadWrite); inWRteDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(inWRteDataPoint.name(), inWRteDataPoint); SunSpecDataPoint inOutWRteWinTmsDataPoint; inOutWRteWinTmsDataPoint.setName("InOutWRte_WinTms"); inOutWRteWinTmsDataPoint.setLabel("InOutWRte_WinTms"); inOutWRteWinTmsDataPoint.setDescription("Time window for charge/discharge rate change."); inOutWRteWinTmsDataPoint.setUnits("Secs"); inOutWRteWinTmsDataPoint.setSize(1); inOutWRteWinTmsDataPoint.setAddressOffset(14); inOutWRteWinTmsDataPoint.setBlockOffset(12); inOutWRteWinTmsDataPoint.setSunSpecDataType("uint16"); inOutWRteWinTmsDataPoint.setAccess(SunSpecDataPoint::AccessReadWrite); inOutWRteWinTmsDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(inOutWRteWinTmsDataPoint.name(), inOutWRteWinTmsDataPoint); SunSpecDataPoint inOutWRteRvrtTmsDataPoint; inOutWRteRvrtTmsDataPoint.setName("InOutWRte_RvrtTms"); inOutWRteRvrtTmsDataPoint.setLabel("InOutWRte_RvrtTms"); inOutWRteRvrtTmsDataPoint.setDescription("Timeout period for charge/discharge rate."); inOutWRteRvrtTmsDataPoint.setUnits("Secs"); inOutWRteRvrtTmsDataPoint.setSize(1); inOutWRteRvrtTmsDataPoint.setAddressOffset(15); inOutWRteRvrtTmsDataPoint.setBlockOffset(13); inOutWRteRvrtTmsDataPoint.setSunSpecDataType("uint16"); inOutWRteRvrtTmsDataPoint.setAccess(SunSpecDataPoint::AccessReadWrite); inOutWRteRvrtTmsDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(inOutWRteRvrtTmsDataPoint.name(), inOutWRteRvrtTmsDataPoint); SunSpecDataPoint inOutWRteRmpTmsDataPoint; inOutWRteRmpTmsDataPoint.setName("InOutWRte_RmpTms"); inOutWRteRmpTmsDataPoint.setLabel("InOutWRte_RmpTms"); inOutWRteRmpTmsDataPoint.setDescription("Ramp time for moving from current setpoint to new setpoint."); inOutWRteRmpTmsDataPoint.setUnits("Secs"); inOutWRteRmpTmsDataPoint.setSize(1); inOutWRteRmpTmsDataPoint.setAddressOffset(16); inOutWRteRmpTmsDataPoint.setBlockOffset(14); inOutWRteRmpTmsDataPoint.setSunSpecDataType("uint16"); inOutWRteRmpTmsDataPoint.setAccess(SunSpecDataPoint::AccessReadWrite); inOutWRteRmpTmsDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(inOutWRteRmpTmsDataPoint.name(), inOutWRteRmpTmsDataPoint); SunSpecDataPoint chaGriSetDataPoint; chaGriSetDataPoint.setName("ChaGriSet"); chaGriSetDataPoint.setSize(1); chaGriSetDataPoint.setAddressOffset(17); chaGriSetDataPoint.setBlockOffset(15); chaGriSetDataPoint.setSunSpecDataType("enum16"); chaGriSetDataPoint.setAccess(SunSpecDataPoint::AccessReadWrite); chaGriSetDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(chaGriSetDataPoint.name(), chaGriSetDataPoint); SunSpecDataPoint wChaMaxSfDataPoint; wChaMaxSfDataPoint.setName("WChaMax_SF"); wChaMaxSfDataPoint.setLabel("WChaMax_SF"); wChaMaxSfDataPoint.setDescription("Scale factor for maximum charge."); wChaMaxSfDataPoint.setMandatory(true); wChaMaxSfDataPoint.setSize(1); wChaMaxSfDataPoint.setAddressOffset(18); wChaMaxSfDataPoint.setBlockOffset(16); wChaMaxSfDataPoint.setSunSpecDataType("sunssf"); wChaMaxSfDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(wChaMaxSfDataPoint.name(), wChaMaxSfDataPoint); SunSpecDataPoint wChaDisChaGraSfDataPoint; wChaDisChaGraSfDataPoint.setName("WChaDisChaGra_SF"); wChaDisChaGraSfDataPoint.setLabel("WChaDisChaGra_SF"); wChaDisChaGraSfDataPoint.setDescription("Scale factor for maximum charge and discharge rate."); wChaDisChaGraSfDataPoint.setMandatory(true); wChaDisChaGraSfDataPoint.setSize(1); wChaDisChaGraSfDataPoint.setAddressOffset(19); wChaDisChaGraSfDataPoint.setBlockOffset(17); wChaDisChaGraSfDataPoint.setSunSpecDataType("sunssf"); wChaDisChaGraSfDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(wChaDisChaGraSfDataPoint.name(), wChaDisChaGraSfDataPoint); SunSpecDataPoint vaChaMaxSfDataPoint; vaChaMaxSfDataPoint.setName("VAChaMax_SF"); vaChaMaxSfDataPoint.setLabel("VAChaMax_SF"); vaChaMaxSfDataPoint.setDescription("Scale factor for maximum charging VA."); vaChaMaxSfDataPoint.setSize(1); vaChaMaxSfDataPoint.setAddressOffset(20); vaChaMaxSfDataPoint.setBlockOffset(18); vaChaMaxSfDataPoint.setSunSpecDataType("sunssf"); vaChaMaxSfDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(vaChaMaxSfDataPoint.name(), vaChaMaxSfDataPoint); SunSpecDataPoint minRsvPctSfDataPoint; minRsvPctSfDataPoint.setName("MinRsvPct_SF"); minRsvPctSfDataPoint.setLabel("MinRsvPct_SF"); minRsvPctSfDataPoint.setDescription("Scale factor for minimum reserve percentage."); minRsvPctSfDataPoint.setSize(1); minRsvPctSfDataPoint.setAddressOffset(21); minRsvPctSfDataPoint.setBlockOffset(19); minRsvPctSfDataPoint.setSunSpecDataType("sunssf"); minRsvPctSfDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(minRsvPctSfDataPoint.name(), minRsvPctSfDataPoint); SunSpecDataPoint chaStateSfDataPoint; chaStateSfDataPoint.setName("ChaState_SF"); chaStateSfDataPoint.setLabel("ChaState_SF"); chaStateSfDataPoint.setDescription("Scale factor for available energy percent."); chaStateSfDataPoint.setSize(1); chaStateSfDataPoint.setAddressOffset(22); chaStateSfDataPoint.setBlockOffset(20); chaStateSfDataPoint.setSunSpecDataType("sunssf"); chaStateSfDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(chaStateSfDataPoint.name(), chaStateSfDataPoint); SunSpecDataPoint storAvalSfDataPoint; storAvalSfDataPoint.setName("StorAval_SF"); storAvalSfDataPoint.setLabel("StorAval_SF"); storAvalSfDataPoint.setDescription("Scale factor for state of charge."); storAvalSfDataPoint.setSize(1); storAvalSfDataPoint.setAddressOffset(23); storAvalSfDataPoint.setBlockOffset(21); storAvalSfDataPoint.setSunSpecDataType("sunssf"); storAvalSfDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(storAvalSfDataPoint.name(), storAvalSfDataPoint); SunSpecDataPoint inBatVSfDataPoint; inBatVSfDataPoint.setName("InBatV_SF"); inBatVSfDataPoint.setLabel("InBatV_SF"); inBatVSfDataPoint.setDescription("Scale factor for battery voltage."); inBatVSfDataPoint.setSize(1); inBatVSfDataPoint.setAddressOffset(24); inBatVSfDataPoint.setBlockOffset(22); inBatVSfDataPoint.setSunSpecDataType("sunssf"); inBatVSfDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(inBatVSfDataPoint.name(), inBatVSfDataPoint); SunSpecDataPoint inOutWRteSfDataPoint; inOutWRteSfDataPoint.setName("InOutWRte_SF"); inOutWRteSfDataPoint.setLabel("InOutWRte_SF"); inOutWRteSfDataPoint.setDescription("Scale factor for percent charge/discharge rate."); inOutWRteSfDataPoint.setSize(1); inOutWRteSfDataPoint.setAddressOffset(25); inOutWRteSfDataPoint.setBlockOffset(23); inOutWRteSfDataPoint.setSunSpecDataType("sunssf"); inOutWRteSfDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(inOutWRteSfDataPoint.name(), inOutWRteSfDataPoint); } void SunSpecStorageModel::processBlockData() { // Scale factors if (m_dataPoints.value("WChaMax_SF").isValid()) m_wChaMaxSf = m_dataPoints.value("WChaMax_SF").toInt16(); if (m_dataPoints.value("WChaDisChaGra_SF").isValid()) m_wChaDisChaGraSf = m_dataPoints.value("WChaDisChaGra_SF").toInt16(); if (m_dataPoints.value("VAChaMax_SF").isValid()) m_vaChaMaxSf = m_dataPoints.value("VAChaMax_SF").toInt16(); if (m_dataPoints.value("MinRsvPct_SF").isValid()) m_minRsvPctSf = m_dataPoints.value("MinRsvPct_SF").toInt16(); if (m_dataPoints.value("ChaState_SF").isValid()) m_chaStateSf = m_dataPoints.value("ChaState_SF").toInt16(); if (m_dataPoints.value("StorAval_SF").isValid()) m_storAvalSf = m_dataPoints.value("StorAval_SF").toInt16(); if (m_dataPoints.value("InBatV_SF").isValid()) m_inBatVSf = m_dataPoints.value("InBatV_SF").toInt16(); if (m_dataPoints.value("InOutWRte_SF").isValid()) m_inOutWRteSf = m_dataPoints.value("InOutWRte_SF").toInt16(); // Update properties according to the data point type if (m_dataPoints.value("WChaMax").isValid()) m_wChaMax = m_dataPoints.value("WChaMax").toFloatWithSSF(m_wChaMaxSf); if (m_dataPoints.value("WChaGra").isValid()) m_wChaGra = m_dataPoints.value("WChaGra").toFloatWithSSF(m_wChaDisChaGraSf); if (m_dataPoints.value("WDisChaGra").isValid()) m_wDisChaGra = m_dataPoints.value("WDisChaGra").toFloatWithSSF(m_wChaDisChaGraSf); if (m_dataPoints.value("StorCtl_Mod").isValid()) m_storCtlMod = static_cast(m_dataPoints.value("StorCtl_Mod").toUInt16()); if (m_dataPoints.value("VAChaMax").isValid()) m_vaChaMax = m_dataPoints.value("VAChaMax").toFloatWithSSF(m_vaChaMaxSf); if (m_dataPoints.value("MinRsvPct").isValid()) m_minRsvPct = m_dataPoints.value("MinRsvPct").toFloatWithSSF(m_minRsvPctSf); if (m_dataPoints.value("ChaState").isValid()) m_chaState = m_dataPoints.value("ChaState").toFloatWithSSF(m_chaStateSf); if (m_dataPoints.value("StorAval").isValid()) m_storAval = m_dataPoints.value("StorAval").toFloatWithSSF(m_storAvalSf); if (m_dataPoints.value("InBatV").isValid()) m_inBatV = m_dataPoints.value("InBatV").toFloatWithSSF(m_inBatVSf); if (m_dataPoints.value("ChaSt").isValid()) m_chaSt = static_cast(m_dataPoints.value("ChaSt").toUInt16()); if (m_dataPoints.value("OutWRte").isValid()) m_outWRte = m_dataPoints.value("OutWRte").toFloatWithSSF(m_inOutWRteSf); if (m_dataPoints.value("InWRte").isValid()) m_inWRte = m_dataPoints.value("InWRte").toFloatWithSSF(m_inOutWRteSf); if (m_dataPoints.value("InOutWRte_WinTms").isValid()) m_inOutWRteWinTms = m_dataPoints.value("InOutWRte_WinTms").toUInt16(); if (m_dataPoints.value("InOutWRte_RvrtTms").isValid()) m_inOutWRteRvrtTms = m_dataPoints.value("InOutWRte_RvrtTms").toUInt16(); if (m_dataPoints.value("InOutWRte_RmpTms").isValid()) m_inOutWRteRmpTms = m_dataPoints.value("InOutWRte_RmpTms").toUInt16(); if (m_dataPoints.value("ChaGriSet").isValid()) m_chaGriSet = static_cast(m_dataPoints.value("ChaGriSet").toUInt16()); if (m_dataPoints.value("WChaMax_SF").isValid()) m_wChaMaxSf = m_dataPoints.value("WChaMax_SF").toInt16(); if (m_dataPoints.value("WChaDisChaGra_SF").isValid()) m_wChaDisChaGraSf = m_dataPoints.value("WChaDisChaGra_SF").toInt16(); if (m_dataPoints.value("VAChaMax_SF").isValid()) m_vaChaMaxSf = m_dataPoints.value("VAChaMax_SF").toInt16(); if (m_dataPoints.value("MinRsvPct_SF").isValid()) m_minRsvPctSf = m_dataPoints.value("MinRsvPct_SF").toInt16(); if (m_dataPoints.value("ChaState_SF").isValid()) m_chaStateSf = m_dataPoints.value("ChaState_SF").toInt16(); if (m_dataPoints.value("StorAval_SF").isValid()) m_storAvalSf = m_dataPoints.value("StorAval_SF").toInt16(); if (m_dataPoints.value("InBatV_SF").isValid()) m_inBatVSf = m_dataPoints.value("InBatV_SF").toInt16(); if (m_dataPoints.value("InOutWRte_SF").isValid()) m_inOutWRteSf = m_dataPoints.value("InOutWRte_SF").toInt16(); qCDebug(dcSunSpecModelData()) << this; } QDebug operator<<(QDebug debug, SunSpecStorageModel *model) { debug.nospace().noquote() << "SunSpecStorageModel(Model: " << model->modelId() << ", Register: " << model->modbusStartRegister() << ", Length: " << model->modelLength() << ")\n"; debug.nospace().noquote() << " - " << model->dataPoints().value("WChaMax") << "-->"; if (model->dataPoints().value("WChaMax").isValid()) { debug.nospace().noquote() << model->wChaMax() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("WChaGra") << "-->"; if (model->dataPoints().value("WChaGra").isValid()) { debug.nospace().noquote() << model->wChaGra() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("WDisChaGra") << "-->"; if (model->dataPoints().value("WDisChaGra").isValid()) { debug.nospace().noquote() << model->wDisChaGra() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("StorCtl_Mod") << "-->"; if (model->dataPoints().value("StorCtl_Mod").isValid()) { debug.nospace().noquote() << model->storCtlMod() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("VAChaMax") << "-->"; if (model->dataPoints().value("VAChaMax").isValid()) { debug.nospace().noquote() << model->vaChaMax() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("MinRsvPct") << "-->"; if (model->dataPoints().value("MinRsvPct").isValid()) { debug.nospace().noquote() << model->minRsvPct() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("ChaState") << "-->"; if (model->dataPoints().value("ChaState").isValid()) { debug.nospace().noquote() << model->chaState() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("StorAval") << "-->"; if (model->dataPoints().value("StorAval").isValid()) { debug.nospace().noquote() << model->storAval() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("InBatV") << "-->"; if (model->dataPoints().value("InBatV").isValid()) { debug.nospace().noquote() << model->inBatV() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("ChaSt") << "-->"; if (model->dataPoints().value("ChaSt").isValid()) { debug.nospace().noquote() << model->chaSt() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("OutWRte") << "-->"; if (model->dataPoints().value("OutWRte").isValid()) { debug.nospace().noquote() << model->outWRte() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("InWRte") << "-->"; if (model->dataPoints().value("InWRte").isValid()) { debug.nospace().noquote() << model->inWRte() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("InOutWRte_WinTms") << "-->"; if (model->dataPoints().value("InOutWRte_WinTms").isValid()) { debug.nospace().noquote() << model->inOutWRteWinTms() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("InOutWRte_RvrtTms") << "-->"; if (model->dataPoints().value("InOutWRte_RvrtTms").isValid()) { debug.nospace().noquote() << model->inOutWRteRvrtTms() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("InOutWRte_RmpTms") << "-->"; if (model->dataPoints().value("InOutWRte_RmpTms").isValid()) { debug.nospace().noquote() << model->inOutWRteRmpTms() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("ChaGriSet") << "-->"; if (model->dataPoints().value("ChaGriSet").isValid()) { debug.nospace().noquote() << model->chaGriSet() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } return debug.space().quote(); }