Merge pull request #106 from ZeWaren/improve-izar-meter

Improve the IZAR meter
pull/111/head
Fredrik Öhrström 2020-04-26 15:01:52 +02:00 zatwierdzone przez GitHub
commit 6e87f9f611
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
6 zmienionych plików z 155 dodań i 6 usunięć

8
simulations/simulation_t1.txt 100644 → 100755
Wyświetl plik

@ -63,14 +63,14 @@ telegram=|5744b40988227711101b7ab20800000265a00842658f088201659f08226589081265a0
# Test IZAR RC 868 I R4 PL water meter telegram # Test IZAR RC 868 I R4 PL water meter telegram
telegram=|1944304C72242421D401A2|013D4013DD8B46A4999C1293E582CC| telegram=|1944304C72242421D401A2|013D4013DD8B46A4999C1293E582CC|
{"media":"water","meter":"izar","name":"IzarWater","id":"21242472","total_m3":3.488,"last_month_total_m3":3.486,"timestamp":"1111-11-11T11:11:11Z"} {"media":"water","meter":"izar","name":"IzarWater","id":"21242472","total_m3":3.488,"last_month_total_m3":3.486,"last_month_measure_date":"2019-09-30","remaining_battery_life_y":14.5,"current_alarms":"meter_blocked,underflow","previous_alarms":"no_alarm","timestamp":"1111-11-11T11:11:11Z"}
|IzarWater;21242472;3.488000;3.486000;1111-11-11 11:11.11 IzarWater;21242472;3.488000;3.486000;2019-09-30;14.500000;meter_blocked,underflow;no_alarm;1111-11-11 11:11.11
# Test new version of IZAR # Test new version of IZAR
telegram=|2944A511780729662366A20118001378D3B3DB8CEDD77731F25832AAF3DA8CADF9774EA673172E8C61F2| telegram=|2944A511780729662366A20118001378D3B3DB8CEDD77731F25832AAF3DA8CADF9774EA673172E8C61F2|
{"media":"water","meter":"izar","name":"IzarWater2","id":"66290778","total_m3":16.76,"last_month_total_m3":11.84,"timestamp":"1111-11-11T11:11:11Z"} {"media":"water","meter":"izar","name":"IzarWater2","id":"66290778","total_m3":16.76,"last_month_total_m3":11.84,"last_month_measure_date":"2019-11-30","remaining_battery_life_y":12,"current_alarms":"no_alarm","previous_alarms":"no_alarm","timestamp":"1111-11-11T11:11:11Z"}
|IzarWater2;66290778;16.760000;11.840000;1111-11-11 11:11.11 IzarWater2;66290778;16.760000;11.840000;2019-11-30;12.000000;no_alarm;no_alarm;1111-11-11 11:11.11
# Test Hydrus water meter telegram # Test Hydrus water meter telegram
telegram=|4E44A5116464646470077AED004005|2F2F01FD08300C13741100007C1300000000FC101300000000FC201300000000726C00000B3B00000002FD748713025A6800C4016D3B177F2ACC011300020000| telegram=|4E44A5116464646470077AED004005|2F2F01FD08300C13741100007C1300000000FC101300000000FC201300000000726C00000B3B00000002FD748713025A6800C4016D3B177F2ACC011300020000|

138
src/meter_izar.cc 100644 → 100755
Wyświetl plik

