kopia lustrzana https://github.com/weetmuts/wmbusmeters
Added ehzp electricity meter.
rodzic
d81a573c6c
commit
e944f3c13f
2
Makefile
2
Makefile
|
@ -84,7 +84,7 @@ $(info Building $(VERSION))
|
|||
CXXFLAGS := $(DEBUG_FLAGS) -fPIC -fmessage-length=0 -std=c++11 -Wall -Wno-unused-function -I$(BUILD)
|
||||
|
||||
$(BUILD)/%.o: src/%.cc $(wildcard src/%.h)
|
||||
@#$(CXX) $(CXXFLAGS) $< -c -E > $@.src
|
||||
$(CXX) $(CXXFLAGS) $< -c -E > $@.src
|
||||
$(CXX) $(CXXFLAGS) $< -MMD -c -o $@
|
||||
|
||||
METER_OBJS:=\
|
||||
|
|
|
@ -211,6 +211,7 @@ Elvaco CMa12w Thermometer (cma12w)
|
|||
|
||||
Supported electricity meters:
|
||||
Tauron Amiplus (amiplus) (includes vendor apator and echelon)
|
||||
EMH Metering (ehzp)
|
||||
|
||||
Work in progress:
|
||||
Electricity meter Kamstrup Omnipower (omnipower)
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
const char *ValueInformationName(ValueInformation v)
|
||||
const char *toString(ValueInformation v)
|
||||
{
|
||||
switch (v) {
|
||||
#define X(name,from,to) case ValueInformation::name: return #name;
|
||||
|
@ -39,6 +39,16 @@ LIST_OF_VALUETYPES
|
|||
assert(0);
|
||||
}
|
||||
|
||||
ValueInformation toValueInformation(int i)
|
||||
{
|
||||
switch (i) {
|
||||
#define X(name,from,to) if (from >= i && i <= to) return ValueInformation::name;
|
||||
LIST_OF_VALUETYPES
|
||||
#undef X
|
||||
}
|
||||
return ValueInformation::None;
|
||||
}
|
||||
|
||||
map<uint16_t,string> hash_to_format_;
|
||||
|
||||
bool loadFormatBytesFromSignature(uint16_t format_signature, vector<uchar> *format_bytes)
|
||||
|
@ -279,10 +289,11 @@ bool parseDV(Telegram *t,
|
|||
void valueInfoRange(ValueInformation v, int *low, int *hi)
|
||||
{
|
||||
switch (v) {
|
||||
#define X(name,from,to) case ValueInformation::name: *low = from; *hi = to; break;
|
||||
#define X(name,from,to) case ValueInformation::name: *low = from; *hi = to; return;
|
||||
LIST_OF_VALUETYPES
|
||||
#undef X
|
||||
}
|
||||
assert(0);
|
||||
}
|
||||
|
||||
bool hasKey(std::map<std::string,std::pair<int,DVEntry>> *values, std::string key)
|
||||
|
@ -290,29 +301,33 @@ bool hasKey(std::map<std::string,std::pair<int,DVEntry>> *values, std::string ke
|
|||
return values->count(key) > 0;
|
||||
}
|
||||
|
||||
bool findKey(MeasurementType mit, ValueInformation vif, int storagenr, std::string *key, std::map<std::string,std::pair<int,DVEntry>> *values)
|
||||
bool findKey(MeasurementType mit, ValueInformation vif, int storagenr,
|
||||
std::string *key, std::map<std::string,std::pair<int,DVEntry>> *values)
|
||||
{
|
||||
int low, hi;
|
||||
valueInfoRange(vif, &low, &hi);
|
||||
|
||||
/* debug("(dvparser) looking for type=%s vif=%s storagenr=%d\n",
|
||||
measurementTypeName(mit).c_str(), ValueInformationName(vif), storagenr);*/
|
||||
debug("(dvparser) looking for type=%s vif=%s storagenr=%d value_ran_low=%02x value_ran_hi=%02x\n",
|
||||
measurementTypeName(mit).c_str(), toString(vif), storagenr,
|
||||
low, hi);
|
||||
|
||||
for (auto& v : *values)
|
||||
{
|
||||
MeasurementType ty = v.second.second.type;
|
||||
int vi = v.second.second.value_information;
|
||||
int sn = v.second.second.storagenr;
|
||||
/* debug("(dvparser) match? type=%s vif=%s and storagenr=%d\n",
|
||||
measurementTypeName(ty).c_str(), ValueInformationName(vif), storagenr, sn); */
|
||||
debug("(dvparser) match? %s type=%s vif=%02x (%s) and storagenr=%d\n",
|
||||
v.first.c_str(),
|
||||
measurementTypeName(ty).c_str(), vi, toString(toValueInformation(vi)), storagenr, sn);
|
||||
|
||||
if (vi >= low && vi <= hi
|
||||
&& (mit == MeasurementType::Unknown || mit == ty)
|
||||
&& (storagenr == ANY_STORAGENR || storagenr == sn))
|
||||
{
|
||||
*key = v.first;
|
||||
/*debug("(dvparser) found key %s for type=%s vif=%s storagenr=%d\n",
|
||||
v.first.c_str(), measurementTypeName(ty).c_str(), ValueInformationName(vif), storagenr);*/
|
||||
debug("(dvparser) found key %s for type=%s vif=%02x (%s) storagenr=%d\n",
|
||||
v.first.c_str(), measurementTypeName(ty).c_str(),
|
||||
vi, toString(toValueInformation(vi)), storagenr);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -437,6 +452,24 @@ bool extractDVdouble(map<string,pair<int,DVEntry>> *values,
|
|||
+ ((unsigned int)v[2])*256*256
|
||||
+ ((unsigned int)v[1])*256
|
||||
+ ((unsigned int)v[0]);
|
||||
} else if (t == 0x6) {
|
||||
assert(v.size() == 6);
|
||||
raw = ((uint64_t)v[5])*256*256*256*256*256
|
||||
+ ((uint64_t)v[4])*256*256*256*256
|
||||
+ ((uint64_t)v[3])*256*256*256
|
||||
+ ((uint64_t)v[2])*256*256
|
||||
+ ((uint64_t)v[1])*256
|
||||
+ ((uint64_t)v[0]);
|
||||
} else if (t == 0x7) {
|
||||
assert(v.size() == 8);
|
||||
raw = ((uint64_t)v[7])*256*256*256*256*256*256*256
|
||||
+ ((uint64_t)v[6])*256*256*256*256*256*256
|
||||
+ ((uint64_t)v[5])*256*256*256*256*256
|
||||
+ ((uint64_t)v[4])*256*256*256*256
|
||||
+ ((uint64_t)v[3])*256*256*256
|
||||
+ ((uint64_t)v[2])*256*256
|
||||
+ ((uint64_t)v[1])*256
|
||||
+ ((uint64_t)v[0]);
|
||||
}
|
||||
double scale = 1.0;
|
||||
if (auto_scale) scale = vifScale(vif);
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include<vector>
|
||||
|
||||
#define LIST_OF_VALUETYPES \
|
||||
X(None,-1,-1) \
|
||||
X(Volume,0x10,0x17) \
|
||||
X(VolumeFlow,0x38,0x3F) \
|
||||
X(FlowTemperature,0x58,0x5B) \
|
||||
|
@ -35,7 +36,7 @@
|
|||
X(HeatCostAllocation,0x6E,0x6E) \
|
||||
X(Date,0x6C,0x6C) \
|
||||
X(DateTime,0x6D,0x6D) \
|
||||
X(EnergyWh,0x03,0x07) \
|
||||
X(EnergyWh,0x00,0x07) \
|
||||
X(PowerW,0x28,0x2f) \
|
||||
|
||||
enum class ValueInformation
|
||||
|
@ -45,7 +46,8 @@ LIST_OF_VALUETYPES
|
|||
#undef X
|
||||
};
|
||||
|
||||
const char *ValueInformatioName(ValueInformation v);
|
||||
const char *toString(ValueInformation v);
|
||||
ValueInformation toValueInformation(int i);
|
||||
|
||||
bool loadFormatBytesFromSignature(uint16_t format_signature, vector<uchar> *format_bytes);
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ private:
|
|||
double current_power_kw_ {};
|
||||
double total_energy_returned_kwh_ {};
|
||||
double current_power_returned_kw_ {};
|
||||
string device_date_time_;
|
||||
double on_time_h_ {};
|
||||
};
|
||||
|
||||
MeterEHZP::MeterEHZP(WMBus *bus, MeterInfo &mi) :
|
||||
|
@ -75,15 +75,11 @@ MeterEHZP::MeterEHZP(WMBus *bus, MeterInfo &mi) :
|
|||
"The total energy production recorded by this meter.",
|
||||
true, true);
|
||||
|
||||
addPrint("current_power_production", Quantity::Power,
|
||||
[&](Unit u){ return currentPowerProduction(u); },
|
||||
"Current power production.",
|
||||
addPrint("on_time", Quantity::Time,
|
||||
[&](Unit u){ assertQuantity(u, Quantity::Time);
|
||||
return convert(on_time_h_, Unit::Hour, u); },
|
||||
"Device on time.",
|
||||
true, true);
|
||||
|
||||
addPrint("device_date_time", Quantity::Text,
|
||||
[&](){ return device_date_time_; },
|
||||
"Device date time.",
|
||||
false, true);
|
||||
}
|
||||
|
||||
unique_ptr<ElectricityMeter> createEHZP(WMBus *bus, MeterInfo &mi)
|
||||
|
@ -120,26 +116,22 @@ void MeterEHZP::processContent(Telegram *t)
|
|||
int offset;
|
||||
string key;
|
||||
|
||||
if (findKey(MeasurementType::Unknown, ValueInformation::EnergyWh, 0, &key, &t->values)) {
|
||||
if (findKey(MeasurementType::Unknown, ValueInformation::EnergyWh, 0, &key, &t->values))
|
||||
{
|
||||
extractDVdouble(&t->values, key, &offset, &total_energy_kwh_);
|
||||
t->addMoreExplanation(offset, " total energy (%f kwh)", total_energy_kwh_);
|
||||
}
|
||||
|
||||
if (findKey(MeasurementType::Unknown, ValueInformation::PowerW, 0, &key, &t->values)) {
|
||||
if (findKey(MeasurementType::Unknown, ValueInformation::PowerW, 0, &key, &t->values))
|
||||
{
|
||||
extractDVdouble(&t->values, key, &offset, ¤t_power_kw_);
|
||||
t->addMoreExplanation(offset, " current power (%f kw)", current_power_kw_);
|
||||
}
|
||||
|
||||
extractDVdouble(&t->values, "0E833C", &offset, &total_energy_returned_kwh_);
|
||||
extractDVdouble(&t->values, "07803C", &offset, &total_energy_returned_kwh_);
|
||||
t->addMoreExplanation(offset, " total energy returned (%f kwh)", total_energy_returned_kwh_);
|
||||
|
||||
extractDVdouble(&t->values, "0BAB3C", &offset, ¤t_power_returned_kw_);
|
||||
t->addMoreExplanation(offset, " current power returned (%f kw)", current_power_returned_kw_);
|
||||
extractDVdouble(&t->values, "0420", &offset, &on_time_h_);
|
||||
t->addMoreExplanation(offset, " on time (%f h)", on_time_h_);
|
||||
|
||||
if (findKey(MeasurementType::Unknown, ValueInformation::DateTime, 0, &key, &t->values)) {
|
||||
struct tm datetime;
|
||||
extractDVdate(&t->values, key, &offset, &datetime);
|
||||
device_date_time_ = strdatetime(&datetime);
|
||||
t->addMoreExplanation(offset, " device datetime (%s)", device_date_time_.c_str());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,9 @@
|
|||
using namespace std;
|
||||
|
||||
#define LIST_OF_CONVERSIONS \
|
||||
X(KWH, GJ, {vto=vfrom*0.0036;}) \
|
||||
X(Second, Hour, {vto=vfrom/3600.0;}) \
|
||||
X(Hour, Second, {vto=vfrom*3600.0;}) \
|
||||
X(KWH, GJ, {vto=vfrom*0.0036;}) \
|
||||
X(GJ, KWH,{vto=vfrom/0.0036;}) \
|
||||
X(M3, L, {vto=vfrom*1000.0;}) \
|
||||
X(L, M3, {vto=vfrom/1000.0;}) \
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (C) 2019 Fredrik Öhrström
|
||||
Copyright (C) 2019-2020 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
|
||||
|
@ -30,7 +30,7 @@
|
|||
X(RelativeHumidity,RH) \
|
||||
X(HCA,HCA) \
|
||||
X(Text,TXT) \
|
||||
X(Time,Seconds) \
|
||||
X(Time,Hour) \
|
||||
|
||||
#define LIST_OF_UNITS \
|
||||
X(KWH,kwh,kWh,Energy,"kilo Watt hour") \
|
||||
|
@ -44,7 +44,8 @@
|
|||
X(RH,rh,RH,RelativeHumidity,"relative humidity") \
|
||||
X(HCA,hca,hca,HCA,"heat cost allocation") \
|
||||
X(TXT,txt,txt,Text,"text") \
|
||||
X(Seconds,s,s,Time,"seconds") \
|
||||
X(Second,s,s,Time,"second") \
|
||||
X(Hour,h,h,Time,"hour")
|
||||
|
||||
enum class Unit
|
||||
{
|
||||
|
|
|
@ -1384,7 +1384,6 @@ bool Telegram::potentiallyDecrypt(vector<uchar>::iterator &pos)
|
|||
}
|
||||
else if (tpl_sec_mode == TPLSecurityMode::AES_CBC_NO_IV)
|
||||
{
|
||||
fprintf(stderr, "BLALSALDLASDÖLAKDLAKDSÖLADS\n");
|
||||
bool ok = decrypt_TPL_AES_CBC_NO_IV(this, frame, pos, tpl_generated_key);
|
||||
if (!ok) return false;
|
||||
// Now the frame from pos and onwards has been decrypted.
|
||||
|
|
Ładowanie…
Reference in New Issue