// SPDX-License-Identifier: LGPL-3.0-or-later /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright (C) 2013 - 2024, nymea GmbH * Copyright (C) 2024 - 2025, chargebyte austria GmbH * * This file is part of libnymea-sunspec. * * libnymea-sunspec is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * libnymea-sunspec 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 libnymea-sunspec. If not, see . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "sunspeclocationmodel.h" #include "sunspecconnection.h" SunSpecLocationModel::SunSpecLocationModel(SunSpecConnection *connection, quint16 modbusStartRegister, quint16 modelLength, SunSpecDataPoint::ByteOrder byteOrder, QObject *parent) : SunSpecModel(connection, modbusStartRegister, 305, modelLength, byteOrder, parent) { m_modelBlockType = SunSpecModel::ModelBlockTypeFixed; initDataPoints(); } SunSpecLocationModel::~SunSpecLocationModel() { } QString SunSpecLocationModel::name() const { return "location"; } QString SunSpecLocationModel::description() const { return "Include to support location measurements"; } QString SunSpecLocationModel::label() const { return "GPS"; } QString SunSpecLocationModel::tm() const { return m_tm; } QString SunSpecLocationModel::date() const { return m_date; } QString SunSpecLocationModel::location() const { return m_location; } float SunSpecLocationModel::lat() const { return m_lat; } float SunSpecLocationModel::longitude() const { return m_longitude; } qint32 SunSpecLocationModel::altitude() const { return m_altitude; } void SunSpecLocationModel::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 tmDataPoint; tmDataPoint.setName("Tm"); tmDataPoint.setLabel("Tm"); tmDataPoint.setDescription("UTC 24 hour time stamp to millisecond hhmmss.sssZ format"); tmDataPoint.setUnits("hhmmss.sssZ"); tmDataPoint.setSize(6); tmDataPoint.setAddressOffset(2); tmDataPoint.setBlockOffset(0); tmDataPoint.setSunSpecDataType("string"); tmDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(tmDataPoint.name(), tmDataPoint); SunSpecDataPoint dateDataPoint; dateDataPoint.setName("Date"); dateDataPoint.setLabel("Date"); dateDataPoint.setDescription("UTC Date string YYYYMMDD format"); dateDataPoint.setUnits("YYYYMMDD"); dateDataPoint.setSize(4); dateDataPoint.setAddressOffset(8); dateDataPoint.setBlockOffset(6); dateDataPoint.setSunSpecDataType("string"); dateDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(dateDataPoint.name(), dateDataPoint); SunSpecDataPoint locationDataPoint; locationDataPoint.setName("Loc"); locationDataPoint.setLabel("Location"); locationDataPoint.setDescription("Location string (40 chars max)"); locationDataPoint.setUnits("text"); locationDataPoint.setSize(20); locationDataPoint.setAddressOffset(12); locationDataPoint.setBlockOffset(10); locationDataPoint.setSunSpecDataType("string"); locationDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(locationDataPoint.name(), locationDataPoint); SunSpecDataPoint latDataPoint; latDataPoint.setName("Lat"); latDataPoint.setLabel("Lat"); latDataPoint.setDescription("Latitude with seven degrees of precision"); latDataPoint.setUnits("Degrees"); latDataPoint.setSize(2); latDataPoint.setAddressOffset(32); latDataPoint.setBlockOffset(30); latDataPoint.setScaleFactorName("-7"); latDataPoint.setSunSpecDataType("int32"); latDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(latDataPoint.name(), latDataPoint); SunSpecDataPoint longitudeDataPoint; longitudeDataPoint.setName("Long"); longitudeDataPoint.setLabel("Long"); longitudeDataPoint.setDescription("Longitude with seven degrees of precision"); longitudeDataPoint.setUnits("Degrees"); longitudeDataPoint.setSize(2); longitudeDataPoint.setAddressOffset(34); longitudeDataPoint.setBlockOffset(32); longitudeDataPoint.setScaleFactorName("-7"); longitudeDataPoint.setSunSpecDataType("int32"); longitudeDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(longitudeDataPoint.name(), longitudeDataPoint); SunSpecDataPoint altitudeDataPoint; altitudeDataPoint.setName("Alt"); altitudeDataPoint.setLabel("Altitude"); altitudeDataPoint.setDescription("Altitude measurement in meters"); altitudeDataPoint.setUnits("meters"); altitudeDataPoint.setSize(2); altitudeDataPoint.setAddressOffset(36); altitudeDataPoint.setBlockOffset(34); altitudeDataPoint.setSunSpecDataType("int32"); altitudeDataPoint.setByteOrder(m_byteOrder); m_dataPoints.insert(altitudeDataPoint.name(), altitudeDataPoint); } void SunSpecLocationModel::processBlockData() { // Update properties according to the data point type if (m_dataPoints.value("Tm").isValid()) m_tm = m_dataPoints.value("Tm").toString(); if (m_dataPoints.value("Date").isValid()) m_date = m_dataPoints.value("Date").toString(); if (m_dataPoints.value("Loc").isValid()) m_location = m_dataPoints.value("Loc").toString(); if (m_dataPoints.value("Lat").isValid()) m_lat = m_dataPoints.value("Lat").toFloatWithSSF(-7); if (m_dataPoints.value("Long").isValid()) m_longitude = m_dataPoints.value("Long").toFloatWithSSF(-7); if (m_dataPoints.value("Alt").isValid()) m_altitude = m_dataPoints.value("Alt").toInt32(); qCDebug(dcSunSpecModelData()) << this; } QDebug operator<<(QDebug debug, SunSpecLocationModel *model) { debug.nospace().noquote() << "SunSpecLocationModel(Model: " << model->modelId() << ", Register: " << model->modbusStartRegister() << ", Length: " << model->modelLength() << ")\n"; debug.nospace().noquote() << " - " << model->dataPoints().value("Tm") << "-->"; if (model->dataPoints().value("Tm").isValid()) { debug.nospace().noquote() << model->tm() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("Date") << "-->"; if (model->dataPoints().value("Date").isValid()) { debug.nospace().noquote() << model->date() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("Loc") << "-->"; if (model->dataPoints().value("Loc").isValid()) { debug.nospace().noquote() << model->location() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("Lat") << "-->"; if (model->dataPoints().value("Lat").isValid()) { debug.nospace().noquote() << model->lat() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("Long") << "-->"; if (model->dataPoints().value("Long").isValid()) { debug.nospace().noquote() << model->longitude() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } debug.nospace().noquote() << " - " << model->dataPoints().value("Alt") << "-->"; if (model->dataPoints().value("Alt").isValid()) { debug.nospace().noquote() << model->altitude() << "\n"; } else { debug.nospace().noquote() << "NaN\n"; } return debug.space().quote(); }