kopia lustrzana https://github.com/weetmuts/wmbusmeters
Added evo868 water wmbus module.
rodzic
f29e819afd
commit
73c18c1831
1
CHANGES
1
CHANGES
|
@ -1,4 +1,5 @@
|
|||
|
||||
Added support for evo868 water meter addon module.
|
||||
Added support for whe542 heat cost allocator.
|
||||
|
||||
Marc Kolly improved the Waterstar meter and added better error codes
|
||||
|
|
1
Makefile
1
Makefile
|
@ -129,6 +129,7 @@ METER_OBJS:=\
|
|||
$(BUILD)/meter_em24.o \
|
||||
$(BUILD)/meter_emerlin868.o \
|
||||
$(BUILD)/meter_ev200.o \
|
||||
$(BUILD)/meter_evo868.o \
|
||||
$(BUILD)/meter_eurisii.o \
|
||||
$(BUILD)/meter_fhkvdataiii.o \
|
||||
$(BUILD)/meter_fhkvdataiv.o \
|
||||
|
|
|
@ -267,6 +267,7 @@ Diehl/Sappel IZAR RC 868 I R4 PL (izar) (non-standard protocol)
|
|||
Diehl HYDRUS (hydrus)
|
||||
Elster Merlin 868 (emerlin868)
|
||||
Elster V200H (ev200)
|
||||
Maddalena EVO 868 (evo868)
|
||||
Honeywell Q400 (q400)
|
||||
Kamstrup Multical 21 (multical21)
|
||||
Kamstrup flowIQ 2200 (flowiq2200)
|
||||
|
|
|
@ -218,3 +218,8 @@ telegram=|294468506935639176F0A0|009F2782290060822900000401D6311AF93E1BF93E008DC
|
|||
telegram=|36446850626262624543A1|009F2777010060780000000A000000000000000000000000000000000000000000000000A0400000B4010000|
|
||||
{"media":"heat","meter":"compact5","name":"Heating","id":"62626262","total_kwh":495,"current_kwh":120,"previous_kwh":375,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
|Heating;62626262;495.000000;120.000000;375.000000;1111-11-11 11:11.11
|
||||
|
||||
# Test Maddalena EVO 868 wmbus module on water meter
|
||||
telegram=|aa4424347677787950077ac10000202f2f041306070000046d1e31b12104fd17000000000e787880048120004413c9040000426c9f2c840113c904000082016c9f2cd3013b9a0200c4016d0534a7218104fd280182046c9f2c840413c9040000c404131b00000084051300000000c405130000000084061300000000c406130000000084071300000000c407130000000084081300000000c408130000000084091300000000c4091300000000ffff|
|
||||
{"media":"water","meter":"evo868","name":"Votchka","id":"79787776","total_m3":1.798,"device_date_time":"2021-01-17 17:30","current_status":"OK","fabrication_no":"000218400887","consumption_at_set_date_m3":1.225,"set_date":"2020-12-31","consumption_at_set_date_2_m3":1.225,"set_date_2":"2020-12-31","max_flow_since_datetime_m3h":0.666,"max_flow_datetime":"2021-01-07 20:05","consumption_at_history_1_m3":1.225,"history_1_date":"2020-12-31","consumption_at_history_2_m3":0.027,"history_2_date":"2020-11-30","consumption_at_history_3_m3":0,"history_3_date":"2020-10-31","consumption_at_history_4_m3":0,"history_4_date":"2020-09-30","consumption_at_history_5_m3":0,"history_5_date":"2020-08-31","consumption_at_history_6_m3":0,"history_6_date":"2020-07-31","consumption_at_history_7_m3":0,"history_7_date":"2020-06-30","consumption_at_history_8_m3":0,"history_8_date":"2020-05-31","consumption_at_history_9_m3":0,"history_9_date":"2020-04-30","consumption_at_history_10_m3":0,"history_10_date":"2020-03-31","consumption_at_history_11_m3":0,"history_11_date":"2020-02-29","consumption_at_history_12_m3":0,"history_12_date":"2020-01-31","timestamp":"1111-11-11T11:11:11Z"}
|
||||
|Votchka;79787776;1.798000;OK;1.225000;2020-12-31;1111-11-11 11:11.11
|
||||
|
|
|
@ -0,0 +1,369 @@
|
|||
/*
|
||||
Copyright (C) 2017-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
|
||||
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"dvparser.h"
|
||||
#include"meters.h"
|
||||
#include"meters_common_implementation.h"
|
||||
#include"wmbus.h"
|
||||
#include"wmbus_utils.h"
|
||||
#include"util.h"
|
||||
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
|
||||
struct MeterEvo868 : public virtual WaterMeter, public virtual MeterCommonImplementation {
|
||||
MeterEvo868(MeterInfo &mi);
|
||||
|
||||
// Total water counted through the meter
|
||||
double totalWaterConsumption(Unit u);
|
||||
bool hasTotalWaterConsumption();
|
||||
uint32_t error_flags_ {};
|
||||
string fabrication_no_;
|
||||
double consumption_at_set_date_m3_ {};
|
||||
string set_date_;
|
||||
double consumption_at_set_date_2_m3_ {};
|
||||
string set_date_2_;
|
||||
double max_flow_since_datetime_m3h_ {};
|
||||
string max_flow_datetime_;
|
||||
|
||||
double consumption_at_history_date_m3_[12];
|
||||
string history_date_[12];
|
||||
|
||||
string status();
|
||||
|
||||
private:
|
||||
void processContent(Telegram *t);
|
||||
|
||||
double total_water_consumption_m3_ {};
|
||||
string device_date_time_;
|
||||
};
|
||||
|
||||
shared_ptr<WaterMeter> createEVO868(MeterInfo &mi)
|
||||
{
|
||||
return shared_ptr<WaterMeter>(new MeterEvo868(mi));
|
||||
}
|
||||
|
||||
MeterEvo868::MeterEvo868(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterType::EVO868)
|
||||
{
|
||||
setExpectedTPLSecurityMode(TPLSecurityMode::AES_CBC_IV);
|
||||
|
||||
addLinkMode(LinkMode::T1);
|
||||
|
||||
addPrint("total", Quantity::Volume,
|
||||
[&](Unit u){ return totalWaterConsumption(u); },
|
||||
"The total water consumption recorded by this meter.",
|
||||
true, true);
|
||||
|
||||
addPrint("device_date_time", Quantity::Text,
|
||||
[&](){ return device_date_time_; },
|
||||
"Device date time.",
|
||||
false, true);
|
||||
|
||||
addPrint("current_status", Quantity::Text,
|
||||
[&](){ return status(); },
|
||||
"Status of meter.",
|
||||
true, true);
|
||||
|
||||
addPrint("fabrication_no", Quantity::Text,
|
||||
[&](){ return fabrication_no_; },
|
||||
"Fabrication number.",
|
||||
false, true);
|
||||
|
||||
addPrint("consumption_at_set_date", Quantity::Volume,
|
||||
[&](Unit u){ assertQuantity(u, Quantity::Volume); return convert(consumption_at_set_date_m3_, Unit::M3, u); },
|
||||
"The total water consumption at the most recent billing period date.",
|
||||
true, true);
|
||||
|
||||
addPrint("set_date", Quantity::Text,
|
||||
[&](){ return set_date_; },
|
||||
"The most recent billing period date.",
|
||||
true, true);
|
||||
|
||||
addPrint("consumption_at_set_date_2", Quantity::Volume,
|
||||
[&](Unit u){ assertQuantity(u, Quantity::Volume); return convert(consumption_at_set_date_2_m3_, Unit::M3, u); },
|
||||
"The total water consumption at the second recent billing period date.",
|
||||
false, true);
|
||||
|
||||
addPrint("set_date_2", Quantity::Text,
|
||||
[&](){ return set_date_2_; },
|
||||
"The second recent billing period date.",
|
||||
false, true);
|
||||
|
||||
addPrint("max_flow_since_datetime", Quantity::Flow,
|
||||
[&](Unit u){ assertQuantity(u, Quantity::Flow); return convert(max_flow_since_datetime_m3h_, Unit::M3H, u); },
|
||||
"Maximum water flow since date time.",
|
||||
false, true);
|
||||
|
||||
addPrint("max_flow_datetime", Quantity::Text,
|
||||
[&](){ return max_flow_datetime_; },
|
||||
"The datetime to which maximum flow is measured.",
|
||||
false, true);
|
||||
|
||||
for (int i=1; i<=12; ++i)
|
||||
{
|
||||
string key = tostrprintf("consumption_at_history_%d", i);
|
||||
string epl = tostrprintf("The total water consumption at the history date %d.", i);
|
||||
|
||||
addPrint(key, Quantity::Volume,
|
||||
[this,i](Unit u){ assertQuantity(u, Quantity::Volume); return convert(consumption_at_history_date_m3_[i-1], Unit::M3, u); },
|
||||
epl,
|
||||
false, true);
|
||||
key = tostrprintf("history_%d_date", i);
|
||||
epl = tostrprintf("The history date %d.", i);
|
||||
|
||||
addPrint(key, Quantity::Text,
|
||||
[this,i](){ return history_date_[i-1]; },
|
||||
epl,
|
||||
false, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MeterEvo868::processContent(Telegram *t)
|
||||
{
|
||||
/*
|
||||
(evo868) 11: 04 dif (32 Bit Integer/Binary Instantaneous value)
|
||||
(evo868) 12: 13 vif (Volume l)
|
||||
(evo868) 13: * 06070000 total consumption (1.798000 m3)
|
||||
|
||||
(evo868) 17: 04 dif (32 Bit Integer/Binary Instantaneous value)
|
||||
(evo868) 18: 6D vif (Date and time type)
|
||||
(evo868) 19: 1E31B121
|
||||
|
||||
(evo868) 1d: 04 dif (32 Bit Integer/Binary Instantaneous value)
|
||||
(evo868) 1e: FD vif (Second extension of VIF-codes)
|
||||
(evo868) 1f: 17 vife (Error flags (binary))
|
||||
(evo868) 20: 00000000
|
||||
|
||||
(evo868) 24: 0E dif (12 digit BCD Instantaneous value)
|
||||
(evo868) 25: 78 vif (Fabrication no)
|
||||
(evo868) 26: 788004812000
|
||||
|
||||
(evo868) 2c: 44 dif (32 Bit Integer/Binary Instantaneous value storagenr=1)
|
||||
(evo868) 2d: 13 vif (Volume l)
|
||||
(evo868) 2e: C9040000
|
||||
|
||||
(evo868) 32: 42 dif (16 Bit Integer/Binary Instantaneous value storagenr=1)
|
||||
(evo868) 33: 6C vif (Date type G)
|
||||
(evo868) 34: 9F2C
|
||||
|
||||
(evo868) 36: 84 dif (32 Bit Integer/Binary Instantaneous value)
|
||||
(evo868) 37: 01 dife (subunit=0 tariff=0 storagenr=2)
|
||||
(evo868) 38: 13 vif (Volume l)
|
||||
(evo868) 39: C9040000
|
||||
|
||||
(evo868) 3d: 82 dif (16 Bit Integer/Binary Instantaneous value)
|
||||
(evo868) 3e: 01 dife (subunit=0 tariff=0 storagenr=2)
|
||||
(evo868) 3f: 6C vif (Date type G)
|
||||
(evo868) 40: 9F2C
|
||||
|
||||
(evo868) 42: D3 dif (24 Bit Integer/Binary Maximum value storagenr=1)
|
||||
(evo868) 43: 01 dife (subunit=0 tariff=0 storagenr=3)
|
||||
(evo868) 44: 3B vif (Volume flow l/h)
|
||||
(evo868) 45: 9A0200
|
||||
|
||||
(evo868) 48: C4 dif (32 Bit Integer/Binary Instantaneous value storagenr=1)
|
||||
(evo868) 49: 01 dife (subunit=0 tariff=0 storagenr=3)
|
||||
(evo868) 4a: 6D vif (Date and time type)
|
||||
(evo868) 4b: 0534A721
|
||||
|
||||
(evo868) 4f: 81 dif (8 Bit Integer/Binary Instantaneous value)
|
||||
(evo868) 50: 04 dife (subunit=0 tariff=0 storagenr=8)
|
||||
(evo868) 51: FD vif (Second extension of VIF-codes)
|
||||
(evo868) 52: 28 vife (Storage interval month(s))
|
||||
(evo868) 53: 01
|
||||
|
||||
(evo868) 54: 82 dif (16 Bit Integer/Binary Instantaneous value)
|
||||
(evo868) 55: 04 dife (subunit=0 tariff=0 storagenr=8)
|
||||
(evo868) 56: 6C vif (Date type G)
|
||||
(evo868) 57: 9F2C
|
||||
|
||||
(evo868) 59: 84 dif (32 Bit Integer/Binary Instantaneous value)
|
||||
(evo868) 5a: 04 dife (subunit=0 tariff=0 storagenr=8)
|
||||
(evo868) 5b: 13 vif (Volume l)
|
||||
(evo868) 5c: C9040000
|
||||
|
||||
(evo868) 60: C4 dif (32 Bit Integer/Binary Instantaneous value storagenr=1)
|
||||
(evo868) 61: 04 dife (subunit=0 tariff=0 storagenr=9)
|
||||
(evo868) 62: 13 vif (Volume l)
|
||||
(evo868) 63: 1B000000
|
||||
|
||||
(evo868) 67: 84 dif (32 Bit Integer/Binary Instantaneous value)
|
||||
(evo868) 68: 05 dife (subunit=0 tariff=0 storagenr=10)
|
||||
(evo868) 69: 13 vif (Volume l)
|
||||
(evo868) 6a: 00000000
|
||||
|
||||
(evo868) 6e: C4 dif (32 Bit Integer/Binary Instantaneous value storagenr=1)
|
||||
(evo868) 6f: 05 dife (subunit=0 tariff=0 storagenr=11)
|
||||
(evo868) 70: 13 vif (Volume l)
|
||||
(evo868) 71: 00000000
|
||||
|
||||
(evo868) 75: 84 dif (32 Bit Integer/Binary Instantaneous value)
|
||||
(evo868) 76: 06 dife (subunit=0 tariff=0 storagenr=12)
|
||||
(evo868) 77: 13 vif (Volume l)
|
||||
(evo868) 78: 00000000
|
||||
|
||||
(evo868) 7c: C4 dif (32 Bit Integer/Binary Instantaneous value storagenr=1)
|
||||
(evo868) 7d: 06 dife (subunit=0 tariff=0 storagenr=13)
|
||||
(evo868) 7e: 13 vif (Volume l)
|
||||
(evo868) 7f: 00000000
|
||||
|
||||
(evo868) 83: 84 dif (32 Bit Integer/Binary Instantaneous value)
|
||||
(evo868) 84: 07 dife (subunit=0 tariff=0 storagenr=14)
|
||||
(evo868) 85: 13 vif (Volume l)
|
||||
(evo868) 86: 00000000
|
||||
|
||||
(evo868) 8a: C4 dif (32 Bit Integer/Binary Instantaneous value storagenr=1)
|
||||
(evo868) 8b: 07 dife (subunit=0 tariff=0 storagenr=15)
|
||||
(evo868) 8c: 13 vif (Volume l)
|
||||
(evo868) 8d: 00000000
|
||||
|
||||
(evo868) 91: 84 dif (32 Bit Integer/Binary Instantaneous value)
|
||||
(evo868) 92: 08 dife (subunit=0 tariff=0 storagenr=16)
|
||||
(evo868) 93: 13 vif (Volume l)
|
||||
(evo868) 94: 00000000
|
||||
|
||||
(evo868) 98: C4 dif (32 Bit Integer/Binary Instantaneous value storagenr=1)
|
||||
(evo868) 99: 08 dife (subunit=0 tariff=0 storagenr=17)
|
||||
(evo868) 9a: 13 vif (Volume l)
|
||||
(evo868) 9b: 00000000
|
||||
|
||||
(evo868) 9f: 84 dif (32 Bit Integer/Binary Instantaneous value)
|
||||
(evo868) a0: 09 dife (subunit=0 tariff=0 storagenr=18)
|
||||
(evo868) a1: 13 vif (Volume l)
|
||||
(evo868) a2: 00000000
|
||||
|
||||
(evo868) a6: C4 dif (32 Bit Integer/Binary Instantaneous value storagenr=1)
|
||||
(evo868) a7: 09 dife (subunit=0 tariff=0 storagenr=19)
|
||||
(evo868) a8: 13 vif (Volume l)
|
||||
(evo868) a9: 00000000
|
||||
*/
|
||||
int offset;
|
||||
string key;
|
||||
|
||||
if(findKey(MeasurementType::Instantaneous, ValueInformation::Volume, 0, 0, &key, &t->values)) {
|
||||
extractDVdouble(&t->values, key, &offset, &total_water_consumption_m3_);
|
||||
t->addMoreExplanation(offset, " total consumption (%f m3)", total_water_consumption_m3_);
|
||||
}
|
||||
|
||||
if (findKey(MeasurementType::Instantaneous, ValueInformation::DateTime, 0, 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());
|
||||
}
|
||||
|
||||
extractDVuint32(&t->values, "04FD17", &offset, &error_flags_);
|
||||
t->addMoreExplanation(offset, " error flags (%s)", status().c_str());
|
||||
|
||||
extractDVstring(&t->values, "0E78", &offset, &fabrication_no_);
|
||||
reverse(fabrication_no_.begin(), fabrication_no_.end());
|
||||
t->addMoreExplanation(offset, " fabrication no (%s)", fabrication_no_.c_str());
|
||||
|
||||
if(findKey(MeasurementType::Instantaneous, ValueInformation::Volume, 1, 0, &key, &t->values)) {
|
||||
extractDVdouble(&t->values, key, &offset, &consumption_at_set_date_m3_);
|
||||
t->addMoreExplanation(offset, " consumption at set date (%f m3)", consumption_at_set_date_m3_);
|
||||
}
|
||||
|
||||
if (findKey(MeasurementType::Instantaneous, ValueInformation::Date, 1, 0, &key, &t->values)) {
|
||||
struct tm date;
|
||||
extractDVdate(&t->values, key, &offset, &date);
|
||||
set_date_ = strdate(&date);
|
||||
t->addMoreExplanation(offset, " set date (%s)", set_date_.c_str());
|
||||
}
|
||||
|
||||
if(findKey(MeasurementType::Instantaneous, ValueInformation::Volume, 2, 0, &key, &t->values)) {
|
||||
extractDVdouble(&t->values, key, &offset, &consumption_at_set_date_2_m3_);
|
||||
t->addMoreExplanation(offset, " consumption at set date 2 (%f m3)", consumption_at_set_date_2_m3_);
|
||||
}
|
||||
|
||||
if (findKey(MeasurementType::Instantaneous, ValueInformation::Date, 2, 0, &key, &t->values)) {
|
||||
struct tm date;
|
||||
extractDVdate(&t->values, key, &offset, &date);
|
||||
set_date_2_ = strdate(&date);
|
||||
t->addMoreExplanation(offset, " set date 2 (%s)", set_date_2_.c_str());
|
||||
}
|
||||
|
||||
if(findKey(MeasurementType::Maximum, ValueInformation::VolumeFlow, 3, 0, &key, &t->values)) {
|
||||
extractDVdouble(&t->values, key, &offset, &max_flow_since_datetime_m3h_);
|
||||
t->addMoreExplanation(offset, " max flow (%f m3/h)", max_flow_since_datetime_m3h_);
|
||||
}
|
||||
|
||||
if (findKey(MeasurementType::Instantaneous, ValueInformation::DateTime, 3, 0, &key, &t->values)) {
|
||||
struct tm datetime;
|
||||
extractDVdate(&t->values, key, &offset, &datetime);
|
||||
max_flow_datetime_ = strdatetime(&datetime);
|
||||
t->addMoreExplanation(offset, " max flow since datetime (%s)", max_flow_datetime_.c_str());
|
||||
}
|
||||
|
||||
uint8_t month_increment = 0;
|
||||
extractDVuint8(&t->values, "8104FD28", &offset, &month_increment);
|
||||
t->addMoreExplanation(offset, " month increment (%d)", month_increment);
|
||||
|
||||
struct tm date;
|
||||
if (findKey(MeasurementType::Instantaneous, ValueInformation::Date, 8, 0, &key, &t->values)) {
|
||||
extractDVdate(&t->values, key, &offset, &date);
|
||||
string start = strdate(&date);
|
||||
t->addMoreExplanation(offset, " history starts with date (%s)", start.c_str());
|
||||
}
|
||||
|
||||
// 12 months of historical data, starting in storage 8.
|
||||
for (int i=1; i<=12; ++i)
|
||||
{
|
||||
if(findKey(MeasurementType::Instantaneous, ValueInformation::Volume, i+7, 0, &key, &t->values)) {
|
||||
extractDVdouble(&t->values, key, &offset, &consumption_at_history_date_m3_[i-1]);
|
||||
t->addMoreExplanation(offset, " consumption at history %d (%f m3)", i, consumption_at_history_date_m3_[i-1]);
|
||||
struct tm d = date;
|
||||
if (i>1) addMonths(&d, 1-i);
|
||||
history_date_[i-1] = strdate(&d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double MeterEvo868::totalWaterConsumption(Unit u)
|
||||
{
|
||||
assertQuantity(u, Quantity::Volume);
|
||||
return convert(total_water_consumption_m3_, Unit::M3, u);
|
||||
}
|
||||
|
||||
bool MeterEvo868::hasTotalWaterConsumption()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
string MeterEvo868::status()
|
||||
{
|
||||
if (error_flags_ == 0)
|
||||
{
|
||||
return "OK";
|
||||
}
|
||||
|
||||
/* Possible errors according to datasheet:
|
||||
overflow (threshold configurable, must be activated)
|
||||
backflow (threshold set, configurable)
|
||||
leak
|
||||
meter blocked
|
||||
non-used (days threshold set, configurable)
|
||||
magnetic and mechanical tampering (removal)
|
||||
*/
|
||||
|
||||
// How do we decode these?
|
||||
string info;
|
||||
strprintf(info, "ERROR bits %08x", error_flags_);
|
||||
return info;
|
||||
}
|
|
@ -41,6 +41,7 @@
|
|||
X(em24, C1_bit, ElectricityMeter, EM24, EM24) \
|
||||
X(emerlin868, T1_bit, WaterMeter, EMERLIN868, EMerlin868) \
|
||||
X(ev200, T1_bit, WaterMeter, EV200, EV200) \
|
||||
X(evo868, T1_bit, WaterMeter, EVO868, EVO868) \
|
||||
X(fhkvdataiii,T1_bit, HeatCostAllocationMeter, FHKVDATAIII, FHKVDataIII) \
|
||||
X(fhkvdataiv, T1_bit, HeatCostAllocationMeter, FHKVDATAIV, FHKVDataIV) \
|
||||
X(hydrus, T1_bit, WaterMeter, HYDRUS, Hydrus) \
|
||||
|
@ -111,6 +112,7 @@
|
|||
X(EM24, MANUFACTURER_KAM, 0x02, 0x33) \
|
||||
X(EMERLIN868,MANUFACTURER_ELR, 0x37, 0x11) \
|
||||
X(EV200, MANUFACTURER_ELR, 0x07, 0x0d) \
|
||||
X(EVO868, MANUFACTURER_MAD, 0x07, 0x50) \
|
||||
X(FHKVDATAIII,MANUFACTURER_TCH, 0x80, 0x69) \
|
||||
X(FHKVDATAIII,MANUFACTURER_TCH, 0x80, 0x94) \
|
||||
X(FHKVDATAIV,MANUFACTURER_TCH, 0x08, 0x69) \
|
||||
|
|
|
@ -37,6 +37,7 @@ void test_ids();
|
|||
void test_kdf();
|
||||
void test_periods();
|
||||
void test_devices();
|
||||
void test_months();
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
@ -62,6 +63,7 @@ int main(int argc, char **argv)
|
|||
test_ids();
|
||||
test_kdf();
|
||||
test_periods();
|
||||
test_months();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -644,3 +646,26 @@ void test_devices()
|
|||
|
||||
|
||||
}
|
||||
|
||||
void test_months()
|
||||
{
|
||||
struct tm date;
|
||||
date.tm_year = 2020-1900;
|
||||
date.tm_mon = 12-1;
|
||||
date.tm_mday = 31;
|
||||
|
||||
string s = strdate(&date);
|
||||
|
||||
struct tm d;
|
||||
d = date;
|
||||
addMonths(&d, -10);
|
||||
|
||||
string os = strdate(&d);
|
||||
|
||||
if (s != "2020-12-31" ||
|
||||
os != "2020-02-29")
|
||||
{
|
||||
printf("ERROR! Expected 2020-12-31 - 10 months should be 2020-02-29\n"
|
||||
"But got %s - 11 = %s\n", s.c_str(), os.c_str());
|
||||
}
|
||||
}
|
||||
|
|
55
src/util.cc
55
src/util.cc
|
@ -1180,6 +1180,61 @@ string strdatetimesec(struct tm *datetime)
|
|||
return string(buf);
|
||||
}
|
||||
|
||||
bool is_leap_year(int year)
|
||||
{
|
||||
if (year % 4 != 0) return false;
|
||||
if (year % 400 == 0) return true;
|
||||
if (year % 100 == 0) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int days_in_months[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
|
||||
int get_days_in_month(int year, int month)
|
||||
{
|
||||
assert(month >= 0);
|
||||
assert(month < 12);
|
||||
|
||||
int days = days_in_months[month];
|
||||
|
||||
if (month == 1 && is_leap_year(year))
|
||||
{
|
||||
// Handle february in a leap year.
|
||||
days += 1;
|
||||
}
|
||||
|
||||
return days;
|
||||
}
|
||||
|
||||
void addMonths(struct tm *date, int months)
|
||||
{
|
||||
bool is_last_day_in_month = date->tm_mday == get_days_in_month(date->tm_year, date->tm_mon);
|
||||
|
||||
int year = date->tm_year + months / 12;
|
||||
int month = date->tm_mon + months % 12;
|
||||
|
||||
if (month > 11)
|
||||
{
|
||||
year += 1;
|
||||
month -= 12;
|
||||
}
|
||||
|
||||
int day;
|
||||
|
||||
if (is_last_day_in_month)
|
||||
{
|
||||
day = get_days_in_month(year, month); // Last day of month maps to last day of result month
|
||||
}
|
||||
else
|
||||
{
|
||||
day = std::min(date->tm_mday, get_days_in_month(year, month));
|
||||
}
|
||||
|
||||
date->tm_year = year;
|
||||
date->tm_mon = month;
|
||||
date->tm_mday = day;
|
||||
}
|
||||
|
||||
AccessCheck checkIfExistsAndSameGroup(string device)
|
||||
{
|
||||
struct stat sb;
|
||||
|
|
|
@ -55,6 +55,7 @@ std::string strdate(struct tm *date);
|
|||
std::string strdatetime(struct tm *date);
|
||||
// Return for example: 2010-03-21 15:22:03
|
||||
std::string strdatetimesec(struct tm *date);
|
||||
void addMonths(struct tm* date, int m);
|
||||
|
||||
bool stringFoundCaseIgnored(std::string haystack, std::string needle);
|
||||
|
||||
|
|
|
@ -220,6 +220,11 @@ Received telegram from: 62626262
|
|||
type: Heat meter (0x43)
|
||||
ver: 0x45
|
||||
driver: compact5
|
||||
Received telegram from: 79787776
|
||||
manufacturer: (MAD) Maddalena, Italy (0x3424)
|
||||
type: Water meter (0x07)
|
||||
ver: 0x50
|
||||
driver: evo868
|
||||
EOF
|
||||
|
||||
RES=$($PROG --logfile=$LOGFILE --t1 simulations/simulation_t1.txt 2>&1)
|
||||
|
|
|
@ -20,6 +20,7 @@ METERS="MyWarmWater supercom587 12345678 NOKEY
|
|||
Room fhkvdataiii 11776622 NOKEY
|
||||
Rooom fhkvdataiv 14542076 FCF41938F63432975B52505F547FCEDF
|
||||
HeatMeter eurisii 88018801 NOKEY
|
||||
Votchka evo868 79787776 NOKEY
|
||||
Smokeo lansensm 00010204 NOKEY
|
||||
Tempoo lansenth 00010203 NOKEY
|
||||
Dooro lansendw 00010205 NOKEY
|
||||
|
|
Ładowanie…
Reference in New Issue