From 960d5d67db6188363fca04a2543b84e46668cc47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20=C3=96hrstr=C3=B6m?= Date: Sat, 18 Jun 2022 23:03:18 +0200 Subject: [PATCH] Added qualcosonic driver. --- CHANGES | 1 + README.md | 1 + src/driver_qualcosonic.cc | 141 +++++++++++++++++++++++++++++ src/dvparser.h | 1 + src/meters.cc | 111 +++++++++++++++++++++++ src/meters.h | 1 + src/meters_common_implementation.h | 3 + 7 files changed, 259 insertions(+) create mode 100644 src/driver_qualcosonic.cc diff --git a/CHANGES b/CHANGES index 3048b0e..cc9c217 100644 --- a/CHANGES +++ b/CHANGES @@ -12,6 +12,7 @@ from /var/log/wmbusmeters/meter_readings to /var/lib/wmbusmeters/meter_readings This only affects new installations. Existing conf files will use the old location as specified int the conf file. +Added qualcosonic heating/cooling meter. Added ei6500 smoke detector. Added kampress pressure sensor. Added hydroclima HCA. diff --git a/README.md b/README.md index e325be0..a882395 100644 --- a/README.md +++ b/README.md @@ -472,6 +472,7 @@ Heat meter Diehl Sharky 775 (sharky) Heat meter Diehl Sharky 774 (sharky774) Heat meter Maddelena microClima (microclima) Heat and Cooling meter BMeters Hydrocal-M3 (hydrocalm3) +Heat and Cooling meter Axioma Qualcosonic E3 (qualcosonic) Heat meter Qundis Q heat 5.5 (qheat) Supported room sensors: diff --git a/src/driver_qualcosonic.cc b/src/driver_qualcosonic.cc new file mode 100644 index 0000000..f69ebbd --- /dev/null +++ b/src/driver_qualcosonic.cc @@ -0,0 +1,141 @@ +/* + Copyright (C) 2022 Fredrik Öhrström (gpl-3.0-or-later) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include"meters_common_implementation.h" + +namespace +{ + struct Driver : public virtual MeterCommonImplementation + { + Driver(MeterInfo &mi, DriverInfo &di); + }; + + static bool ok = registerDriver([](DriverInfo&di) + { + di.setName("qualcosonic"); + di.setMeterType(MeterType::HeatCoolingMeter); + di.addLinkMode(LinkMode::C1); + di.addDetection(MANUFACTURER_AXI, 0x0d, 0x0b); + di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr(new Driver(mi, di)); }); + }); + + Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di) + { + addOptionalCommonFields(); + addOptionalFlowRelatedFields(); + + addStringFieldWithExtractorAndLookup( + "status", + "Meter status. Includes both meter error field and tpl status field.", + PrintProperty::JSON | PrintProperty::FIELD | PrintProperty::IMPORTANT | + PrintProperty::STATUS | PrintProperty::JOIN_TPL_STATUS, + FieldMatcher::build() + .set(VIFRange::ErrorFlags), + Translate::Lookup( + { + { + { + "ERROR_FLAGS", + Translate::Type::BitToString, + 0xffffffff, + "OK", + { + /* What do these bits mean? There are a lot of them... + */ + } + }, + }, + })); + + addNumericFieldWithExtractor( + "total_heat_energy", + "The total heating energy consumption recorded by this meter.", + PrintProperty::FIELD | PrintProperty::JSON | PrintProperty::IMPORTANT, + Quantity::Energy, + VifScaling::Auto, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::AnyEnergyVIF) + .add(VIFCombinable::ForwardFlow) + ); + + addNumericFieldWithExtractor( + "total_cooling_energy", + "The total cooling energy consumption recorded by this meter.", + PrintProperty::FIELD | PrintProperty::JSON | PrintProperty::IMPORTANT, + Quantity::Energy, + VifScaling::Auto, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::AnyEnergyVIF) + .add(VIFCombinable::BackwardFlow) + ); + + addNumericFieldWithExtractor( + "power", + "The current power consumption.", + PrintProperty::JSON | PrintProperty::FIELD, + Quantity::Power, + VifScaling::AutoSigned, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::AnyPowerVIF) + ); + + addStringFieldWithExtractor( + "target_datetime", + "Date and time when the previous billing period ended.", + PrintProperty::FIELD | PrintProperty::JSON, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::DateTime) + .set(StorageNr(16)) + ); + + addNumericFieldWithExtractor( + "target_heat_energy", + "The heating energy consumption recorded at the end of the previous billing period.", + PrintProperty::FIELD | PrintProperty::JSON, + Quantity::Energy, + VifScaling::Auto, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::AnyEnergyVIF) + .add(VIFCombinable::ForwardFlow) + .set(StorageNr(16)) + ); + + addNumericFieldWithExtractor( + "target_cooling_energy", + "The cooling energy consumption recorded at the end of the previous billing period.", + PrintProperty::FIELD | PrintProperty::JSON, + Quantity::Energy, + VifScaling::Auto, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::AnyEnergyVIF) + .add(VIFCombinable::BackwardFlow) + .set(StorageNr(16)) + ); + + } +} + +// Test: qualco qualcosonic 03016408 NOKEY +// telegram=|76440907086401030B0d7a78000000046d030fB726346d0000010134fd170000000004200f13cf0104240f13cf0104863B0000000004863cdc0000000413B5150600042B86f1ffff043B030200000259c002025d2c05026194fd0c780864010384086d3B17Bf258408863B000000008408863c0B000000| +// {"media":"heat/cooling load","meter":"qualcosonic","name":"qualco","id":"03016408","fabrication_no":"03016408","operating_time_h":2.34167,"on_time_h":2.34167,"meter_datetime":"2021-06-23 15:03","meter_error_datetime":"2000-01-01 00:00","total_m3":398.773,"flow_temperature_c":7.04,"return_temperature_c":13.24,"flow_return_temperature_difference_c":-6.2,"volume_flow_m3h":0.515,"status":"OK","total_heat_energy_kwh":0,"total_cooling_energy_kwh":220,"power_kw":-3.706,"target_datetime":"2021-05-31 23:59","target_heat_energy_kwh":0,"target_cooling_energy_kwh":11,"timestamp":"1111-11-11T11:11:11Z"} +// |qualco;03016408;OK;0.000000;220.000000;-3.706000;2021-05-31 23:59;0.000000;11.000000;1111-11-11 11:11.11 diff --git a/src/dvparser.h b/src/dvparser.h index 065c3f9..44540fa 100644 --- a/src/dvparser.h +++ b/src/dvparser.h @@ -30,6 +30,7 @@ #define LIST_OF_VIF_RANGES \ X(Volume,0x10,0x17,Quantity::Volume,Unit::M3) \ + X(OnTime,0x20,0x23, Quantity::Time, Unit::Second) \ X(OperatingTime,0x24,0x27, Quantity::Time, Unit::Second) \ X(VolumeFlow,0x38,0x3F, Quantity::Flow, Unit::M3H) \ X(FlowTemperature,0x58,0x5B, Quantity::Temperature, Unit::C) \ diff --git a/src/meters.cc b/src/meters.cc index 4704e05..3fbbb2f 100644 --- a/src/meters.cc +++ b/src/meters.cc @@ -2670,3 +2670,114 @@ bool Address::parse(string &s) return true; } + +void MeterCommonImplementation::addOptionalCommonFields() +{ + addStringFieldWithExtractor( + "fabrication_no", + "Fabrication number.", + PrintProperty::JSON | PrintProperty::OPTIONAL, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::FabricationNo) + ); + + addNumericFieldWithExtractor( + "operating_time", + "How long the meter has been collecting data.", + PrintProperty::JSON | PrintProperty::OPTIONAL, + Quantity::Time, + VifScaling::Auto, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::OperatingTime) + ); + + addNumericFieldWithExtractor( + "on_time", + "How long the meter has been powered up.", + PrintProperty::JSON | PrintProperty::OPTIONAL, + Quantity::Time, + VifScaling::Auto, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::OnTime) + ); + + addStringFieldWithExtractor( + "meter_datetime", + "Date and time when the meter sent the telegram.", + PrintProperty::JSON | PrintProperty::OPTIONAL, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::DateTime) + ); + + addStringFieldWithExtractor( + "meter_error_datetime", + "Date and time when the meter was in error.", + PrintProperty::JSON | PrintProperty::OPTIONAL, + FieldMatcher::build() + .set(MeasurementType::AtError) + .set(VIFRange::DateTime) + ); + +} + +void MeterCommonImplementation::addOptionalFlowRelatedFields() +{ + addNumericFieldWithExtractor( + "total", + "The total heating/cooling media volume consumption recorded by this meter.", + PrintProperty::JSON | PrintProperty::OPTIONAL, + Quantity::Volume, + VifScaling::Auto, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::Volume) + ); + + addNumericFieldWithExtractor( + "flow_temperature", + "Forward heat/cooling media temperature.", + PrintProperty::JSON | PrintProperty::OPTIONAL, + Quantity::Temperature, + VifScaling::Auto, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::FlowTemperature) + ); + + addNumericFieldWithExtractor( + "return_temperature", + "Return heat/cooling media temperature.", + PrintProperty::JSON | PrintProperty::OPTIONAL, + Quantity::Temperature, + VifScaling::Auto, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::ReturnTemperature) + ); + + addNumericFieldWithExtractor( + "flow_return_temperature_difference", + "The difference between flow and return media temperatures.", + PrintProperty::JSON | PrintProperty::OPTIONAL, + Quantity::Temperature, + VifScaling::AutoSigned, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::TemperatureDifference) + ); + + addNumericFieldWithExtractor( + "volume_flow", + "Media volume flow.", + PrintProperty::JSON | PrintProperty::OPTIONAL, + Quantity::Flow, + VifScaling::Auto, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::VolumeFlow) + ); + } diff --git a/src/meters.h b/src/meters.h index 044575d..820ca3e 100644 --- a/src/meters.h +++ b/src/meters.h @@ -39,6 +39,7 @@ X(GasMeter) \ X(HeatCostAllocationMeter) \ X(HeatMeter) \ + X(HeatCoolingMeter) \ X(PulseCounter) \ X(SmokeDetector) \ X(TempHygroMeter) \ diff --git a/src/meters_common_implementation.h b/src/meters_common_implementation.h index 1df469f..cb8edcc 100644 --- a/src/meters_common_implementation.h +++ b/src/meters_common_implementation.h @@ -225,6 +225,9 @@ protected: std::string getStringValue(FieldInfo *fi); std::string decodeTPLStatusByte(uchar sts); + void addOptionalCommonFields(); + void addOptionalFlowRelatedFields(); + private: int index_ {};