@ -20,13 +20,30 @@
#include"wmbus.h" #include"wmbus.h"
#include"wmbus_utils.h" #include"wmbus_utils.h"
#include <algorithm> #include<algorithm>
#include<stdbool.h>
using namespace std; using namespace std;
#define PRIOS_DEFAULT_KEY1 "39BC8A10E66D83F8" #define PRIOS_DEFAULT_KEY1 "39BC8A10E66D83F8"
#define PRIOS_DEFAULT_KEY2 "51728910E66D83F8" #define PRIOS_DEFAULT_KEY2 "51728910E66D83F8"
/** Contains all the booleans required to store the alarms of a PRIOS device. */
typedef struct _izar_alarms {
bool general_alarm;
bool leakage_currently;
bool leakage_previously;
bool meter_blocked;
bool back_flow;
bool underflow;
bool overflow;
bool submarine;
bool sensor_fraud_currently;
bool sensor_fraud_previously;
bool mechanical_fraud_currently;
bool mechanical_fraud_previously;
} izar_alarms;
struct MeterIzar : public virtual WaterMeter, public virtual MeterCommonImplementation { struct MeterIzar : public virtual WaterMeter, public virtual MeterCommonImplementation {
MeterIzar(WMBus *bus, MeterInfo &mi); MeterIzar(WMBus *bus, MeterInfo &mi);
@ -35,6 +52,9 @@ struct MeterIzar : public virtual WaterMeter, public virtual MeterCommonImplemen
bool hasTotalWaterConsumption(); bool hasTotalWaterConsumption();
double lastMonthTotalWaterConsumption(Unit u); double lastMonthTotalWaterConsumption(Unit u);
string setH0Date();
string currentAlarmsText();
string previousAlarmsText();
private: private:
@ -44,8 +64,13 @@ private:
uint32_t uint32FromBytes(const vector<uchar> &data, int offset, bool reverse = false); uint32_t uint32FromBytes(const vector<uchar> &data, int offset, bool reverse = false);
vector<uchar> decodePrios(const vector<uchar> &payload, uint32_t key); vector<uchar> decodePrios(const vector<uchar> &payload, uint32_t key);
double remaining_battery_life;
uint16_t h0_year;
uint8_t h0_month;
uint8_t h0_day;
double total_water_consumption_l_ {}; double total_water_consumption_l_ {};
double last_month_total_water_consumption_l_ {}; double last_month_total_water_consumption_l_ {};
izar_alarms alarms;
vector<uint32_t> keys; vector<uint32_t> keys;
}; };
@ -88,6 +113,27 @@ MeterIzar::MeterIzar(WMBus *bus, MeterInfo &mi) :
[&](Unit u){ return lastMonthTotalWaterConsumption(u); }, [&](Unit u){ return lastMonthTotalWaterConsumption(u); },
"The total water consumption recorded by this meter around end of last month.", "The total water consumption recorded by this meter around end of last month.",
true, true); true, true);
addPrint("last_month_measure_date", Quantity::Text,
[&](){ return setH0Date(); },
"The date when the meter recorded the most recent billing value.",
true, true);
addPrint("remaining_battery_life", Quantity::Time, Unit::Year,
[&](Unit u){ return convert(remaining_battery_life, Unit::Year, u); },
"How many more years the battery is expected to last",
true, true);
addPrint("current_alarms", Quantity::Text,
[&](){ return currentAlarmsText(); },
"Alarms currently reported by the meter.",
true, true);
addPrint("previous_alarms", Quantity::Text,
[&](){ return previousAlarmsText(); },
"Alarms currently reported by the meter.",
true, true);
} }
double MeterIzar::totalWaterConsumption(Unit u) double MeterIzar::totalWaterConsumption(Unit u)
@ -107,6 +153,69 @@ double MeterIzar::lastMonthTotalWaterConsumption(Unit u)
return convert(last_month_total_water_consumption_l_, Unit::L, u); return convert(last_month_total_water_consumption_l_, Unit::L, u);
} }
string MeterIzar::setH0Date()
{
char result[11];
snprintf(result, sizeof(result), "%04d-%02d-%02d", h0_year, h0_month, h0_day);
return result;
}
string MeterIzar::currentAlarmsText()
{
string s;
if (alarms.leakage_currently) {
s.append("leakage,");
}
if (alarms.meter_blocked) {
s.append("meter_blocked,");
}
if (alarms.back_flow) {
s.append("back_flow,");
}
if (alarms.underflow) {
s.append("underflow,");
}
if (alarms.overflow) {
s.append("overflow,");
}
if (alarms.submarine) {
s.append("submarine,");
}
if (alarms.sensor_fraud_currently) {
s.append("sensor_fraud,");
}
if (alarms.mechanical_fraud_currently) {
s.append("mechanical_fraud,");
}
if (s.length() > 0) {
if (alarms.general_alarm) {
return "general_alarm";
}
s.pop_back();
return s;
}
return "no_alarm";
}
string MeterIzar::previousAlarmsText()
{
string s;
if (alarms.leakage_previously) {
s.append("leakage,");
}
if (alarms.sensor_fraud_previously) {
s.append("sensor_fraud,");
}
if (alarms.mechanical_fraud_previously) {
s.append("mechanical_fraud,");
}
if (s.length() > 0) {
s.pop_back();
return s;
}
return "no_alarm";
}
uint32_t MeterIzar::uint32FromBytes(const vector<uchar> &data, int offset, bool reverse) uint32_t MeterIzar::uint32FromBytes(const vector<uchar> &data, int offset, bool reverse)
{ {
if (reverse) if (reverse)
@ -156,9 +265,36 @@ void MeterIzar::processContent(Telegram *t)
return; return;
} }
// get the remaining battery life (in year)
remaining_battery_life = (frame[12] & 0x1F) / 2.0;
total_water_consumption_l_ = uint32FromBytes(decoded_content, 1, true); total_water_consumption_l_ = uint32FromBytes(decoded_content, 1, true);
last_month_total_water_consumption_l_ = uint32FromBytes(decoded_content, 5, true); last_month_total_water_consumption_l_ = uint32FromBytes(decoded_content, 5, true);
// get the date when the second measurement was taken
h0_year = ((decoded_content[10] & 0xF0) >> 1) + ((decoded_content[9] & 0xE0) >> 5);
if (h0_year > 80) {
h0_year += 1900;
} else {
h0_year += 2000;
}
h0_month = decoded_content[10] & 0xF;
h0_day = decoded_content[9] & 0x1F;
// read the alarms:
alarms.general_alarm = frame[11] >> 7;
alarms.leakage_currently = frame[12] >> 7;
alarms.leakage_previously = frame[12] >> 6 & 0x1;
alarms.meter_blocked = frame[12] >> 5 & 0x1;
alarms.back_flow = frame[13] >> 7;
alarms.underflow = frame[13] >> 6 & 0x1;
alarms.overflow = frame[13] >> 5 & 0x1;
alarms.submarine = frame[13] >> 4 & 0x1;
alarms.sensor_fraud_currently = frame[13] >> 3 & 0x1;
alarms.sensor_fraud_previously = frame[13] >> 2 & 0x1;
alarms.mechanical_fraud_currently = frame[13] >> 1 & 0x1;
alarms.mechanical_fraud_previously = frame[13] & 0x1;
// override incorrectly reported medium (oil) // override incorrectly reported medium (oil)
t->dll_type = 7; t->dll_type = 7;
} }

