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
as specified int the conf file.
Added qualcosonic heating/cooling meter.
Added ei6500 smoke detector.
Added kampress pressure sensor.
Added hydroclima HCA.

Wyświetl plik

@ -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:

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 \
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) \

Wyświetl plik

@ -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)
);
}

Wyświetl plik

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

Wyświetl plik

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