kopia lustrzana https://github.com/weetmuts/wmbusmeters
Merge pull request #401 from trsqr/minomess
Add support for Zenner Minomess water meterpull/404/head
commit
4ca4fdba57
1
Makefile
1
Makefile
|
@ -168,6 +168,7 @@ METER_OBJS:=\
|
|||
$(BUILD)/meter_lansenth.o \
|
||||
$(BUILD)/meter_lansenpu.o \
|
||||
$(BUILD)/meter_lse_07_17.o \
|
||||
$(BUILD)/meter_minomess.o \
|
||||
$(BUILD)/meter_mkradio3.o \
|
||||
$(BUILD)/meter_mkradio4.o \
|
||||
$(BUILD)/meter_multical21.o \
|
||||
|
|
|
@ -345,6 +345,7 @@ Sontex Supercom 587 (supercom587)
|
|||
Sensus iPERL (iperl)
|
||||
Techem MK Radio 3 and 4 (mkradio3,mkradio4) (non-standard protocols)
|
||||
Waterstar M (waterstarm)
|
||||
Zenner Minomess (minomess)
|
||||
|
||||
Currently not supported, please help!
|
||||
Diehl/Sappel ACQUARIUS/IZAR R3 (izar3)
|
||||
|
|
|
@ -90,3 +90,7 @@ telegram=|5E462515112801000C1A7A370050252F2F|0BFD0F060101046D300CAB2202FD1700008
|
|||
# Test Techem radio convert + Wehrle water meter combo.
|
||||
telegram=|494468509494949495377286868686A85CFE07A90030052F2F|0413100000000F52FCF6A52A90A8D83CA8F7FEAE86990502323D0C70EFF49833C7C1696F75BCABC1E52E6305308D0F31FB|
|
||||
{"media":"water","meter":"weh_07","name":"Vatten","id":"86868686","total_m3":0.016,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
|
||||
# Test Zenner Minomess C1 water meter
|
||||
telegram=|6644496A1064035514377251345015496A0007EE0050052F2F|0C1359000000026CBE2B82046CA12B8C0413FFFFFFFF8D0493132CFBFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02FD1700002F2F|
|
||||
{"media":"water","meter":"minomess","name":"Mino","id":"15503451","total_m3":0.059,"meter_date":"2021-11-30","target_m3":0,"target_date":"2021-11-01","status":"OK","timestamp":"1111-11-11T11:11:11Z"}
|
||||
|
|
|
@ -82,6 +82,7 @@
|
|||
X(LSE_07_17, MANUFACTURER_LSE, 0x07, 0x17) \
|
||||
X(LSE_07_17, MANUFACTURER_QDS, 0x37, 0x33) \
|
||||
X(LSE_08, MANUFACTURER_LSE, 0x08, 0x01) \
|
||||
X(MINOMESS, MANUFACTURER_ZRI, 0x07, 0x00) \
|
||||
X(MKRADIO3, MANUFACTURER_TCH, 0x62, 0x74) \
|
||||
X(MKRADIO3, MANUFACTURER_TCH, 0x72, 0x74) \
|
||||
X(MKRADIO4, MANUFACTURER_TCH, 0x62, 0x95) \
|
||||
|
|
|
@ -0,0 +1,235 @@
|
|||
/*
|
||||
Copyright (C) 2021 Olli Salonen
|
||||
|
||||
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"
|
||||
|
||||
struct MeterMinomess : public virtual WaterMeter, public virtual MeterCommonImplementation {
|
||||
MeterMinomess(MeterInfo &mi);
|
||||
|
||||
// Total water counted through the meter
|
||||
double totalWaterConsumption(Unit u);
|
||||
bool hasTotalWaterConsumption();
|
||||
|
||||
double targetWaterConsumption(Unit u);
|
||||
bool hasTargetWaterConsumption();
|
||||
|
||||
private:
|
||||
|
||||
string status();
|
||||
uint16_t info_codes_ {};
|
||||
void processContent(Telegram *t);
|
||||
|
||||
double total_water_consumption_m3_ {};
|
||||
string meter_date_ {};
|
||||
double target_water_consumption_m3_ {};
|
||||
string target_water_consumption_date_ {};
|
||||
bool has_target_water_consumption_ {};
|
||||
|
||||
};
|
||||
|
||||
MeterMinomess::MeterMinomess(MeterInfo &mi) :
|
||||
MeterCommonImplementation(mi, MeterDriver::MINOMESS)
|
||||
{
|
||||
setExpectedELLSecurityMode(ELLSecurityMode::AES_CTR);
|
||||
|
||||
addLinkMode(LinkMode::C1);
|
||||
|
||||
addPrint("total", Quantity::Volume,
|
||||
[&](Unit u){ return totalWaterConsumption(u); },
|
||||
"The total water consumption recorded by this meter.",
|
||||
true, true);
|
||||
|
||||
addPrint("meter_date", Quantity::Text,
|
||||
[&](){ return meter_date_; },
|
||||
"Date when measurement was recorded.",
|
||||
false, true);
|
||||
|
||||
addPrint("target", Quantity::Volume,
|
||||
[&](Unit u){ return targetWaterConsumption(u); },
|
||||
"The total water consumption recorded at the beginning of this month.",
|
||||
true, true);
|
||||
|
||||
addPrint("target_date", Quantity::Text,
|
||||
[&](){ return target_water_consumption_date_; },
|
||||
"Date when target water consumption was recorded.",
|
||||
false, true);
|
||||
|
||||
addPrint("status", Quantity::Text,
|
||||
[&](){ return status(); },
|
||||
"Status of meter.",
|
||||
true, true);
|
||||
|
||||
}
|
||||
|
||||
shared_ptr<WaterMeter> createMinomess(MeterInfo &mi)
|
||||
{
|
||||
return shared_ptr<WaterMeter>(new MeterMinomess(mi));
|
||||
}
|
||||
|
||||
double MeterMinomess::totalWaterConsumption(Unit u)
|
||||
{
|
||||
assertQuantity(u, Quantity::Volume);
|
||||
return convert(total_water_consumption_m3_, Unit::M3, u);
|
||||
}
|
||||
|
||||
bool MeterMinomess::hasTotalWaterConsumption()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
double MeterMinomess::targetWaterConsumption(Unit u)
|
||||
{
|
||||
assertQuantity(u, Quantity::Volume);
|
||||
return convert(target_water_consumption_m3_, Unit::M3, u);
|
||||
}
|
||||
|
||||
bool MeterMinomess::hasTargetWaterConsumption()
|
||||
{
|
||||
return has_target_water_consumption_;
|
||||
}
|
||||
|
||||
void MeterMinomess::processContent(Telegram *t)
|
||||
{
|
||||
// 00: 66 length (102 bytes)
|
||||
// 01: 44 dll-c (from meter SND_NR)
|
||||
// 02: 496a dll-mfct (ZRI)
|
||||
// 04: 10640355 dll-id (55036410)
|
||||
// 08: 14 dll-version
|
||||
// 09: 37 dll-type (Radio converter (meter side))
|
||||
// 0a: 72 tpl-ci-field (EN 13757-3 Application Layer (long tplh))
|
||||
// 0b: 51345015 tpl-id (15503451)
|
||||
// 0f: 496a tpl-mfct (ZRI)
|
||||
// 11: 00 tpl-version
|
||||
// 12: 07 tpl-type (Water meter)
|
||||
// 13: 76 tpl-acc-field
|
||||
// 14: 00 tpl-sts-field (OK)
|
||||
// 15: 5005 tpl-cfg 0550 (AES_CBC_IV nb=5 cntn=0 ra=0 hc=0 )
|
||||
// 17: 2f2f decrypt check bytes
|
||||
|
||||
// 19: 0C dif (8 digit BCD Instantaneous value)
|
||||
// 1a: 13 vif (Volume l)
|
||||
// 1b: * 55140000 total consumption (1.455000 m3)
|
||||
// 1f: 02 dif (16 Bit Integer/Binary Instantaneous value)
|
||||
// 20: 6C vif (Date type G)
|
||||
// 21: * A92B meter date (2021-11-09)
|
||||
// 23: 82 dif (16 Bit Integer/Binary Instantaneous value)
|
||||
// 24: 04 dife (subunit=0 tariff=0 storagenr=8)
|
||||
// 25: 6C vif (Date type G)
|
||||
// 26: * A12B target consumption reading date (2021-11-01)
|
||||
// 28: 8C dif (8 digit BCD Instantaneous value)
|
||||
// 29: 04 dife (subunit=0 tariff=0 storagenr=8)
|
||||
// 2a: 13 vif (Volume l)
|
||||
// 2b: * 71000000 target consumption (0.071000 m3)
|
||||
//
|
||||
// 2f: 8D dif (variable length Instantaneous value)
|
||||
// 30: 04 dife (subunit=0 tariff=0 storagenr=8)
|
||||
// 31: 93 vif (Volume l)
|
||||
// 32: 13 vife (Reverse compact profile without register)
|
||||
// 33: 2C varlen=44
|
||||
// This register has 24-bit integers for the consumption of the past months n-2 until n-15.
|
||||
// If the meter is commissioned less than 15 months ago, you will see FFFFFF as the value.
|
||||
// n-2 n-3 n-4 n-5 n-6 n-7 n-8 n-9 n-10 n-11 n-12 n-13 n-14 n-15
|
||||
// 34: FBFE 000000 FFFFFF FFFFFF FFFFFF FFFFFF FFFFFF FFFFFF FFFFFF FFFFFF FFFFFF FFFFFF FFFFFF FFFFFF FFFFFF
|
||||
//
|
||||
// 60: 02 dif (16 Bit Integer/Binary Instantaneous value)
|
||||
// 61: FD vif (Second extension FD of VIF-codes)
|
||||
// 62: 17 vife (Error flags (binary))
|
||||
// 63: * 0000 info codes (OK)
|
||||
|
||||
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::Date, 0, 0, &key, &t->values)) {
|
||||
struct tm date;
|
||||
extractDVdate(&t->values, key, &offset, &date);
|
||||
meter_date_ = strdate(&date);
|
||||
t->addMoreExplanation(offset, " meter date (%s)", meter_date_.c_str());
|
||||
}
|
||||
|
||||
if (findKey(MeasurementType::Instantaneous, ValueInformation::Volume, 8, 0, &key, &t->values)) {
|
||||
uint32_t i;
|
||||
extractDVdouble(&t->values, key, &offset, &target_water_consumption_m3_);
|
||||
extractDVuint32(&t->values, key, &offset, &i);
|
||||
/* if the meter is recently commissioned, the target water consumption value is bogus */
|
||||
if (i != 0xffffffff) {
|
||||
has_target_water_consumption_ = true;
|
||||
} else {
|
||||
target_water_consumption_m3_ = 0;
|
||||
}
|
||||
t->addMoreExplanation(offset, " target consumption (%f m3)", target_water_consumption_m3_);
|
||||
}
|
||||
|
||||
if (findKey(MeasurementType::Instantaneous, ValueInformation::Date, 8, 0, &key, &t->values)) {
|
||||
struct tm date;
|
||||
extractDVdate(&t->values, key, &offset, &date);
|
||||
target_water_consumption_date_ = strdate(&date);
|
||||
t->addMoreExplanation(offset, " target consumption reading date (%s)", target_water_consumption_date_.c_str());
|
||||
}
|
||||
|
||||
if (extractDVuint16(&t->values, "02FD17", &offset, &info_codes_)) {
|
||||
t->addMoreExplanation(offset, " info codes (%s)", status().c_str());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
string MeterMinomess::status()
|
||||
{
|
||||
/*
|
||||
To-Do: Implement status handling
|
||||
According to data sheet, there are two status/info bytes, byte A and byte B.
|
||||
|
||||
Byte A:
|
||||
bit 7 removal active in the past
|
||||
bit 6 tamper active in the past
|
||||
bit 5 leak active in the past
|
||||
bit 4 temporary error (in connection with smart functions)
|
||||
bit 3 permanent error (meter value might be lost)
|
||||
bit 2 battery EOL (measured)
|
||||
bit 1 abnormal error
|
||||
bit 0 unused
|
||||
|
||||
Byte B:
|
||||
bit 7 burst
|
||||
bit 6 removal
|
||||
bit 5 leak
|
||||
bit 4 backflow in the past
|
||||
bit 3 backflow
|
||||
bit 2 meter blocked in the past
|
||||
bit 1 meter undersized
|
||||
bit 0 meter oversized
|
||||
*/
|
||||
|
||||
string s;
|
||||
|
||||
if (info_codes_ == 0) return "OK";
|
||||
|
||||
s = tostrprintf("%x", info_codes_);
|
||||
if (s.length() > 0) {
|
||||
s.pop_back(); // Remove final space
|
||||
return s;
|
||||
}
|
||||
return s;
|
||||
}
|
|
@ -65,6 +65,7 @@
|
|||
X(lansendw, T1_bit, DoorWindowDetector, LANSENDW, LansenDW) \
|
||||
X(lansenpu, T1_bit, PulseCounter, LANSENPU, LansenPU) \
|
||||
X(lse_07_17, S1_bit, WaterMeter, LSE_07_17, LSE_07_17) \
|
||||
X(minomess, C1_bit, WaterMeter, MINOMESS, Minomess) \
|
||||
X(mkradio3, T1_bit, WaterMeter, MKRADIO3, MKRadio3) \
|
||||
X(mkradio4, T1_bit, WaterMeter, MKRADIO4, MKRadio4) \
|
||||
X(multical21, C1_bit|T1_bit, WaterMeter, MULTICAL21, Multical21) \
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
name=Mino
|
||||
type=minomess
|
||||
id=55036410
|
|
@ -25,6 +25,7 @@ $PROG --format=json simulations/simulation_c1.txt \
|
|||
myomnipower omnipower 32666857 NOKEY \
|
||||
Smokey ei6500 00012811 NOKEY \
|
||||
Vatten weh_07 86868686 NOKEY \
|
||||
Mino minomess 55036410 NOKEY \
|
||||
> $TEST/test_output.txt 2> $TEST/test_stderr.txt
|
||||
|
||||
if [ "$?" = "0" ]
|
||||
|
|
Ładowanie…
Reference in New Issue