Wyświetl plik

@ -104,6 +104,12 @@ void MeterCommonImplementation::addPrint(string vname, Quantity vquantity,
prints_.push_back( { vname, vquantity, defaultUnitForQuantity(vquantity), getValueFunc, NULL, help, field, json }); prints_.push_back( { vname, vquantity, defaultUnitForQuantity(vquantity), getValueFunc, NULL, help, field, json });
} }
void MeterCommonImplementation::addPrint(string vname, Quantity vquantity, Unit unit,
function<double(Unit)> getValueFunc, string help, bool field, bool json)
{
prints_.push_back( { vname, vquantity, unit, getValueFunc, NULL, help, field, json });
}
void MeterCommonImplementation::addPrint(string vname, Quantity vquantity, void MeterCommonImplementation::addPrint(string vname, Quantity vquantity,
function<string()> getValueFunc, function<string()> getValueFunc,
string help, bool field, bool json) string help, bool field, bool json)

Wyświetl plik

@ -84,6 +84,8 @@ protected:
void addManufacturer(int m); void addManufacturer(int m);
void addPrint(string vname, Quantity vquantity, void addPrint(string vname, Quantity vquantity,
function<double(Unit)> getValueFunc, string help, bool field, bool json); function<double(Unit)> getValueFunc, string help, bool field, bool json);
void addPrint(string vname, Quantity vquantity, Unit unit,
function<double(Unit)> getValueFunc, string help, bool field, bool json);
void addPrint(string vname, Quantity vquantity, void addPrint(string vname, Quantity vquantity,
function<std::string()> getValueFunc, string help, bool field, bool json); function<std::string()> getValueFunc, string help, bool field, bool json);
bool handleTelegram(vector<uchar> frame); bool handleTelegram(vector<uchar> frame);

4
src/units.cc 100644 → 100755
Wyświetl plik

@ -23,6 +23,10 @@ using namespace std;
#define LIST_OF_CONVERSIONS \ #define LIST_OF_CONVERSIONS \
X(Second, Hour, {vto=vfrom/3600.0;}) \ X(Second, Hour, {vto=vfrom/3600.0;}) \
X(Hour, Second, {vto=vfrom*3600.0;}) \ X(Hour, Second, {vto=vfrom*3600.0;}) \
X(Year, Second, {vto=vfrom*3600.0*24.0*365;}) \
X(Second, Year, {vto=vfrom/3600.0/24.0/365;}) \
X(Hour, Year, {vto=vfrom/24.0/365;}) \
X(Year, Hour, {vto=vfrom*24.0*365;}) \
X(KWH, GJ, {vto=vfrom*0.0036;}) \ X(KWH, GJ, {vto=vfrom*0.0036;}) \
X(GJ, KWH,{vto=vfrom/0.0036;}) \ X(GJ, KWH,{vto=vfrom/0.0036;}) \
X(M3, L, {vto=vfrom*1000.0;}) \ X(M3, L, {vto=vfrom*1000.0;}) \

3
src/units.h 100644 → 100755
Wyświetl plik

@ -45,7 +45,8 @@
X(HCA,hca,"hca",HCA,"heat cost allocation") \ X(HCA,hca,"hca",HCA,"heat cost allocation") \
X(TXT,txt,"txt",Text,"text") \ X(TXT,txt,"txt",Text,"text") \
X(Second,s,"s",Time,"second") \ X(Second,s,"s",Time,"second") \
X(Hour,h,"h",Time,"hour") X(Hour,h,"h",Time,"hour") \
X(Year,y,"y",Time,"year")
enum class Unit enum class Unit
{ {