nymea-plugins-modbus/libnymea-sunspec/models/sunspecbasemetmodel.cpp

377 lines
14 KiB
C++

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2025, 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 "sunspecbasemetmodel.h"
#include "sunspecconnection.h"
SunSpecBaseMetModel::SunSpecBaseMetModel(SunSpecConnection *connection, quint16 modbusStartRegister, quint16 modelLength, SunSpecDataPoint::ByteOrder byteOrder, QObject *parent) :
SunSpecModel(connection, modbusStartRegister, 307, modelLength, byteOrder, parent)
{
m_modelBlockType = SunSpecModel::ModelBlockTypeFixed;
initDataPoints();
}
SunSpecBaseMetModel::~SunSpecBaseMetModel()
{
}
QString SunSpecBaseMetModel::name() const
{
return "base_met";
}
QString SunSpecBaseMetModel::description() const
{
return "Base Meteorological Model";
}
QString SunSpecBaseMetModel::label() const
{
return "Base Met";
}
float SunSpecBaseMetModel::ambientTemperature() const
{
return m_ambientTemperature;
}
qint16 SunSpecBaseMetModel::relativeHumidity() const
{
return m_relativeHumidity;
}
qint16 SunSpecBaseMetModel::barometricPressure() const
{
return m_barometricPressure;
}
qint16 SunSpecBaseMetModel::windSpeed() const
{
return m_windSpeed;
}
qint16 SunSpecBaseMetModel::windDirection() const
{
return m_windDirection;
}
qint16 SunSpecBaseMetModel::rainfall() const
{
return m_rainfall;
}
qint16 SunSpecBaseMetModel::snowDepth() const
{
return m_snowDepth;
}
qint16 SunSpecBaseMetModel::precipitationType() const
{
return m_precipitationType;
}
qint16 SunSpecBaseMetModel::electricField() const
{
return m_electricField;
}
qint16 SunSpecBaseMetModel::surfaceWetness() const
{
return m_surfaceWetness;
}
qint16 SunSpecBaseMetModel::soilWetness() const
{
return m_soilWetness;
}
void SunSpecBaseMetModel::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 ambientTemperatureDataPoint;
ambientTemperatureDataPoint.setName("TmpAmb");
ambientTemperatureDataPoint.setLabel("Ambient Temperature");
ambientTemperatureDataPoint.setUnits("C");
ambientTemperatureDataPoint.setSize(1);
ambientTemperatureDataPoint.setAddressOffset(2);
ambientTemperatureDataPoint.setBlockOffset(0);
ambientTemperatureDataPoint.setScaleFactorName("-1");
ambientTemperatureDataPoint.setSunSpecDataType("int16");
ambientTemperatureDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(ambientTemperatureDataPoint.name(), ambientTemperatureDataPoint);
SunSpecDataPoint relativeHumidityDataPoint;
relativeHumidityDataPoint.setName("RH");
relativeHumidityDataPoint.setLabel("Relative Humidity");
relativeHumidityDataPoint.setUnits("Pct");
relativeHumidityDataPoint.setSize(1);
relativeHumidityDataPoint.setAddressOffset(3);
relativeHumidityDataPoint.setBlockOffset(1);
relativeHumidityDataPoint.setSunSpecDataType("int16");
relativeHumidityDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(relativeHumidityDataPoint.name(), relativeHumidityDataPoint);
SunSpecDataPoint barometricPressureDataPoint;
barometricPressureDataPoint.setName("Pres");
barometricPressureDataPoint.setLabel("Barometric Pressure");
barometricPressureDataPoint.setUnits("HPa");
barometricPressureDataPoint.setSize(1);
barometricPressureDataPoint.setAddressOffset(4);
barometricPressureDataPoint.setBlockOffset(2);
barometricPressureDataPoint.setSunSpecDataType("int16");
barometricPressureDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(barometricPressureDataPoint.name(), barometricPressureDataPoint);
SunSpecDataPoint windSpeedDataPoint;
windSpeedDataPoint.setName("WndSpd");
windSpeedDataPoint.setLabel("Wind Speed");
windSpeedDataPoint.setUnits("mps");
windSpeedDataPoint.setSize(1);
windSpeedDataPoint.setAddressOffset(5);
windSpeedDataPoint.setBlockOffset(3);
windSpeedDataPoint.setSunSpecDataType("int16");
windSpeedDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(windSpeedDataPoint.name(), windSpeedDataPoint);
SunSpecDataPoint windDirectionDataPoint;
windDirectionDataPoint.setName("WndDir");
windDirectionDataPoint.setLabel("Wind Direction");
windDirectionDataPoint.setUnits("deg");
windDirectionDataPoint.setSize(1);
windDirectionDataPoint.setAddressOffset(6);
windDirectionDataPoint.setBlockOffset(4);
windDirectionDataPoint.setSunSpecDataType("int16");
windDirectionDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(windDirectionDataPoint.name(), windDirectionDataPoint);
SunSpecDataPoint rainfallDataPoint;
rainfallDataPoint.setName("Rain");
rainfallDataPoint.setLabel("Rainfall");
rainfallDataPoint.setUnits("mm");
rainfallDataPoint.setSize(1);
rainfallDataPoint.setAddressOffset(7);
rainfallDataPoint.setBlockOffset(5);
rainfallDataPoint.setSunSpecDataType("int16");
rainfallDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(rainfallDataPoint.name(), rainfallDataPoint);
SunSpecDataPoint snowDepthDataPoint;
snowDepthDataPoint.setName("Snw");
snowDepthDataPoint.setLabel("Snow Depth");
snowDepthDataPoint.setUnits("mm");
snowDepthDataPoint.setSize(1);
snowDepthDataPoint.setAddressOffset(8);
snowDepthDataPoint.setBlockOffset(6);
snowDepthDataPoint.setSunSpecDataType("int16");
snowDepthDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(snowDepthDataPoint.name(), snowDepthDataPoint);
SunSpecDataPoint precipitationTypeDataPoint;
precipitationTypeDataPoint.setName("PPT");
precipitationTypeDataPoint.setLabel("Precipitation Type");
precipitationTypeDataPoint.setDescription("Precipitation Type (WMO 4680 SYNOP code reference)");
precipitationTypeDataPoint.setSize(1);
precipitationTypeDataPoint.setAddressOffset(9);
precipitationTypeDataPoint.setBlockOffset(7);
precipitationTypeDataPoint.setSunSpecDataType("int16");
precipitationTypeDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(precipitationTypeDataPoint.name(), precipitationTypeDataPoint);
SunSpecDataPoint electricFieldDataPoint;
electricFieldDataPoint.setName("ElecFld");
electricFieldDataPoint.setLabel("Electric Field");
electricFieldDataPoint.setUnits("Vm");
electricFieldDataPoint.setSize(1);
electricFieldDataPoint.setAddressOffset(10);
electricFieldDataPoint.setBlockOffset(8);
electricFieldDataPoint.setSunSpecDataType("int16");
electricFieldDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(electricFieldDataPoint.name(), electricFieldDataPoint);
SunSpecDataPoint surfaceWetnessDataPoint;
surfaceWetnessDataPoint.setName("SurWet");
surfaceWetnessDataPoint.setLabel("Surface Wetness");
surfaceWetnessDataPoint.setUnits("kO");
surfaceWetnessDataPoint.setSize(1);
surfaceWetnessDataPoint.setAddressOffset(11);
surfaceWetnessDataPoint.setBlockOffset(9);
surfaceWetnessDataPoint.setSunSpecDataType("int16");
surfaceWetnessDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(surfaceWetnessDataPoint.name(), surfaceWetnessDataPoint);
SunSpecDataPoint soilWetnessDataPoint;
soilWetnessDataPoint.setName("SoilWet");
soilWetnessDataPoint.setLabel("Soil Wetness");
soilWetnessDataPoint.setUnits("Pct");
soilWetnessDataPoint.setSize(1);
soilWetnessDataPoint.setAddressOffset(12);
soilWetnessDataPoint.setBlockOffset(10);
soilWetnessDataPoint.setSunSpecDataType("int16");
soilWetnessDataPoint.setByteOrder(m_byteOrder);
m_dataPoints.insert(soilWetnessDataPoint.name(), soilWetnessDataPoint);
}
void SunSpecBaseMetModel::processBlockData()
{
// Update properties according to the data point type
if (m_dataPoints.value("TmpAmb").isValid())
m_ambientTemperature = m_dataPoints.value("TmpAmb").toFloatWithSSF(-1);
if (m_dataPoints.value("RH").isValid())
m_relativeHumidity = m_dataPoints.value("RH").toInt16();
if (m_dataPoints.value("Pres").isValid())
m_barometricPressure = m_dataPoints.value("Pres").toInt16();
if (m_dataPoints.value("WndSpd").isValid())
m_windSpeed = m_dataPoints.value("WndSpd").toInt16();
if (m_dataPoints.value("WndDir").isValid())
m_windDirection = m_dataPoints.value("WndDir").toInt16();
if (m_dataPoints.value("Rain").isValid())
m_rainfall = m_dataPoints.value("Rain").toInt16();
if (m_dataPoints.value("Snw").isValid())
m_snowDepth = m_dataPoints.value("Snw").toInt16();
if (m_dataPoints.value("PPT").isValid())
m_precipitationType = m_dataPoints.value("PPT").toInt16();
if (m_dataPoints.value("ElecFld").isValid())
m_electricField = m_dataPoints.value("ElecFld").toInt16();
if (m_dataPoints.value("SurWet").isValid())
m_surfaceWetness = m_dataPoints.value("SurWet").toInt16();
if (m_dataPoints.value("SoilWet").isValid())
m_soilWetness = m_dataPoints.value("SoilWet").toInt16();
qCDebug(dcSunSpecModelData()) << this;
}
QDebug operator<<(QDebug debug, SunSpecBaseMetModel *model)
{
debug.nospace().noquote() << "SunSpecBaseMetModel(Model: " << model->modelId() << ", Register: " << model->modbusStartRegister() << ", Length: " << model->modelLength() << ")\n";
debug.nospace().noquote() << " - " << model->dataPoints().value("TmpAmb") << "-->";
if (model->dataPoints().value("TmpAmb").isValid()) {
debug.nospace().noquote() << model->ambientTemperature() << "\n";
} else {
debug.nospace().noquote() << "NaN\n";
}
debug.nospace().noquote() << " - " << model->dataPoints().value("RH") << "-->";
if (model->dataPoints().value("RH").isValid()) {
debug.nospace().noquote() << model->relativeHumidity() << "\n";
} else {
debug.nospace().noquote() << "NaN\n";
}
debug.nospace().noquote() << " - " << model->dataPoints().value("Pres") << "-->";
if (model->dataPoints().value("Pres").isValid()) {
debug.nospace().noquote() << model->barometricPressure() << "\n";
} else {
debug.nospace().noquote() << "NaN\n";
}
debug.nospace().noquote() << " - " << model->dataPoints().value("WndSpd") << "-->";
if (model->dataPoints().value("WndSpd").isValid()) {
debug.nospace().noquote() << model->windSpeed() << "\n";
} else {
debug.nospace().noquote() << "NaN\n";
}
debug.nospace().noquote() << " - " << model->dataPoints().value("WndDir") << "-->";
if (model->dataPoints().value("WndDir").isValid()) {
debug.nospace().noquote() << model->windDirection() << "\n";
} else {
debug.nospace().noquote() << "NaN\n";
}
debug.nospace().noquote() << " - " << model->dataPoints().value("Rain") << "-->";
if (model->dataPoints().value("Rain").isValid()) {
debug.nospace().noquote() << model->rainfall() << "\n";
} else {
debug.nospace().noquote() << "NaN\n";
}
debug.nospace().noquote() << " - " << model->dataPoints().value("Snw") << "-->";
if (model->dataPoints().value("Snw").isValid()) {
debug.nospace().noquote() << model->snowDepth() << "\n";
} else {
debug.nospace().noquote() << "NaN\n";
}
debug.nospace().noquote() << " - " << model->dataPoints().value("PPT") << "-->";
if (model->dataPoints().value("PPT").isValid()) {
debug.nospace().noquote() << model->precipitationType() << "\n";
} else {
debug.nospace().noquote() << "NaN\n";
}
debug.nospace().noquote() << " - " << model->dataPoints().value("ElecFld") << "-->";
if (model->dataPoints().value("ElecFld").isValid()) {
debug.nospace().noquote() << model->electricField() << "\n";
} else {
debug.nospace().noquote() << "NaN\n";
}
debug.nospace().noquote() << " - " << model->dataPoints().value("SurWet") << "-->";
if (model->dataPoints().value("SurWet").isValid()) {
debug.nospace().noquote() << model->surfaceWetness() << "\n";
} else {
debug.nospace().noquote() << "NaN\n";
}
debug.nospace().noquote() << " - " << model->dataPoints().value("SoilWet") << "-->";
if (model->dataPoints().value("SoilWet").isValid()) {
debug.nospace().noquote() << model->soilWetness() << "\n";
} else {
debug.nospace().noquote() << "NaN\n";
}
return debug.space().quote();
}