Added gwfwater. Require di.usesProcessContent() to setup for mftc specific decoding.

pull/799/head
Fredrik Öhrström 2023-01-10 20:52:14 +01:00
rodzic ab9e4b3c1d
commit e7d723f5c7
18 zmienionych plików z 167 dodań i 28 usunięć

Wyświetl plik

@ -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<Meter>(new Driver(mi, di)); });
});

Wyświetl plik

@ -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<Meter>(new Driver(mi, di)); });
});

Wyświetl plik

@ -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<Meter>(new Driver(mi, di)); });
});

Wyświetl plik

@ -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<Meter>(new Driver(mi, di)); });
});

Wyświetl plik

@ -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<Meter> createAuto(MeterInfo &mi)
di.setName("auto");
return shared_ptr<Meter>(new MeterAuto(mi, di));
}
void MeterAuto::processContent(Telegram *t)
{
}

Wyświetl plik

@ -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<Meter>(new Driver(mi, di)); });
});

Wyświetl plik

@ -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<Meter>(new Driver(mi, di)); });
});

Wyświetl plik

@ -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<Meter>(new Driver(mi, di)); });
});

Wyświetl plik

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

Wyświetl plik

@ -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<Meter>(new Driver(mi, di)); });
});

Wyświetl plik

@ -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<Meter>(new Driver(mi, di)); });
});

Wyświetl plik

@ -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<Meter>(new Driver(mi, di)); });
});

Wyświetl plik

@ -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<Meter>(new Driver(mi, di)); });
});

Wyświetl plik

@ -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<Meter> createUnknown(MeterInfo &mi)
di.setName("unknown");
return shared_ptr<Meter>(new MeterUnknown(mi, di));
}
void MeterUnknown::processContent(Telegram *t)
{
}

Wyświetl plik

@ -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<Meter>(new Driver(mi, di)); });
});

Wyświetl plik

@ -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, vector<ucha
// Invoke standardized field extractors!
processFieldExtractors(&t);
// Invoke tailor made meter specific parsing!
processContent(&t);
if (hasProcessContent())
{
// Invoke tailor made meter specific parsing!
processContent(&t);
}
// Invoke any calculators working on the extracted fields.
processFieldCalculators();
// All done....
@ -1225,6 +1231,11 @@ void MeterCommonImplementation::processContent(Telegram *t)
{
}
bool MeterCommonImplementation::hasProcessContent()
{
return has_process_content_;
}
void MeterCommonImplementation::setNumericValue(FieldInfo *fi, DVEntry *dve, Unit u, double v)
{
if (fi->hasSetNumericValueOverride())
@ -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(

Wyświetl plik

@ -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<void(DriverInfo&di)> setup);

Wyświetl plik

@ -63,6 +63,7 @@ struct MeterCommonImplementation : public virtual Meter
vector<string> &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: