From e7d723f5c7c9db0f0c74ea8ccc87764611b7bbf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20=C3=96hrstr=C3=B6m?= Date: Tue, 10 Jan 2023 20:52:14 +0100 Subject: [PATCH] Added gwfwater. Require di.usesProcessContent() to setup for mftc specific decoding. --- src/driver_apator08.cc | 1 + src/driver_apator162.cc | 1 + src/driver_apator172.cc | 1 + src/driver_apatoreitn.cc | 1 + src/driver_auto.cc | 6 -- src/driver_bfw240radio.cc | 1 + src/driver_compact5.cc | 2 +- src/driver_fhkvdataiii.cc | 2 +- src/driver_gwfwater.cc | 104 +++++++++++++++++++++++++++++ src/driver_mkradio3.cc | 2 +- src/driver_mkradio4.cc | 2 +- src/driver_rfmtx1.cc | 1 + src/driver_tsd2.cc | 2 +- src/driver_unknown.cc | 6 -- src/driver_vario451.cc | 1 + src/meters.cc | 53 +++++++++++++-- src/meters.h | 2 +- src/meters_common_implementation.h | 7 +- 18 files changed, 167 insertions(+), 28 deletions(-) create mode 100644 src/driver_gwfwater.cc diff --git a/src/driver_apator08.cc b/src/driver_apator08.cc index 3a84834..6b06473 100644 --- a/src/driver_apator08.cc +++ b/src/driver_apator08.cc @@ -35,6 +35,7 @@ namespace di.setMeterType(MeterType::WaterMeter); di.addLinkMode(LinkMode::T1); di.addDetection(0x8614/*APT?*/, 0x03, 0x03); + di.usesProcessContent(); di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr(new Driver(mi, di)); }); }); diff --git a/src/driver_apator162.cc b/src/driver_apator162.cc index f16e861..c6714af 100644 --- a/src/driver_apator162.cc +++ b/src/driver_apator162.cc @@ -38,6 +38,7 @@ namespace di.addDetection(MANUFACTURER_APA, 0x06, 0x05); di.addDetection(MANUFACTURER_APA, 0x07, 0x05); di.addDetection(0x8614 /*APT?*/, 0x07, 0x05); // Older version of telegram that is not understood! + di.usesProcessContent(); di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr(new Driver(mi, di)); }); }); diff --git a/src/driver_apator172.cc b/src/driver_apator172.cc index 5485c7f..8ef232f 100644 --- a/src/driver_apator172.cc +++ b/src/driver_apator172.cc @@ -34,6 +34,7 @@ namespace di.setDefaultFields("name,id,total_m3,timestamp"); di.setMeterType(MeterType::WaterMeter); di.addDetection(0x8614 /*APT?*/, 0x11, 0x04); + di.usesProcessContent(); di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr(new Driver(mi, di)); }); }); diff --git a/src/driver_apatoreitn.cc b/src/driver_apatoreitn.cc index a338cb0..e90cbe8 100644 --- a/src/driver_apatoreitn.cc +++ b/src/driver_apatoreitn.cc @@ -38,6 +38,7 @@ namespace di.setMeterType(MeterType::HeatCostAllocationMeter); di.addDetection(0x8614 /* APT? */, 0x08, 0x04); di.addDetection(0x8601 /* APA? */, 0x08, 0x04); + di.usesProcessContent(); di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr(new Driver(mi, di)); }); }); diff --git a/src/driver_auto.cc b/src/driver_auto.cc index 6d15c9e..0892c95 100644 --- a/src/driver_auto.cc +++ b/src/driver_auto.cc @@ -22,8 +22,6 @@ using namespace std; struct MeterAuto : public virtual MeterCommonImplementation { MeterAuto(MeterInfo &mi, DriverInfo &di); - - void processContent(Telegram *t); }; bool ok = registerDriver([](DriverInfo&di) @@ -44,7 +42,3 @@ shared_ptr createAuto(MeterInfo &mi) di.setName("auto"); return shared_ptr(new MeterAuto(mi, di)); } - -void MeterAuto::processContent(Telegram *t) -{ -} diff --git a/src/driver_bfw240radio.cc b/src/driver_bfw240radio.cc index d413acb..df0376d 100644 --- a/src/driver_bfw240radio.cc +++ b/src/driver_bfw240radio.cc @@ -34,6 +34,7 @@ namespace di.setMeterType(MeterType::HeatCostAllocationMeter); di.addDetection(MANUFACTURER_BFW,0x08, 0x02); di.forceMfctIndex(2); // First two bytes are 2f2f after that its completely mfct specific. + di.usesProcessContent(); di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr(new Driver(mi, di)); }); }); diff --git a/src/driver_compact5.cc b/src/driver_compact5.cc index 19f9318..9c1b553 100644 --- a/src/driver_compact5.cc +++ b/src/driver_compact5.cc @@ -38,7 +38,7 @@ namespace di.addDetection(MANUFACTURER_TCH, 0x43, 0x22); di.addDetection(MANUFACTURER_TCH, 0x43, 0x45); di.addDetection(MANUFACTURER_TCH, 0x43, 0x39); - + di.usesProcessContent(); di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr(new Driver(mi, di)); }); }); diff --git a/src/driver_fhkvdataiii.cc b/src/driver_fhkvdataiii.cc index 83fc116..c669f69 100644 --- a/src/driver_fhkvdataiii.cc +++ b/src/driver_fhkvdataiii.cc @@ -37,7 +37,7 @@ namespace di.addLinkMode(LinkMode::T1); di.addDetection(MANUFACTURER_TCH, 0x80, 0x69); di.addDetection(MANUFACTURER_TCH, 0x80, 0x94); - + di.usesProcessContent(); di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr(new Driver(mi, di)); }); }); diff --git a/src/driver_gwfwater.cc b/src/driver_gwfwater.cc new file mode 100644 index 0000000..f13eb20 --- /dev/null +++ b/src/driver_gwfwater.cc @@ -0,0 +1,104 @@ +/* + Copyright (C) 2023 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); + + void processContent(Telegram *t); + }; + + static bool ok = registerDriver([](DriverInfo&di) + { + di.setName("gwfwater"); + di.setDefaultFields("name,id,total_m3,timestamp"); + di.setMeterType(MeterType::WaterMeter); + di.addDetection(MANUFACTURER_GWF, 0x0e, 0x01); + di.usesProcessContent(); + di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr(new Driver(mi, di)); }); + }); + + Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di) + { + addOptionalCommonFields("actuality_duration_s"); + addOptionalFlowRelatedFields("total_m3,target_m3,target_date"); + + addStringField( + "status", + "Meter status.", + PrintProperty::INCLUDE_TPL_STATUS | PrintProperty::STATUS); + + addStringField( + "mfct_status", + "Mfct status bit.", + PrintProperty::INJECT_INTO_STATUS | PrintProperty::HIDE); + + addStringField( + "power_mode", + "Normal or saving.", + DEFAULT_PRINT_PROPERTIES); + + addNumericField( + "battery", + Quantity::Time, + DEFAULT_PRINT_PROPERTIES, + "Remaining battery life in years.", + Unit::Year); + } + + void Driver::processContent(Telegram *t) + { + vector bytes; + t->extractMfctData(&bytes); // Extract raw frame data after the DIF 0x0F. + + if (bytes.size() < 3) return; + + uchar type = bytes[0]; + uchar a = bytes[1]; + uchar b = bytes[2]; + + if (type != 1) + { + setStringValue("mfct_status", tostrprintf("UKNOWN_MFCT_STATUS=%02x%02x%02x", type, a, b)); + return; + } + + string info; + + if (a & 0x02) info += "CONTINUOUS_FLOW "; + if (a & 0x08) info += "BROKEN_PIPE "; + if (a & 0x20) info += "BATTERY_LOW "; + if (a & 0x40) info += "BACKFLOW "; + + if (info.size() > 0) info.pop_back(); + setStringValue("mfct_status", info); + + setStringValue("power_mode", (b & 0x01) ? "SAVING" : "NORMAL"); + + double battery_semesters = (b >> 3); // Half years. + setNumericValue("battery", Unit::Year, battery_semesters/2.0); + } +} + +// Test: Wateroo gwfwater 20221031 NOKEY +// telegram=|3144E61E31102220010E8C04F47ABE0420452F2F_037410000004133E0000004413FFFFFFFF426CFFFF0F0120012F2F2F2F2F| +// {"actuality_duration_s": 16,"battery_y": 0,"id": "20221031","media": "bus/system component","meter": "gwfwater","name": "Wateroo","power_mode": "SAVING","status": "BATTERY_LOW POWER_LOW","target_datetime": "2128-03-31 00:00","target_m3": 4294967.295,"timestamp": "1111-11-11T11:11:11Z","total_m3": 0.062} +// |Wateroo;20221031;0.062;1111-11-11 11:11.11 diff --git a/src/driver_mkradio3.cc b/src/driver_mkradio3.cc index 5387fcb..78a5618 100644 --- a/src/driver_mkradio3.cc +++ b/src/driver_mkradio3.cc @@ -34,7 +34,7 @@ namespace di.addLinkMode(LinkMode::T1); di.addDetection(MANUFACTURER_TCH, 0x62, 0x74); di.addDetection(MANUFACTURER_TCH, 0x72, 0x74); - + di.usesProcessContent(); di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr(new Driver(mi, di)); }); }); diff --git a/src/driver_mkradio4.cc b/src/driver_mkradio4.cc index 7d8f158..6781bfb 100644 --- a/src/driver_mkradio4.cc +++ b/src/driver_mkradio4.cc @@ -36,7 +36,7 @@ namespace di.addDetection(MANUFACTURER_TCH, 0x62, 0x70); di.addDetection(MANUFACTURER_TCH, 0x72, 0x95); di.addDetection(MANUFACTURER_TCH, 0x72, 0x70); - + di.usesProcessContent(); di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr(new Driver(mi, di)); }); }); diff --git a/src/driver_rfmtx1.cc b/src/driver_rfmtx1.cc index 8deb507..da164d5 100644 --- a/src/driver_rfmtx1.cc +++ b/src/driver_rfmtx1.cc @@ -32,6 +32,7 @@ namespace di.setMeterType(MeterType::WaterMeter); di.addLinkMode(LinkMode::T1); di.addDetection(MANUFACTURER_BMT, 0x07, 0x05); + di.usesProcessContent(); di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr(new Driver(mi, di)); }); }); diff --git a/src/driver_tsd2.cc b/src/driver_tsd2.cc index 9354e14..62beeba 100644 --- a/src/driver_tsd2.cc +++ b/src/driver_tsd2.cc @@ -33,7 +33,7 @@ namespace di.setMeterType(MeterType::SmokeDetector); di.addLinkMode(LinkMode::T1); di.addDetection(MANUFACTURER_TCH, 0xf0, 0x76); - + di.usesProcessContent(); di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr(new Driver(mi, di)); }); }); diff --git a/src/driver_unknown.cc b/src/driver_unknown.cc index cb62780..ea27bea 100644 --- a/src/driver_unknown.cc +++ b/src/driver_unknown.cc @@ -22,8 +22,6 @@ using namespace std; struct MeterUnknown : public virtual MeterCommonImplementation { MeterUnknown(MeterInfo &mi, DriverInfo &di); - - void processContent(Telegram *t); }; static bool ok = registerDriver([](DriverInfo&di) @@ -44,7 +42,3 @@ shared_ptr createUnknown(MeterInfo &mi) di.setName("unknown"); return shared_ptr(new MeterUnknown(mi, di)); } - -void MeterUnknown::processContent(Telegram *t) -{ -} diff --git a/src/driver_vario451.cc b/src/driver_vario451.cc index cee554f..2e7b601 100644 --- a/src/driver_vario451.cc +++ b/src/driver_vario451.cc @@ -35,6 +35,7 @@ namespace di.addLinkMode(LinkMode::T1); di.addDetection(MANUFACTURER_TCH, 0x04, 0x27); di.addDetection(MANUFACTURER_TCH, 0xc3, 0x27); + di.usesProcessContent(); di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr(new Driver(mi, di)); }); }); diff --git a/src/meters.cc b/src/meters.cc index 7d32df9..096ca81 100644 --- a/src/meters.cc +++ b/src/meters.cc @@ -162,11 +162,13 @@ bool lookupDriverInfo(const string& driver, DriverInfo *out_di) return true; } - - +/* MeterCommonImplementation::MeterCommonImplementation(MeterInfo &mi, string driver) : - driver_name_(driver), bus_(mi.bus), name_(mi.name), waiting_for_poll_response_sem_("waiting_for_poll_response") + driver_name_(driver), + bus_(mi.bus), + name_(mi.name), + waiting_for_poll_response_sem_("waiting_for_poll_response") { ids_ = mi.ids; idsc_ = toIdsCommaSeparated(ids_); @@ -185,7 +187,7 @@ MeterCommonImplementation::MeterCommonImplementation(MeterInfo &mi, addExtraConstantField(j); } } - +*/ MeterCommonImplementation::MeterCommonImplementation(MeterInfo &mi, DriverInfo &di) : type_(di.type()), @@ -193,6 +195,7 @@ MeterCommonImplementation::MeterCommonImplementation(MeterInfo &mi, bus_(mi.bus), name_(mi.name), mfct_tpl_status_bits_(di.mfctTPLStatusBits()), + has_process_content_(di.hasProcessContent()), waiting_for_poll_response_sem_("waiting_for_poll_response") { ids_ = mi.ids; @@ -1082,8 +1085,11 @@ bool MeterCommonImplementation::handleTelegram(AboutTelegram &about, vectorhasSetNumericValueOverride()) @@ -2676,6 +2687,36 @@ void MeterCommonImplementation::addOptionalFlowRelatedFields(string field_names) ); } + if (checkIf(fields,"target_m3")) + { + addNumericFieldWithExtractor( + "target", + "The volume recorded by this meter at the target date.", + DEFAULT_PRINT_PROPERTIES, + Quantity::Volume, + VifScaling::Auto, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::Volume) + .set(StorageNr(1)) + ); + } + + if (checkIf(fields,"target_date")) + { + addNumericFieldWithExtractor( + "target", + "The target date. Usually the end of the previous billing period.", + DEFAULT_PRINT_PROPERTIES, + Quantity::PointInTime, + VifScaling::Auto, + FieldMatcher::build() + .set(MeasurementType::Instantaneous) + .set(VIFRange::Date) + .set(StorageNr(1)) + ); + } + if (checkIf(fields,"total_forward_m3")) { addNumericFieldWithExtractor( diff --git a/src/meters.h b/src/meters.h index 3c9ce63..ff81717 100644 --- a/src/meters.h +++ b/src/meters.h @@ -215,7 +215,7 @@ public: bool isValidMedia(uchar type); bool isCloseEnoughMedia(uchar type); int forceMfctIndex() { return force_mfct_index_; } - bool hasProcessContentCode() { return has_process_content_; } + bool hasProcessContent() { return has_process_content_; } }; bool registerDriver(function setup); diff --git a/src/meters_common_implementation.h b/src/meters_common_implementation.h index 8da8410..77221f3 100644 --- a/src/meters_common_implementation.h +++ b/src/meters_common_implementation.h @@ -63,6 +63,7 @@ struct MeterCommonImplementation : public virtual Meter vector &extraConstantFields(); string name(); DriverName driverName(); + bool hasProcessContent(); ELLSecurityMode expectedELLSecurityMode(); TPLSecurityMode expectedTPLSecurityMode(); @@ -82,7 +83,7 @@ struct MeterCommonImplementation : public virtual Meter static bool isTelegramForMeter(Telegram *t, Meter *meter, MeterInfo *mi); MeterKeys *meterKeys(); - MeterCommonImplementation(MeterInfo &mi, string driver); +// MeterCommonImplementation(MeterInfo &mi, string driver); MeterCommonImplementation(MeterInfo &mi, DriverInfo &di); ~MeterCommonImplementation() = default; @@ -134,9 +135,6 @@ protected: string help, Unit display_unit = Unit::Unknown); // If specified use this unit for the json field instead instead of the default unit. -#define SET_STRING_FUNC(varname) {[=](string s){varname = s;}} -#define GET_STRING_FUNC(varname) {[=](){return varname; }} - void addStringFieldWithExtractor( string vname, string help, @@ -228,6 +226,7 @@ private: time_t poll_interval_ {}; Translate::Lookup mfct_tpl_status_bits_ = NoLookup; int force_mfct_index_ = -1; + bool has_process_content_ = false; protected: