Added qualcosonic driver.

pull/565/head
Fredrik Öhrström 2022-06-18 23:03:18 +02:00
rodzic 269176fe27
commit 960d5d67db
7 zmienionych plików z 259 dodań i 0 usunięć

Wyświetl plik

@ -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 This only affects new installations. Existing conf files will use the old location
as specified int the conf file. as specified int the conf file.
Added qualcosonic heating/cooling meter.
Added ei6500 smoke detector. Added ei6500 smoke detector.
Added kampress pressure sensor. Added kampress pressure sensor.
Added hydroclima HCA. Added hydroclima HCA.

Wyświetl plik

@ -472,6 +472,7 @@ Heat meter Diehl Sharky 775 (sharky)
Heat meter Diehl Sharky 774 (sharky774) Heat meter Diehl Sharky 774 (sharky774)
Heat meter Maddelena microClima (microclima) Heat meter Maddelena microClima (microclima)
Heat and Cooling meter BMeters Hydrocal-M3 (hydrocalm3) Heat and Cooling meter BMeters Hydrocal-M3 (hydrocalm3)
Heat and Cooling meter Axioma Qualcosonic E3 (qualcosonic)
Heat meter Qundis Q heat 5.5 (qheat) Heat meter Qundis Q heat 5.5 (qheat)
Supported room sensors: Supported room sensors:

Wyświetl plik

@ -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 <http://www.gnu.org/licenses/>.
*/
#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<Meter>(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

Wyświetl plik

@ -30,6 +30,7 @@
#define LIST_OF_VIF_RANGES \ #define LIST_OF_VIF_RANGES \
X(Volume,0x10,0x17,Quantity::Volume,Unit::M3) \ 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(OperatingTime,0x24,0x27, Quantity::Time, Unit::Second) \
X(VolumeFlow,0x38,0x3F, Quantity::Flow, Unit::M3H) \ X(VolumeFlow,0x38,0x3F, Quantity::Flow, Unit::M3H) \
X(FlowTemperature,0x58,0x5B, Quantity::Temperature, Unit::C) \ X(FlowTemperature,0x58,0x5B, Quantity::Temperature, Unit::C) \

Wyświetl plik

@ -2670,3 +2670,114 @@ bool Address::parse(string &s)
return true; 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)
);
}

Wyświetl plik

@ -39,6 +39,7 @@
X(GasMeter) \ X(GasMeter) \
X(HeatCostAllocationMeter) \ X(HeatCostAllocationMeter) \
X(HeatMeter) \ X(HeatMeter) \
X(HeatCoolingMeter) \
X(PulseCounter) \ X(PulseCounter) \
X(SmokeDetector) \ X(SmokeDetector) \
X(TempHygroMeter) \ X(TempHygroMeter) \

Wyświetl plik

@ -225,6 +225,9 @@ protected:
std::string getStringValue(FieldInfo *fi); std::string getStringValue(FieldInfo *fi);
std::string decodeTPLStatusByte(uchar sts); std::string decodeTPLStatusByte(uchar sts);
void addOptionalCommonFields();
void addOptionalFlowRelatedFields();
private: private:
int index_ {}; int index_ {};