/* 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'
        }
    }
}