/* Copyright (C) 2021 Olli Salonen (gpl-3.0-or-later)
Copyright (C) 2022-2026 Fredrik Öhrström (gpl-3.0-or-later)
Copyright (C) 2026 Hynek Moravec (gpl-3.0-or-later) */
driver {
name = minomess
meter_type = WaterMeter
default_fields = name,id,status,total_m3,target_m3,timestamp
manufacturer = Zenner
detect {
mvt = ZRI,00,07
mvt = ZRI,01,16
mvt = ZRI,01,06
}
mfct_tpl_status_bits {
mask_bits = 0xf8
default_message = OK
map {
name = PERMANENT_ERROR
value = 0x08
test = Set
}
map {
name = TEMPORARY_ERROR
value = 0x10
test = Set
}
map {
name = WAS_LEAKING
value = 0x20
test = Set
}
map {
name = WAS_TAMPERED
value = 0x40
test = Set
}
map {
name = WAS_REMOVED
value = 0x80
test = Set
}
}
library {
use = total_m3
use = meter_date
use = meter_datetime
use = fabrication_no
use = operating_time_h
use = on_time_h
use = on_time_at_error_h
use = total_backward_m3
use = volume_flow_m3h
use = rssi_dbm
}
flags {
flag {
name = WAS_LEAKING
info = 'A leak was detected earlier.'
}
flag {
name = WAS_TAMPERED
info = 'Tampering was detected earlier.'
}
flag {
name = WAS_REMOVED
info = 'The removal of the meter was detected earlier.'
}
flag {
name = BURSTING
info = 'A pipe burst has been detected.'
}
flag {
name = REMOVED
info = 'The meter has been removed.'
}
flag {
name = LEAKING
info = 'A leak has been detected.'
}
flag {
name = WAS_BACKFLOWING
info = 'A backflow was detected earlier.'
}
flag {
name = BACKFLOWING
info = 'The water flows through the meter in the wrong direction.'
}
flag {
name = WAS_BLOCKED
info = 'The meter was blocked earlier.'
}
flag {
name = UNDERSIZED
info = 'The meter is undersized for the flow, the flow is above its maximum.'
}
flag {
name = OVERSIZED
info = 'The meter is oversized for the flow, the flow is below its minimum.'
}
flag {
name = BATTERY_EOL
info = 'The battery has reached its end of life.'
}
flag {
name = ABNORMAL_CONDITION
info = 'The meter reports an abnormal condition.'
}
}
fields {
field {
// The meter sends 8C0413 with DIF 0C (8 digit BCD) but the value is a
// binary uint32 (litres). Re-key the bytes as 840413 (32 bit integer).
// FFFFFFFF (not set) is not re-keyed.
name = target_raw
quantity = Text
attributes = HIDE
info = 'Target volume sent as binary despite the BCD DIF.'
match {
difvifkey = 8C0413
}
ixml = "decode = 'FFFFFFFF' | target.
target = byte, byte, byte, msb, @DV_840413.
-msb = hex, nf | nf, 'F'.
-nf = ['A'-'E';'0'-'9'].
-hex = ['A'-'F';'0'-'9'].
-byte = hex, hex.
DV_840413>dvk = +'840413'."
}
field {
name = target
quantity = Volume
info = 'The total water consumption recorded at the beginning of this month.'
null_value = -2147483.648
match {
difvifkey = 840413
}
}
field {
name = target
quantity = PointInTime
info = 'Date when target water consumption was recorded.'
display_unit = date
match {
measurement_type = Instantaneous
vif_range = Date
storage_nr = 8
}
}
field {
name = target
quantity = Volume
info = 'The total water consumption recorded at the beginning of this month.'
match {
measurement_type = Instantaneous
vif_range = Volume
storage_nr = 1
}
}
field {
name = target
quantity = PointInTime
info = 'Date when target water consumption was recorded.'
display_unit = date
match {
measurement_type = Instantaneous
vif_range = Date
storage_nr = 1
}
}
field {
name = status
quantity = Flags
info = 'Status and error flags.'
attributes = STATUS,INCLUDE_TPL_STATUS
match {
difvifkey = 02FD17
}
lookup {
name = ERROR_FLAGS
map_type = BitToString
mask_bits = 0xffff
default_message = OK
// Status byte B (high byte)
map {
name = BURSTING
value = 0x8000
test = Set
}
map {
name = REMOVED
value = 0x4000
test = Set
}
map {
name = LEAKING
value = 0x2000
test = Set
}
map {
name = WAS_BACKFLOWING
value = 0x1000
test = Set
}
map {
name = BACKFLOWING
value = 0x0800
test = Set
}
map {
name = WAS_BLOCKED
value = 0x0400
test = Set
}
map {
name = UNDERSIZED
value = 0x0200
test = Set
}
map {
name = OVERSIZED
value = 0x0100
test = Set
}
// Status byte A (low byte)
map {
name = WAS_REMOVED
value = 0x0080
test = Set
}
map {
name = WAS_TAMPERED
value = 0x0040
test = Set
}
map {
name = WAS_LEAKING
value = 0x0020
test = Set
}
map {
name = TEMPORARY_ERROR
value = 0x0010
test = Set
}
map {
name = PERMANENT_ERROR
value = 0x0008
test = Set
}
map {
name = BATTERY_EOL
value = 0x0004
test = Set
}
map {
name = ABNORMAL_CONDITION
value = 0x0002
test = Set
}
}
}
}
tests {
test {
args = 'MBusRSSI minomess 15363320 NOKEY'
telegram = 685F5F6808007220333615496A0116A30000000C1397750500026C513A82046C413A8C0413AADB00008D0493132C33FED0D200A6CD007EC8009CC10048BA00FAB3009BAD00D2A80028A2004F9B00F694009B8F00F9890048860002FD17000001FD71AAE716
json = '{"_":"telegram","media":"cold water","driver":"minomess","name":"MBusRSSI","id":"15363320","rssi_dbm":-86,"target_m3":21.987,"target_date":"2026-10-01","total_m3":57.597,"meter_date":"2026-10-17","status":"OK","timestamp":"1111-11-11T11:11:11Z"}'
fields = 'MBusRSSI;15363320;OK;57.597;21.987;1111-11-11 11:11.11'
}
test {
args = 'Mino minomess 15503451 NOKEY'
telegram = 6644496A1064035514377251345015496A0007EE0050052F2F_0C1359000000026CBE2B82046CA12B8C0413FFFFFFFF8D0493132CFBFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02FD1700002F2F
json = '{"_":"telegram","media":"water","driver":"minomess","name":"Mino","id":"15503451","meter_date":"2021-11-30","total_m3":0.059,"target_date":"2021-11-01","status":"OK","timestamp":"1111-11-11T11:11:11Z"}'
fields = 'Mino;15503451;OK;0.059;null;1111-11-11 11:11.11'
}
test {
args = 'Zenner_cold minomess 21314151 NOKEY'
telegram = 6644496A4425155518377251413121496A0116360050052F2F_0C1355000000026CEC2182046CE1218C0413000000808D0493132C33FE00008000008000008000008000008000008000008000008000008000008000008000008000008000008002FD1700002F2F
json = '{"_":"telegram","media":"cold water","driver":"minomess","name":"Zenner_cold","id":"21314151","meter_date":"2023-01-12","total_m3":0.055,"target_m3":null,"target_date":"2023-01-01","status":"OK","timestamp":"1111-11-11T11:11:11Z"}'
fields = 'Zenner_cold;21314151;OK;0.055;null;1111-11-11 11:11.11'
}
test {
args = 'Zenner_warm minomess 51413121 NOKEY'
telegram = 6644496A8753155518377221314151496A0106300050052F2F_0C1357000000026CEC2182046CE1218C0413000000808D0493132C33FE00008000008000008000008000008000008000008000008000008000008000008000008000008000008002FD1700002F2F
json = '{"_":"telegram","media":"warm water","driver":"minomess","name":"Zenner_warm","id":"51413121","meter_date":"2023-01-12","total_m3":0.057,"target_m3":null,"target_date":"2023-01-01","status":"OK","timestamp":"1111-11-11T11:11:11Z"}'
fields = 'Zenner_warm;51413121;OK;0.057;null;1111-11-11 11:11.11'
}
test {
args = 'Zenner_warm2 minomess 12345678 NOKEY'
comment = 'Target 8C0413 sent as binary uint32 litres: F51C0200 = 138485 l.'
telegram = 6644496A7856341218377278563412496A01067D0050052F2F_0C1354031400026C4F3A82046C413A8C0413F51C02008D0493132C33FEEE0F020D05021EFA018CED010CE0013ED401FFC601A9B701E2A2011B94014884011D7401FC6601EA5A0102FD1700002F2F
json = '{"_":"telegram","media":"warm water","driver":"minomess","name":"Zenner_warm2","id":"12345678","meter_date":"2026-10-15","total_m3":140.354,"target_m3":138.485,"target_date":"2026-10-01","status":"OK","timestamp":"1111-11-11T11:11:11Z"}'
fields = 'Zenner_warm2;12345678;OK;140.354;138.485;1111-11-11 11:11.11'
}
}
}