From 5fd9d3a4f5b00f2b616236f0133d14580ac89a59 Mon Sep 17 00:00:00 2001 From: IzeQube Date: Sun, 26 Jul 2020 14:40:25 +0200 Subject: [PATCH] Added Techem Compact V heatmeter --- Makefile | 1 + README.md | 1 + src/meter_compact5.cc | 128 ++++++++++++++++++++++++++++++++++++++++++ src/meters.h | 2 + 4 files changed, 132 insertions(+) create mode 100644 src/meter_compact5.cc diff --git a/Makefile b/Makefile index 5ab28c0..b3002f8 100644 --- a/Makefile +++ b/Makefile @@ -115,6 +115,7 @@ METER_OBJS:=\ $(BUILD)/meter_apator08.o \ $(BUILD)/meter_apator162.o \ $(BUILD)/meter_cma12w.o \ + $(BUILD)/meter_compact5.o \ $(BUILD)/meter_ebzwmbe.o \ $(BUILD)/meter_ehzp.o \ $(BUILD)/meter_esyswm.o \ diff --git a/README.md b/README.md index b1fa450..4d5301e 100644 --- a/README.md +++ b/README.md @@ -220,6 +220,7 @@ Innotas EurisII (eurisii) Techem FHKV data II/III (fhkvdataiii) Supported heat meter: +Heat meter Techem Compact V (compact5) (non-standard protocol) Heat meter Techem Vario 4 (vario451) (non-standard protocol) Heat meter Kamstrup Multical 302 (multical302) (in C1 mode, please open issue for T1 mode) diff --git a/src/meter_compact5.cc b/src/meter_compact5.cc new file mode 100644 index 0000000..a23f80a --- /dev/null +++ b/src/meter_compact5.cc @@ -0,0 +1,128 @@ +/* + Copyright (C) 2019 Fredrik Öhrström + + 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"dvparser.h" +#include"meters.h" +#include"meters_common_implementation.h" +#include"wmbus.h" +#include"wmbus_utils.h" +#include"units.h" +#include"util.h" + +struct MeterCompact5 : public virtual HeatMeter, public virtual MeterCommonImplementation +{ + MeterCompact5(WMBus *bus, MeterInfo &mi); + + double totalEnergyConsumption(Unit u); + double currentPeriodEnergyConsumption(Unit u); + double previousPeriodEnergyConsumption(Unit u); + + private: + + void processContent(Telegram *t); + + double total_energy_kwh_ {}; + double curr_energy_kwh_ {}; + double prev_energy_kwh_ {}; +}; + +unique_ptr createCompact5(WMBus *bus, MeterInfo &mi) +{ + return unique_ptr(new MeterCompact5(bus, mi)); +} + +MeterCompact5::MeterCompact5(WMBus *bus, MeterInfo &mi) : + MeterCommonImplementation(bus, mi, MeterType::COMPACT5, MANUFACTURER_TCH) +{ + addMedia(0x04); // C telegrams + addMedia(0xC3); // T telegrams + + addLinkMode(LinkMode::C1); + addLinkMode(LinkMode::T1); + + addExpectedVersion(0x45); + + addPrint("total", Quantity::Energy, + [&](Unit u){ return totalEnergyConsumption(u); }, + "The total energy consumption recorded by this meter.", + true, true); + + addPrint("current", Quantity::Energy, + [&](Unit u){ return currentPeriodEnergyConsumption(u); }, + "Energy consumption so far in this billing period.", + true, true); + + addPrint("previous", Quantity::Energy, + [&](Unit u){ return previousPeriodEnergyConsumption(u); }, + "Energy consumption in previous billing period.", + true, true); +} + +double MeterCompact5::totalEnergyConsumption(Unit u) +{ + assertQuantity(u, Quantity::Energy); + return convert(total_energy_kwh_, Unit::KWH, u); +} + +double MeterCompact5::currentPeriodEnergyConsumption(Unit u) +{ + assertQuantity(u, Quantity::Energy); + return convert(curr_energy_kwh_, Unit::KWH, u); +} + +double MeterCompact5::previousPeriodEnergyConsumption(Unit u) +{ + assertQuantity(u, Quantity::Energy); + return convert(prev_energy_kwh_, Unit::KWH, u); +} + +void MeterCompact5::processContent(Telegram *t) +{ + // Unfortunately, the Techem Compact V is mostly a proprieatary protocol + // simple wrapped inside a wmbus telegram since the ci-field is 0xa2. + // Which means that the entire payload is manufacturer specific. + + map> vendor_values; + vector content; + + t->extractPayload(&content); + uchar prev_lo = content[3]; + uchar prev_hi = content[4]; + double prev = (256.0*prev_hi+prev_lo)/1000; + + string prevs; + strprintf(prevs, "%02x%02x", prev_lo, prev_hi); + int offset = t->parsed.size()+3; + vendor_values["0215"] = { offset, DVEntry(MeasurementType::Instantaneous, 0x15, 0, 0, 0, prevs) }; + t->explanations.push_back({ offset, prevs }); + t->addMoreExplanation(offset, " energy used in previous billing period (%f KWH)", prev); + + uchar curr_lo = content[7]; + uchar curr_hi = content[8]; + double curr = (256.0*curr_hi+curr_lo)/1000; + + string currs; + strprintf(currs, "%02x%02x", curr_lo, curr_hi); + offset = t->parsed.size()+7; + vendor_values["0215"] = { offset, DVEntry(MeasurementType::Instantaneous, 0x15, 0, 0, 0, currs) }; + t->explanations.push_back({ offset, currs }); + t->addMoreExplanation(offset, " energy used in current billing period (%f KWH)", curr); + + total_energy_kwh_ = prev+curr; + curr_energy_kwh_ = curr; + prev_energy_kwh_ = prev; +} diff --git a/src/meters.h b/src/meters.h index 162c546..0a6c466 100644 --- a/src/meters.h +++ b/src/meters.h @@ -30,6 +30,7 @@ X(apator08, T1_bit, Water, APATOR08, Apator08) \ X(apator162, C1_bit|T1_bit, Water, APATOR162, Apator162) \ X(cma12w, C1_bit|T1_bit, TempHygro, CMA12W, CMa12w) \ + X(compact5, T1_bit, Heat, COMPACT5, Compact5) \ X(ebzwmbe, T1_bit, Electricity, EBZWMBE, EBZWMBE) \ X(eurisii, T1_bit, HeatCostAllocation, EURISII, EurisII) \ X(ehzp, T1_bit, Electricity, EHZP, EHZP) \ @@ -225,6 +226,7 @@ unique_ptr createMultical21(WMBus *bus, MeterInfo &m); unique_ptr createFlowIQ3100(WMBus *bus, MeterInfo &m); unique_ptr createMultical302(WMBus *bus, MeterInfo &m); unique_ptr createVario451(WMBus *bus, MeterInfo &m); +unique_ptr createCompact5(WMBus *bus, MeterInfo &m); unique_ptr createWaterstarM(WMBus *bus, MeterInfo &m); unique_ptr createOmnipower(WMBus *bus, MeterInfo &m); unique_ptr createAmiplus(WMBus *bus, MeterInfo &m);