kopia lustrzana https://github.com/weetmuts/wmbusmeters
commit
6e87f9f611
|
@ -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|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;}) \
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
Ładowanie…
Reference in New Issue