/* Copyright (C) 2018-2025 Fredrik Öhrström (gpl-3.0-or-later)
   Copyright (C)      2020 Eric Bus (gpl-3.0-or-later)
   Copyright (C)      2022 thecem (gpl-3.0-or-later) */
driver {
    name           = kamheat
    aliases        = multical302,multical303,multical403,multical602,multical603,multical803
    default_fields = name,id,total_energy_consumption_kwh,total_volume_m3,status,timestamp
    meter_type     = HeatMeter
    manufacturer   = Kamstrup
    detect {
        mvt = KAM,30,04
        // 302
        mvt = KAM,30,0d
        // 302
        mvt = KAM,30,0c
        // 302
        mvt = KAM,40,04
        // 303
        mvt = KAM,40,0c
        // 303
        mvt = KAM,40,0d
        // 303 heat&cool
        mvt = KAM,19,04
        // 402
        mvt = KAM,34,04
        // 403
        mvt = KAM,34,0a
        // 403
        mvt = KAM,34,0b
        // 403
        mvt = KAM,34,0c
        // 403
        mvt = KAM,34,0d
        // 403
        mvt = KAM,1c,04
        // 602
        mvt = KAM,35,04
        // 603
        mvt = KAM,35,0c
        // 603
        mvt = KAM,35,0d
        // 603 heat&cool
        mvt = KAM,39,04
        // 803
    }
    compact_frame_formats {
        // KAM,1c,04
        difvif = 02F9FF15040604EEFF0704EEFF0804148440148480401402FD17026C426C44064414C44014C4804014043B0259025D
        // KAM,30,04
        difvif = 030643060314426C022D01FF21
        // KAM,30,0c
        difvif = 030E430E0313426C022D01FF21
        // KAM,34,0c
        difvif = 040604FF0704FF080414043B0259025D04FF22026C44064414426C
        // KAM,39,04
        difvif = 040F04FF0704FF08041484401484804014043B0259025D142D84100F84200F04FF22026C440F4414C44014C4804014426C
        // MC 303 heat
        difvif = 0406041404FF0704FF080259025D023B02FF22026C44064414426C
    }
    library {
        use = fabrication_no
        use = 'meter_date|(10/348/Date and time)'
        use = 'meter_datetime|(10/348/Date and time)'
        use = on_time_h
        use = on_time_at_error_h
        use = flow_return_temperature_difference_c
        use = 'target_date|(14/348/Date and Time logged)'
    }
    flags {
        flag {
            name = VOLTAGE_INTERRUPTED
            info = 'The supply voltage has been interrupted.'
        }
        flag {
            name = LOW_BATTERY_LEVEL
            info = 'The battery level is low.'
        }
        flag {
            name = SENSOR_ERROR
            info = 'A temperature sensor error has been detected.'
        }
        flag {
            name = SENSOR_T1_ABOVE_MEASURING_RANGE
            info = 'Temperature sensor T1 is above its measuring range.'
        }
        flag {
            name = SENSOR_T2_ABOVE_MEASURING_RANGE
            info = 'Temperature sensor T2 is above its measuring range.'
        }
        flag {
            name = SENSOR_T1_BELOW_MEASURING_RANGE
            info = 'Temperature sensor T1 is below its measuring range.'
        }
        flag {
            name = SENSOR_T2_BELOW_MEASURING_RANGE
            info = 'Temperature sensor T2 is below its measuring range.'
        }
        flag {
            name = TEMP_DIFF_WRONG_POLARITY
            info = 'The temperature difference between T1 and T2 has the wrong polarity.'
        }
        flag {
            name = FLOW_SENSOR_WEAK_OR_AIR
            info = 'The flow sensor signal is weak or there is air in the flow sensor.'
        }
        flag {
            name = WRONG_FLOW_DIRECTION
            info = 'The water flows through the flow sensor in the wrong direction.'
        }
        flag {
            name = FLOW_INCREASED
            info = 'The flow is above the maximum flow rate of the flow sensor.'
        }
        flag {
            name = IN_A1_LEAKAGE_IN_THE_SYSTEM
            info = 'Input A1 reports a leakage in the system.'
        }
        flag {
            name = IN_B1_LEAKAGE_IN_THE_SYSTEM
            info = 'Input B1 reports a leakage in the system.'
        }
        flag {
            name = IN_A1_A2_EXTERNAL_ALARM
            info = 'Input A1 or A2 reports an external alarm.'
        }
        flag {
            name = IN_B1_B2_EXTERNAL_ALARM
            info = 'Input B1 or B2 reports an external alarm.'
        }
        flag {
            name = V1_COMMUNICATION_ERROR
            info = 'The communication with flow sensor V1 has failed.'
        }
        flag {
            name = V1_WRONG_PULSE_FIGURE
            info = 'Flow sensor V1 has the wrong pulse figure.'
        }
        flag {
            name = IN_A2_LEAKAGE_IN_THE_SYSTEM
            info = 'Input A2 reports a leakage in the system.'
        }
        flag {
            name = IN_B2_LEAKAGE_IN_THE_SYSTEM
            info = 'Input B2 reports a leakage in the system.'
        }
        flag {
            name = T3_ABOVE_MEASURING_RANGE_OR_SWITCHED_OFF
            info = 'Temperature sensor T3 is above its measuring range or switched off.'
        }
        flag {
            name = T3_BELOW_MEASURING_RANGE_OR_SWITCHED_OFF
            info = 'Temperature sensor T3 is below its measuring range or switched off.'
        }
        flag {
            name = V2_COMMUNICATION_ERROR
            info = 'The communication with flow sensor V2 has failed.'
        }
        flag {
            name = V2_WRONG_PULSE_FIGURE
            info = 'Flow sensor V2 has the wrong pulse figure.'
        }
        flag {
            name = V2_AIR
            info = 'There is air in flow sensor V2.'
        }
        flag {
            name = V2_WRONG_FLOW_DIRECTION
            info = 'The water flows through flow sensor V2 in the wrong direction.'
        }
        flag {
            name = V2_INCREASED_FLOW
            info = 'The flow in flow sensor V2 is above its maximum flow rate.'
        }
        flag {
            name = V1_V2_BURST_WATER_LOSS
            info = 'The difference between V1 and V2 indicates a burst with water loss.'
        }
        flag {
            name = V1_V2_BURST_WATER_PENETRATION
            info = 'The difference between V1 and V2 indicates a burst with water penetration.'
        }
        flag {
            name = V1_V2_LEAKAGE_WATER_LOSS
            info = 'The difference between V1 and V2 indicates a leakage with water loss.'
        }
        flag {
            name = V1_V2_LEAKAGE_WATER_PENETRATION
            info = 'The difference between V1 and V2 indicates a leakage with water penetration.'
        }
        flag {
            name = SENSOR_T1_OUTSIDE_MEASURING_RANGE
            info = 'Temperature sensor T1 is outside its measuring range.'
        }
        flag {
            name = SENSOR_T2_OUTSIDE_MEASURING_RANGE
            info = 'Temperature sensor T2 is outside its measuring range.'
        }
        flag {
            name = SENSOR_T3_OUTSIDE_MEASURING_RANGE
            info = 'Temperature sensor T3 is outside its measuring range.'
        }
        flag {
            name = LEAKAGE_COLD_WATER
            info = 'A leakage in the cold water system has been detected.'
        }
        flag {
            name = LEAKAGE_HOT_WATER
            info = 'A leakage in the hot water system has been detected.'
        }
        flag {
            name = BURST_WATER_LOSS
            info = 'A burst with water loss has been detected.'
        }
        flag {
            name = V1_AIR
            info = 'There is air in flow sensor V1.'
        }
        flag {
            name = V1_WRONG_FLOW_DIRECTION
            info = 'The water flows through flow sensor V1 in the wrong direction.'
        }
    }
    fields {
        field {
            name       = status
            quantity   = Flags
            info       = 'Status and error flags'
            attributes = STATUS,INCLUDE_TPL_STATUS
            match {
                difvifkey = 04FF22
            }
            lookup {
                name            = ERROR_FLAGS
                map_type        = BitToString
                mask_bits       = 0xffffffff
                default_message = OK
                map {
                    name = VOLTAGE_INTERRUPTED
                    bit  = 0
                    test = Set
                }
                map {
                    name = LOW_BATTERY_LEVEL
                    bit  = 1
                    test = Set
                }
                map {
                    name = SENSOR_ERROR
                    bit  = 2
                    test = Set
                }
                map {
                    name = SENSOR_T1_ABOVE_MEASURING_RANGE
                    bit  = 3
                    test = Set
                }
                map {
                    name = SENSOR_T2_ABOVE_MEASURING_RANGE
                    bit  = 4
                    test = Set
                }
                map {
                    name = SENSOR_T1_BELOW_MEASURING_RANGE
                    bit  = 5
                    test = Set
                }
                map {
                    name = SENSOR_T2_BELOW_MEASURING_RANGE
                    bit  = 6
                    test = Set
                }
                map {
                    name = TEMP_DIFF_WRONG_POLARITY
                    bit  = 7
                    test = Set
                }
                map {
                    name = FLOW_SENSOR_WEAK_OR_AIR
                    bit  = 8
                    test = Set
                }
                map {
                    name = WRONG_FLOW_DIRECTION
                    bit  = 9
                    test = Set
                }
                // bit 10 is reserved
                map {
                    name = FLOW_INCREASED
                    bit  = 11
                    test = Set
                }
                map {
                    name = IN_A1_LEAKAGE_IN_THE_SYSTEM
                    bit  = 12
                    test = Set
                }
                map {
                    name = IN_B1_LEAKAGE_IN_THE_SYSTEM
                    bit  = 13
                    test = Set
                }
                map {
                    name = IN_A1_A2_EXTERNAL_ALARM
                    bit  = 14
                    test = Set
                }
                map {
                    name = IN_B1_B2_EXTERNAL_ALARM
                    bit  = 15
                    test = Set
                }
                map {
                    name = V1_COMMUNICATION_ERROR
                    bit  = 16
                    test = Set
                }
                map {
                    name = V1_WRONG_PULSE_FIGURE
                    bit  = 17
                    test = Set
                }
                map {
                    name = IN_A2_LEAKAGE_IN_THE_SYSTEM
                    bit  = 18
                    test = Set
                }
                map {
                    name = IN_B2_LEAKAGE_IN_THE_SYSTEM
                    bit  = 19
                    test = Set
                }
                map {
                    name = T3_ABOVE_MEASURING_RANGE_OR_SWITCHED_OFF
                    bit  = 20
                    test = Set
                }
                map {
                    name = T3_BELOW_MEASURING_RANGE_OR_SWITCHED_OFF
                    bit  = 21
                    test = Set
                }
                map {
                    name = V2_COMMUNICATION_ERROR
                    bit  = 22
                    test = Set
                }
                map {
                    name = V2_WRONG_PULSE_FIGURE
                    bit  = 23
                    test = Set
                }
                map {
                    name = V2_AIR
                    bit  = 24
                    test = Set
                }
                map {
                    name = V2_WRONG_FLOW_DIRECTION
                    bit  = 25
                    test = Set
                }
                // bit 26 is reserved
                map {
                    name = V2_INCREASED_FLOW
                    bit  = 27
                    test = Set
                }
                map {
                    name = V1_V2_BURST_WATER_LOSS
                    bit  = 28
                    test = Set
                }
                map {
                    name = V1_V2_BURST_WATER_PENETRATION
                    bit  = 29
                    test = Set
                }
                map {
                    name = V1_V2_LEAKAGE_WATER_LOSS
                    bit  = 30
                    test = Set
                }
                map {
                    name = V1_V2_LEAKAGE_WATER_PENETRATION
                    bit  = 31
                    test = Set
                }
            }
        }
        field {
            name       = status16
            quantity   = Flags
            info       = 'Status and error flags'
            attributes = INJECT_INTO_STATUS,HIDE
            match {
                difvifkey = 02FF22
            }
            lookup {
                name            = ERROR_FLAGS
                map_type        = BitToString
                mask_bits       = 0xffff
                default_message = OK
                map {
                    name = VOLTAGE_INTERRUPTED
                    bit  = 0
                    test = Set
                }
                map {
                    name = LOW_BATTERY_LEVEL
                    bit  = 1
                    test = Set
                }
                // bit 2 is reserved
                map {
                    name = SENSOR_T1_ABOVE_MEASURING_RANGE
                    bit  = 3
                    test = Set
                }
                map {
                    name = SENSOR_T2_ABOVE_MEASURING_RANGE
                    bit  = 4
                    test = Set
                }
                map {
                    name = SENSOR_T1_BELOW_MEASURING_RANGE
                    bit  = 5
                    test = Set
                }
                map {
                    name = SENSOR_T2_BELOW_MEASURING_RANGE
                    bit  = 6
                    test = Set
                }
                map {
                    name = TEMP_DIFF_WRONG_POLARITY
                    bit  = 7
                    test = Set
                }
                map {
                    name = FLOW_SENSOR_WEAK_OR_AIR
                    bit  = 8
                    test = Set
                }
                map {
                    name = WRONG_FLOW_DIRECTION
                    bit  = 9
                    test = Set
                }
                // bit 10 is reserved
                map {
                    name = FLOW_INCREASED
                    bit  = 11
                    test = Set
                }
                // bits 12-15 are reserved
            }
        }
        field {
            name       = status_narrow
            quantity   = Flags
            info       = 'Status and error flags'
            attributes = INJECT_INTO_STATUS,HIDE
            match {
                measurement_type = Instantaneous
                vif_range        = ErrorFlags
            }
            lookup {
                name            = NARROW_ERROR_FLAGS
                map_type        = BitToString
                mask_bits       = 0xffff
                default_message = OK
                map {
                    name = VOLTAGE_INTERRUPTED
                    bit  = 0
                    test = Set
                }
                map {
                    name = SENSOR_T1_OUTSIDE_MEASURING_RANGE
                    bit  = 3
                    test = Set
                }
                map {
                    name = SENSOR_T2_OUTSIDE_MEASURING_RANGE
                    bit  = 2
                    test = Set
                }
                map {
                    name = SENSOR_T3_OUTSIDE_MEASURING_RANGE
                    bit  = 5
                    test = Set
                }
                map {
                    name = LEAKAGE_COLD_WATER
                    bit  = 6
                    test = Set
                }
                map {
                    name = LEAKAGE_HOT_WATER
                    bit  = 8
                    test = Set
                }
                map {
                    name = BURST_WATER_LOSS
                    bit  = 9
                    test = Set
                }
                map {
                    name = V1_COMMUNICATION_ERROR
                    bit  = 4
                    test = Set
                }
                map {
                    name = V2_COMMUNICATION_ERROR
                    bit  = 10
                    test = Set
                }
                map {
                    name = V1_WRONG_PULSE_FIGURE
                    bit  = 11
                    test = Set
                }
                map {
                    name = V2_WRONG_PULSE_FIGURE
                    bit  = 7
                    test = Set
                }
                map {
                    name = V1_AIR
                    bit  = 12
                    test = Set
                }
                map {
                    name = V2_AIR
                    bit  = 13
                    test = Set
                }
                map {
                    name = V1_WRONG_FLOW_DIRECTION
                    bit  = 14
                    test = Set
                }
                map {
                    name = V2_WRONG_FLOW_DIRECTION
                    bit  = 15
                    test = Set
                }
            }
        }
        field {
            name     = total_energy_consumption
            quantity = Energy
            change   = Increasing
            info     = 'The total energy consumption recorded by this meter.'
            match {
                measurement_type = Instantaneous
                vif_range        = AnyEnergyVIF
            }
        }
        field {
            name     = total_energy_backward
            quantity = Energy
            change   = Increasing
            info     = 'The total backwards energy consumption recorded by this meter.'
            match {
                measurement_type = Instantaneous
                vif_range        = AnyEnergyVIF
                add_combinable   = BackwardFlow
            }
        }
        field {
            name     = total_volume
            quantity = Volume
            change   = Increasing
            info     = 'The volume of water (3/68/Volume V1).'
            match {
                measurement_type = Instantaneous
                vif_range        = Volume
            }
        }
        field {
            name     = 'total_volume_subunit{subunit_counter}'
            quantity = Volume
            change   = Increasing
            info     = 'The volume of water for a subunit.'
            match {
                measurement_type = Instantaneous
                vif_range        = Volume
                subunit_nr       = 1,4
            }
        }
        field {
            name     = volume_flow
            quantity = Flow
            info     = 'The actual amount of water that pass through this meter (8/74/Flow V1 actual).'
            match {
                measurement_type = Instantaneous
                vif_range        = VolumeFlow
            }
        }
        field {
            name     = power
            quantity = Power
            info     = 'The current power flowing.'
            match {
                measurement_type = Instantaneous
                vif_range        = AnyPowerVIF
            }
        }
        field {
            name     = max_power
            quantity = Power
            info     = 'The maximum power supplied.'
            match {
                measurement_type = Maximum
                vif_range        = AnyPowerVIF
            }
        }
        field {
            name     = t1_temperature
            quantity = Temperature
            info     = 'The forward temperature of the water (6/86/t2 actual 2 decimals).'
            match {
                measurement_type = Instantaneous
                vif_range        = FlowTemperature
            }
        }
        field {
            name     = t2_temperature
            quantity = Temperature
            info     = 'The return temperature of the water (7/87/t2 actual 2 decimals).'
            match {
                measurement_type = Instantaneous
                vif_range        = ReturnTemperature
            }
        }
        field {
            name     = max_flow
            quantity = Flow
            info     = 'The maximum flow of water that passed through this meter.'
            match {
                measurement_type = Maximum
                vif_range        = VolumeFlow
            }
        }
        field {
            name         = forward_energy
            quantity     = Energy
            info         = 'The forward energy of the water (4/97/Energy E8).'
            vif_scaling  = None
            display_unit = m3c
            match {
                difvifkey = 04FF07
            }
        }
        field {
            name         = return_energy
            quantity     = Energy
            info         = 'The return energy of the water (5/110/Energy E9).'
            vif_scaling  = None
            display_unit = m3c
            match {
                difvifkey = 04FF08
            }
        }
        field {
            name     = total_energy_cooling
            quantity = Energy
            change   = Increasing
            info     = 'The cooling energy E3 of a combined heat and cooling meter (63/E3 HC).'
            match {
                measurement_type = Instantaneous
                vif_range        = AnyEnergyVIF
                add_combinable   = Mfct02
            }
        }
        field {
            name     = target_energy_cooling
            quantity = Energy
            info     = 'The cooling energy E3 of a combined heat and cooling meter at the set date.'
            match {
                measurement_type = Instantaneous
                vif_range        = AnyEnergyVIF
                add_combinable   = Mfct02
                storage_nr       = 1
            }
        }
        field {
            name         = target_forward_energy
            quantity     = Energy
            info         = 'The forward energy E8 at the set date.'
            vif_scaling  = None
            display_unit = m3c
            match {
                difvifkey = 44FF07
            }
        }
        field {
            name         = target_return_energy
            quantity     = Energy
            info         = 'The return energy E9 at the set date.'
            vif_scaling  = None
            display_unit = m3c
            match {
                difvifkey = 44FF08
            }
        }
        field {
            name     = target_max_power
            quantity = Power
            info     = 'The maximum power at the set date.'
            match {
                measurement_type = Maximum
                vif_range        = AnyPowerVIF
                storage_nr       = 1
            }
        }
        field {
            name     = target_max_flow
            quantity = Flow
            info     = 'The maximum flow at the set date.'
            match {
                measurement_type = Maximum
                vif_range        = VolumeFlow
                storage_nr       = 1
            }
        }
        field {
            name            = meter_type
            quantity        = Text
            info            = 'Kamstrup meter type and variant, e.g. 1B02 = MULTICAL 603 heat/cooling.'
            readable_string = Normal
            match {
                difvifkey = 02FF1A
            }
        }
        field {
            name         = module_type_config
            quantity     = Dimensionless
            info         = 'M-Bus module type, configuration and datagram profile, e.g. 2000101.'
            vif_scaling  = None
            display_unit = nr
            match {
                difvifkey = 04FF16
            }
        }
        field {
            name         = module_software
            quantity     = Dimensionless
            info         = 'M-Bus module software number and revision.'
            vif_scaling  = None
            display_unit = nr
            match {
                difvifkey = 04FF17
            }
        }
        field {
            name     = target_energy
            quantity = Energy
            info     = 'The energy consumption recorded by this meter at the set date (11/60/Heat energy E1/026C).'
            match {
                measurement_type = Instantaneous
                vif_range        = AnyEnergyVIF
                storage_nr       = 1
            }
        }
        field {
            name     = target_energy_backward
            quantity = Energy
            info     = 'The cooling energy consumption recorded by this meter at the set date (63 Cooling energy E3).'
            match {
                measurement_type = Instantaneous
                vif_range        = AnyEnergyVIF
                add_combinable   = BackwardFlow
                storage_nr       = 1
            }
        }
        field {
            name     = target_volume
            quantity = Volume
            info     = 'The amount of water that had passed through this meter at the set date (13/68/Volume V1).'
            match {
                measurement_type = Instantaneous
                vif_range        = Volume
                storage_nr       = 1
            }
        }
        field {
            name     = 'target_volume_subunit{subunit_counter}'
            quantity = Volume
            info     = 'The amount of water that had passed through a subunit of the meter at the set date.'
            match {
                measurement_type = Instantaneous
                vif_range        = Volume
                storage_nr       = 1
                subunit_nr       = 1,4
            }
        }
        field {
            name     = operating_time
            quantity = Time
            info     = 'How long the meter has been collecting data.'
            match {
                measurement_type = Instantaneous
                vif_range        = OperatingTime
                add_combinable   = Mfct21
            }
        }
        field {
            name            = enhanced_id
            quantity        = Text
            readable_string = Normal
            match {
                difvifkey = 02F9FF15
            }
        }
        field {
            name         = va
            quantity     = Dimensionless
            vif_scaling  = None
            display_unit = counter
            match {
                difvifkey = 04EEFF07
            }
        }
        field {
            name         = vb
            quantity     = Dimensionless
            vif_scaling  = None
            display_unit = counter
            match {
                difvifkey = 04EEFF08
            }
        }
    }
    tests {
        test {
            args     = 'MyHeater kamheat 67676767 NOKEY'
            comment  = Multical302
            telegram = 2E442D2C6767676730048D2039D1684020_BCDB7803062C000043060000000314630000426C7F2A022D130001FF2100
            json     = '{"_":"telegram","id": "67676767","media": "heat","driver": "kamheat","name": "MyHeater","power_kw": 1.9,"status": "OK","target_date": "2019-10-31","target_energy_kwh": 0,"timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 44,"total_volume_m3": 0.99}'
            fields   = 'MyHeater;67676767;44;0.99;OK;1111-11-11 11:11.11'
        }
        test {
            args     = 'MyHeater kamheat 67676767 NOKEY'
            comment  = 'Multical302 Test second compressed telegram.'
            telegram = 2E442D2C6767676730048D2039D1684020_BCDB7803062C000043060000000314630000426C7F2A022D130001FF2100,25442D2C6767676730048D203AD2684020_D81579E7F1D5902C00000000006300007F2A130000
            json     = '{"_":"telegram","id": "67676767","media": "heat","driver": "kamheat","name": "MyHeater","power_kw": 1.9,"status": "OK","target_date": "2019-10-31","target_energy_kwh": 0,"timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 44,"total_volume_m3": 0.99}'
            fields   = 'MyHeater;67676767;44;0.99;OK;1111-11-11 11:11.11'
        }
        test {
            args     = 'MyHeaterMj kamheat 46464646 NOKEY'
            comment  = 'Multical302 Using mj kwh'
            telegram = 2E442D2C46464646300C8D207A70EA6021B1C178_030FC51000430F9210000314072B05426CBE2B022D0C0001FF2100
            json     = '{"_":"telegram","id": "46464646","media": "heat volume at inlet","driver": "kamheat","name": "MyHeaterMj","power_kw": 1.2,"status": "OK","target_date": "2021-11-30","target_energy_kwh": 11783.333333,"timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 11925,"total_volume_m3": 3386.95}'
            fields   = 'MyHeaterMj;46464646;11925;3386.95;OK;1111-11-11 11:11.11'
        }
        test {
            args     = 'MyHeaterMj kamheat 46464646 NOKEY'
            comment  = 'Multical302 Test second compressed telegram.'
            telegram = 2E442D2C46464646300C8D207A70EA6021B1C178_030FC51000430F9210000314072B05426CBE2B022D0C0001FF2100,25442D2C46464646300C8D20D3E2EB60212B6D79E26DCD65_C51000921000152B05BE2B0C0000
            json     = '{"_":"telegram","id": "46464646","media": "heat volume at inlet","driver": "kamheat","name": "MyHeaterMj","power_kw": 1.2,"status": "OK","target_date": "2021-11-30","target_energy_kwh": 11783.333333,"timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 11925,"total_volume_m3": 3387.09}'
            fields   = 'MyHeaterMj;46464646;11925;3387.09;OK;1111-11-11 11:11.11'
        }
        test {
            args     = 'Heat kamheat 36363636 NOKEY'
            comment  = Multical603
            telegram = 42442D2C3636363635048D20E18025B62087D078_0406A500000004FF072B01000004FF089C000000041421020000043B120000000259D014025D000904FF2200000000
            json     = '{"_":"telegram","media":"heat","driver":"kamheat","name":"Heat","id":"36363636","status":"OK","total_energy_consumption_kwh":165,"total_volume_m3":5.45,"volume_flow_m3h":0.018,"t1_temperature_c":53.28,"t2_temperature_c":23.04,"forward_energy_m3c":299,"return_energy_m3c":156,"timestamp":"1111-11-11T11:11:11Z"}'
            fields   = 'Heat;36363636;165;5.45;OK;1111-11-11 11:11.11'
        }
        test {
            args     = 'HeatInlet kamheat 66666666 NOKEY'
            comment  = Multical603
            telegram = 5A442D2C66666666350C8D2066D0E16420C6A178_0406051C000004FF07393D000004FF08AE2400000414F7680000043B47000000042D1600000002596D14025DFD0804FF22000000000422E61A0000143B8C010000142D7C000000
            json     = '{"_":"telegram","media":"heat volume at inlet","driver":"kamheat","name":"HeatInlet","id":"66666666","on_time_h":6886,"status":"OK","total_energy_consumption_kwh":7173,"total_volume_m3":268.71,"volume_flow_m3h":0.071,"power_kw":2.2,"max_power_kw":12.4,"t1_temperature_c":52.29,"t2_temperature_c":23.01,"max_flow_m3h":0.396,"forward_energy_m3c":15673,"return_energy_m3c":9390,"timestamp":"1111-11-11T11:11:11Z"}'
            fields   = 'HeatInlet;66666666;7173;268.71;OK;1111-11-11 11:11.11'
        }
        test {
            args     = 'My403Cooling kamheat 78780102 NOKEY'
            comment  = Multical403
            telegram = 88442D2C02017878340A8D208D529C132037FC78_040E2D0A000004FF07F8FF000004FF08401801000413C1900500844014000000008480401400000000043BED0000000259BC06025DCD07142DE7FFFFFF84100E0000000084200E0000000004FF2200000000026C9228440E5F0300004413960D0200C4401400000000C480401400000000426C8128
            json     = '{"_":"telegram","forward_energy_m3c": 65528,"id": "78780102","max_power_kw": -2.5,"media": "cooling load volume at outlet","driver": "kamheat","meter_date": "2020-08-18","name": "My403Cooling","return_energy_m3c": 71744,"status": "OK","t1_temperature_c": 17.24,"t2_temperature_c": 19.97,"target_date": "2020-08-01","target_energy_kwh": 239.722222,"target_volume_m3": 134.55,"timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 723.611111,"total_volume_m3": 364.737,"volume_flow_m3h": 0.237,"target_volume_subunit1_m3": 0,"target_volume_subunit2_m3": 0,"total_volume_subunit1_m3": 0,"total_volume_subunit2_m3": 0,"timestamp": "1111-11-11T11:11:11Z"}'
            fields   = 'My403Cooling;78780102;723.611111;364.737;OK;1111-11-11 11:11.11'
        }
        test {
            args     = 'My403Cooling kamheat 78780102 NOKEY'
            comment  = Multical403
            telegram = 88442D2C02017878340A8D208D529C132037FC78_040E2D0A000004FF07F8FF000004FF08401801000413C1900500844014000000008480401400000000043BED0000000259BC06025DCD07142DE7FFFFFF84100E0000000084200E0000000004FF2200000000026C9228440E5F0300004413960D0200C4401400000000C480401400000000426C8128,5B442D2C02017878340A8D2096809C1320EF2B7934147ED7_2D0A0000FAFF000043180100CE9005000000000000000000EE000000BA06CB07E7FFFFFF00000000000000000000000092285F030000960D020000000000000000008128
            json     = '{"_":"telegram","forward_energy_m3c": 65530,"id": "78780102","max_power_kw": -2.5,"media": "cooling load volume at outlet","driver": "kamheat","meter_date": "2020-08-18","name": "My403Cooling","return_energy_m3c": 71747,"status": "OK","t1_temperature_c": 17.22,"t2_temperature_c": 19.95,"target_date": "2020-08-01","target_energy_kwh": 239.722222,"target_volume_m3": 134.55,"timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 723.611111,"total_volume_m3": 364.75,"volume_flow_m3h": 0.238,"target_volume_subunit1_m3": 0,"target_volume_subunit2_m3": 0,"total_volume_subunit1_m3": 0,"total_volume_subunit2_m3": 0}'
            fields   = 'My403Cooling;78780102;723.611111;364.75;OK;1111-11-11 11:11.11'
        }
        test {
            args     = 'Heato kamheat 78152801 NOKEY'
            comment  = Multical602
            telegram = 7A442D2C012815781C048D206450E76322344678_02F9FF1511130406690B010004EEFF07C1BC020004EEFF0890D401000414A925040084401400000000848040140000000002FD170000026CB929426CBF284406100A01004414D81A0400C4401400000000C480401400000000043B3900000002592A17025D2912
            json     = '{"_":"telegram","id": "78152801","media": "heat","driver": "kamheat","meter_date": "2021-09-25","name": "Heato","status": "OK","t1_temperature_c": 59.3,"t2_temperature_c": 46.49,"target_date": "2021-08-31","target_energy_kwh": 68112,"target_volume_m3": 2690.16,"timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 68457,"total_volume_m3": 2717.85,"volume_flow_m3h": 0.057, "va_counter": 179393,"vb_counter": 119952,"enhanced_id": "1311","target_volume_subunit1_m3": 0,"target_volume_subunit2_m3": 0,"total_volume_subunit1_m3": 0,"total_volume_subunit2_m3": 0}'
            fields   = 'Heato;78152801;68457;2717.85;OK;1111-11-11 11:11.11'
        }
        test {
            args     = 'Heato kamheat 78152801 NOKEY'
            comment  = Multical602
            telegram = 7A442D2C012815781C048D206450E76322344678_02F9FF1511130406690B010004EEFF07C1BC020004EEFF0890D401000414A925040084401400000000848040140000000002FD170000026CB929426CBF284406100A01004414D81A0400C4401400000000C480401400000000043B3900000002592A17025D2912,4F442D2C012815781C048D206551E76322BE767900843005_1113690B0100C1BC020090D40100A925040000000000000000000000B929BF28100A0100D81A04000000000000000000390000002A172912
            json     = '{"_":"telegram","id": "78152801","media": "heat","driver": "kamheat","meter_date": "2021-09-25","name": "Heato","status": "OK","t1_temperature_c": 59.3,"t2_temperature_c": 46.49,"target_date": "2021-08-31","target_energy_kwh": 68112,"target_volume_m3": 2690.16,"timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 68457,"total_volume_m3": 2717.85,"volume_flow_m3h": 0.057,"enhanced_id": "1311","va_counter": 179393,"vb_counter": 119952,"target_volume_subunit1_m3": 0,"target_volume_subunit2_m3": 0,"total_volume_subunit1_m3": 0,"total_volume_subunit2_m3": 0}'
            fields   = 'Heato;78152801;68457;2717.85;OK;1111-11-11 11:11.11'
        }
        test {
            args     = 'Heater kamheat 80808081 NOKEY'
            comment  = Multical803
            telegram = 88442D2C8180808039048D208640513220EA7978_040FA000000004FF070200000004FF08090000000414FF000000844014000000008480401400000000043B0000000002590000025D0000142D0000000084100F0000000084200F0000000004FF2260000100026C892B440F00000000441400000000C4401400000000C480401400000000426C812B
            json     = '{"_":"telegram","forward_energy_m3c": 2,"id": "80808081","max_power_kw": 0,"media": "heat","driver": "kamheat","meter_date": "2020-11-09","name": "Heater","return_energy_m3c": 9,"status": "SENSOR_T1_BELOW_MEASURING_RANGE SENSOR_T2_BELOW_MEASURING_RANGE V1_COMMUNICATION_ERROR","t1_temperature_c": 0,"t2_temperature_c": 0,"target_date": "2020-11-01","target_energy_kwh": 0,"target_volume_m3": 0,"timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 444.444444,"total_volume_m3": 2.55,"volume_flow_m3h": 0,"target_volume_subunit1_m3": 0,"target_volume_subunit2_m3": 0,"total_volume_subunit1_m3": 0,"total_volume_subunit2_m3": 0}'
            fields   = 'Heater;80808081;444.444444;2.55;SENSOR_T1_BELOW_MEASURING_RANGE SENSOR_T2_BELOW_MEASURING_RANGE V1_COMMUNICATION_ERROR;1111-11-11 11:11.11'
        }
        test {
            args     = 'Kamstrup_303 kamheat 78787878 NOKEY'
            telegram = 5E442D2C78787878400C7A6E0050252F2F_04056C2B000004138A0B070004FF07C657020004FF08FD36020002594B09025DFA08023B000002FF220000026CF42144052F000000441302AD0000426CE1212F2F2F2F2F2F2F2F2F2F2F2F2F2F2F
            json     = '{"_":"telegram","media":"heat volume at inlet","driver":"kamheat","name":"Kamstrup_303","id":"78787878","status":"OK","total_energy_consumption_kwh":1111.6,"total_volume_m3":461.706,"volume_flow_m3h":0,"t1_temperature_c":23.79,"t2_temperature_c":22.98,"forward_energy_m3c":153542,"return_energy_m3c":145149,"meter_date":"2023-01-20","target_energy_kwh":4.7,"target_volume_m3":44.29,"target_date":"2023-01-01","timestamp":"1111-11-11T11:11:11Z"}'
            fields   = 'Kamstrup_303;78787878;1111.6;461.706;OK;1111-11-11 11:11.11'
        }
        test {
            args     = 'Kamstrup_403_mbus kamheat 77447744 NOKEY'
            telegram = 68464668084a72447744772d2c3404060000000406ce86000004ff073444020004ff08f8ce0100041411680300043B0f02000002593c19025da41104ff220000000004a5ff21c7d02700d916
            json     = '{"_":"telegram","forward_energy_m3c": 148532,"id": "77447744","media": "heat","driver": "kamheat","name": "Kamstrup_403_mbus","return_energy_m3c": 118520,"status": "OK","t1_temperature_c": 64.6,"t2_temperature_c": 45.16,"timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 34510,"total_volume_m3": 2232.49,"volume_flow_m3h": 0.527,"operating_time_h": 43489.183333}'
            fields   = 'Kamstrup_403_mbus;77447744;34510;2232.49;OK;1111-11-11 11:11.11'
        }
        test {
            args     = 'Kamstrup_402_wmbus kamheat 62215006 NOKEY'
            telegram = 40442D2C0650216219048D2083A4E1162306FF78_040F2C3F000004FF07DBA40D0004FF08860B0D000414BA33140002FD170000043B620000000259A21E025DFA1B
            json     = '{"_":"telegram","media":"heat","driver":"kamheat","name":"Kamstrup_402_wmbus","id":"62215006","forward_energy_m3c":894171,"return_energy_m3c":854918,"t1_temperature_c":78.42,"t2_temperature_c":71.62,"total_energy_consumption_kwh":44922.222222,"total_volume_m3":13239.62,"volume_flow_m3h":0.098,"status":"OK","timestamp":"1111-11-11T11:11:11Z"}'
            fields   = 'Kamstrup_402_wmbus;62215006;44922.222222;13239.62;OK;1111-11-11 11:11.11'
        }
        test {
            args     = 'Kamstrup_MC603_mbus kamheat 32323232 NOKEY'
            telegram = 68c9c96808e672323232322d2c35041900000004fB006083000004ff074006010004ff08299400000416984e010084401400000000848040140000000004225043000034221c0000000259c91f025d4f1102617a0e042e30020000142e65030000043c24050000143ce308000004ff2200000000046d2e2B0f3144fB00007d000044ff07Bdf9000044ff08308d00004416B73f0100c4401400000000c480401400000000542ed9020000543ce8090000426c013102ff1a011B0c783032858404ff16e5841e0004ff17c1d5B400a516
            json     = '{"_":"telegram","fabrication_no": "84853230",  "flow_return_temperature_difference_c": 37.06,  "forward_energy_m3c": 67136,  "id": "32323232",  "max_flow_m3h": 22.75,  "max_power_kw": 869,  "media": "heat",  "driver": "kamheat",  "meter_datetime": "2024-01-15 11:46",  "name": "Kamstrup_MC603_mbus",  "on_time_at_error_h": 28,  "on_time_h": 17232,  "power_kw": 560,  "return_energy_m3c": 37929,  "status": "OK",  "t1_temperature_c": 81.37,  "t2_temperature_c": 44.31,  "target_date": "2024-01-01",  "target_energy_kwh": 3200000,  "target_volume_m3": 81847,  "timestamp": "1111-11-11T11:11:11Z",  "total_energy_consumption_kwh": 3363200,  "total_volume_m3": 85656,  "volume_flow_m3h": 13.16,"target_volume_subunit1_m3": 0,"target_volume_subunit2_m3": 0,"total_volume_subunit1_m3": 0,"total_volume_subunit2_m3": 0,"meter_type": "1B01","module_software_nr": 11851201,"module_type_config_nr": 2000101,"target_forward_energy_m3c": 63933,"target_max_flow_m3h": 25.36,"target_max_power_kw": 729,"target_return_energy_m3c": 36144}'
            fields   = 'Kamstrup_MC603_mbus;32323232;3363200;85656;OK;1111-11-11 11:11.11'
        }
        test {
            args     = 'KMHEAT kamheat 85412440 NOKEY'
            telegram = 5e442d2c4024418535047ae10050252f2f04fB091300000004167500000004ff2200000000043ca301000002599c1d025dB00e844014000000008480401400000000042eB9000000026c0534426c013444fB0900000000543c000000002f2f
            json     = '{"_":"telegram","id": "85412440","media": "heat","driver": "kamheat","meter_date": "2024-04-05","name": "KMHEAT","power_kw": 185,"status": "OK","t1_temperature_c": 75.8,"t2_temperature_c": 37.6,"target_date": "2024-04-01","target_energy_kwh": 0,"timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 5277.777778,"total_volume_m3": 117,"volume_flow_m3h": 4.19,"total_volume_subunit1_m3": 0,"total_volume_subunit2_m3": 0,"target_max_flow_m3h": 0}'
            fields   = 'KMHEAT;85412440;5277.777778;117;OK;1111-11-11 11:11.11'
        }
        test {
            args     = 'KM2 kamheat 85007420 NOKEY'
            telegram = 689f9f68081472207400852d2c350cad00000004fb08c304000004ff07f21c000004ff084d1100000415fe29000084401400000000848040140000000004228829000034220a00000002598511025dab100261da00042d00000000142d08000000043b00000000143b6000000004ff2200000000046d0d2c0238542dc9010000543be1050000426c013102ff1a011b0c782074008504ff16850b200004ff17c9ff0e01cb16
            json     = '{"_":"telegram","fabrication_no": "85007420","flow_return_temperature_difference_c": 2.18,"forward_energy_m3c": 7410,"id": "85007420","max_flow_m3h": 0.096,"max_power_kw": 0.8,"media": "heat volume at inlet","driver": "kamheat","meter_datetime": "2024-08-02 12:13","name": "KM2","on_time_at_error_h": 10,"on_time_h": 10632,"power_kw": 0,"return_energy_m3c": 4429,"status": "OK","t1_temperature_c": 44.85,"t2_temperature_c": 42.67,"target_date": "2024-01-01","timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 33861.111111,"total_volume_m3": 1075,"volume_flow_m3h": 0,"total_volume_subunit1_m3": 0,"total_volume_subunit2_m3": 0,"meter_type": "1B01","module_software_nr": 17760201,"module_type_config_nr": 2100101,"target_max_flow_m3h": 1.505,"target_max_power_kw": 45.7}'
            fields   = 'KM2;85007420;33861.111111;1075;OK;1111-11-11 11:11.11'
        }
        test {
            args     = 'Kamstrup_MC303_Heat_AND_COOLING kamheat 30303030 NOKEY'
            telegram = 68888868083072303030302d2c400d0000000004069a00000004863c0000000004146d0f000004ff077205000004ff08ec0400000322890a0033220000000259720b025d040b02616e00022d0e00122db400023b6804123b7a0402ff22000044060000000044863c0000000044140000000044ff070000000044ff0800000000522d0000523b0000426c00006C16
            json     = '{"_":"telegram","media":"heat/cooling load","driver":"kamheat","name":"Kamstrup_MC303_Heat_AND_COOLING","id":"30303030","flow_return_temperature_difference_c":1.1,"forward_energy_m3c":1394,"max_flow_m3h":1.146,"max_power_kw":18,"on_time_h":2697,"on_time_at_error_h":0,"power_kw":1.4,"return_energy_m3c":1260,"t1_temperature_c":29.3,"t2_temperature_c":28.2,"target_energy_kwh":0,"target_volume_m3":0,"total_energy_backward_kwh":0,"total_energy_consumption_kwh":154,"total_volume_m3":39.49,"volume_flow_m3h":1.128,"status":"OK","target_date":"1999-11-30","target_energy_backward_kwh":0,"timestamp":"1111-11-11T11:11:11Z","target_forward_energy_m3c": 0,"target_max_flow_m3h": 0,"target_max_power_kw": 0,"target_return_energy_m3c": 0}'
            fields   = 'Kamstrup_MC303_Heat_AND_COOLING;30303030;154;39.49;OK;1111-11-11 11:11.11'
        }
        test {
            comment  = 'KAM,30,04 - Long Telegram'
            args     = 'kamheat_30_04 kamheat 67947613 NOKEY'
            telegram = 2E442D2C1376946730048D20EA00A80B20E1347803068E010043060000000314CA0900426CFFFF022D010001FF2100
            json     = '{"_":"telegram","media":"heat","driver":"kamheat","name":"kamheat_30_04","id":"67947613","power_kw":0.1,"target_date":null,"target_energy_kwh":0,"total_energy_consumption_kwh":398,"total_volume_m3":25.06,"status":"OK","timestamp":"1111-11-11T11:11:11Z"}'
            fields   = 'kamheat_30_04;67947613;398;25.06;OK;1111-11-11 11:11.11'
        }
        test {
            comment  = 'KAM,30,04 - Compact Telegram'
            args     = 'kamheat_30_04 kamheat 67947613 NOKEY'
            telegram = 25442D2C1376946730048D20E9F1A70B20154D79E7F1887F8E0100000000CA0900FFFF010000
            json     = '{"_":"telegram","media":"heat","driver":"kamheat","name":"kamheat_30_04","id":"67947613","power_kw":0.1,"target_date":null,"target_energy_kwh":0,"total_energy_consumption_kwh":398,"total_volume_m3":25.06,"status":"OK","timestamp":"1111-11-11T11:11:11Z"}'
            fields   = 'kamheat_30_04;67947613;398;25.06;OK;1111-11-11 11:11.11'
        }
        test {
            comment  = 'KAM,30,0c - Long Telegram'
            args     = 'kamheat_30_0c kamheat 67051653 NOKEY'
            telegram = 2E442D2C53160567300C8D2093D055F824AD3A78030E90DE00430EE9DD00031334EE17426C1F33022D000001FF2100
            json     = '{"_":"telegram","media":"heat volume at inlet","driver":"kamheat","name":"kamheat_30_0c","id":"67051653","power_kw":0,"target_date":"2024-03-31","target_energy_kwh":15780.277778,"total_energy_consumption_kwh":15826.666667,"total_volume_m3":1568.308,"status":"OK","timestamp":"1111-11-11T11:11:11Z"}'
            fields   = 'kamheat_30_0c;67051653;15826.666667;1568.308;OK;1111-11-11 11:11.11'
        }
        test {
            comment  = 'KAM,30,0c - Compact Telegram'
            args     = 'kamheat_30_0c kamheat 67051653 NOKEY'
            telegram = 25442D2C53160567300C8D2092C155F824389079C252C47190DE00E9DD0034EE171F33000000
            json     = '{"_":"telegram","media":"heat volume at inlet","driver":"kamheat","name":"kamheat_30_0c","id":"67051653","power_kw":0,"target_date":"2024-03-31","target_energy_kwh":15780.277778,"total_energy_consumption_kwh":15826.666667,"total_volume_m3":1568.308,"status":"OK","timestamp":"1111-11-11T11:11:11Z"}'
            fields   = 'kamheat_30_0c;67051653;15826.666667;1568.308;OK;1111-11-11 11:11.11'
        }
        test {
            comment  = 'KAM,34,0c - Long Telegram'
            args     = 'kamheat_34_0c kamheat 71054899 NOKEY'
            telegram = 56442D2C99480571340C8D2019708C8322C88F780406AF7D000004FF076556020004FF08D7E701000414CC7A0500043B0000000002598F0C025D920D04FF2200000000026CDF214406AF7D00004414CC7A0500426CC121
            json     = '{"_":"telegram","media":"heat volume at inlet","driver":"kamheat","name":"kamheat_34_0c","id":"71054899","forward_energy_m3c":153189,"return_energy_m3c":124887,"t1_temperature_c":32.15,"t2_temperature_c":34.74,"target_date":"2022-01-01","target_energy_kwh":32175,"target_volume_m3":3591.16,"total_energy_consumption_kwh":32175,"total_volume_m3":3591.16,"volume_flow_m3h":0,"meter_date":"2022-01-31","status":"OK","timestamp":"1111-11-11T11:11:11Z"}'
            fields   = 'kamheat_34_0c;71054899;32175;3591.16;OK;1111-11-11 11:11.11'
        }
        test {
            comment  = 'KAM,34,0c - Compact Telegram'
            args     = 'kamheat_34_0c kamheat 71054899 NOKEY'
            telegram = 3F442D2C99480571340C8D201B728C8322BE3D794DB3E88DAF7D000065560200D7E70100CC7A050000000000810C930D00000000DF21AF7D0000CC7A0500C121
            json     = '{"_":"telegram","media":"heat volume at inlet","driver":"kamheat","name":"kamheat_34_0c","id":"71054899","forward_energy_m3c":153189,"return_energy_m3c":124887,"t1_temperature_c":32.01,"t2_temperature_c":34.75,"target_date":"2022-01-01","target_energy_kwh":32175,"target_volume_m3":3591.16,"total_energy_consumption_kwh":32175,"total_volume_m3":3591.16,"volume_flow_m3h":0,"meter_date":"2022-01-31","status":"OK","timestamp":"1111-11-11T11:11:11Z"}'
            fields   = 'kamheat_34_0c;71054899;32175;3591.16;OK;1111-11-11 11:11.11'
        }
        test {
            comment  = 'KAM,39,04 - Long Telegram'
            args     = 'kamheat_39_04 kamheat 79806477 NOKEY'
            telegram = 88442D2C7764807939048D20864051322084C178040F0000000004FF070000000004FF0800000000041400000000844014000000008480401400000000043B0000000002590000025D0000142D0000000084100F0000000084200F0000000004FF2260000100026C892B440F00000000441400000000C4401400000000C480401400000000426C812B
            json     = '{"_":"telegram","media":"heat","driver":"kamheat","name":"kamheat_39_04","id":"79806477","forward_energy_m3c":0,"max_power_kw":0,"return_energy_m3c":0,"t1_temperature_c":0,"t2_temperature_c":0,"target_date":"2020-11-01","target_energy_kwh":0,"target_volume_m3":0,"target_volume_subunit1_m3":0,"target_volume_subunit2_m3":0,"total_energy_consumption_kwh":0,"total_volume_m3":0,"total_volume_subunit1_m3":0,"total_volume_subunit2_m3":0,"volume_flow_m3h":0,"meter_date":"2020-11-09","status":"SENSOR_T1_BELOW_MEASURING_RANGE SENSOR_T2_BELOW_MEASURING_RANGE V1_COMMUNICATION_ERROR","timestamp":"1111-11-11T11:11:11Z"}'
            fields   = 'kamheat_39_04;79806477;0;0;SENSOR_T1_BELOW_MEASURING_RANGE SENSOR_T2_BELOW_MEASURING_RANGE V1_COMMUNICATION_ERROR;1111-11-11 11:11.11'
        }
        test {
            comment  = 'KAM,39,04 - Compact Telegram'
            args     = 'kamheat_39_04 kamheat 79806477 NOKEY'
            telegram = 5B442D2C7764807939048D20870055322006F779A2E76FFD000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000100892B00000000000000000000000000000000812B
            json     = '{"_":"telegram","media":"heat","driver":"kamheat","name":"kamheat_39_04","id":"79806477","forward_energy_m3c":0,"max_power_kw":0,"return_energy_m3c":0,"t1_temperature_c":0,"t2_temperature_c":0,"target_date":"2020-11-01","target_energy_kwh":0,"target_volume_m3":0,"target_volume_subunit1_m3":0,"target_volume_subunit2_m3":0,"total_energy_consumption_kwh":0,"total_volume_m3":0,"total_volume_subunit1_m3":0,"total_volume_subunit2_m3":0,"volume_flow_m3h":0,"meter_date":"2020-11-09","status":"SENSOR_T1_BELOW_MEASURING_RANGE SENSOR_T2_BELOW_MEASURING_RANGE V1_COMMUNICATION_ERROR","timestamp":"1111-11-11T11:11:11Z"}'
            fields   = 'kamheat_39_04;79806477;0;0;SENSOR_T1_BELOW_MEASURING_RANGE SENSOR_T2_BELOW_MEASURING_RANGE V1_COMMUNICATION_ERROR;1111-11-11 11:11.11'
        }
        test {
            comment  = 'KAM,35,0d - MC603 heat/cooling over wired M-Bus, cooling energy E3 as 8F FF 02'
            args     = 'MC603_heat_cool kamheat 11223344 NOKEY'
            telegram = 68d7d768082a72443322112d2c350d07000000040f26af0000048fff020000000004ff07b27a020004ff0860d60000041448df020084401400000000848040140000000004227943000034222fb9000002594813025d05090261430a042d40000000142d31000000043bd3000000143ba400000004ff2200000000046d30294739440f14ae0000448fff020000000044ff07c975020044ff0807d40000441483d50200c4401400000000c480401400000000542d31000000543ba4000000426c413902ff1a021b0c784433221104ff16e6841e0004ff172d000f010616
            json     = '{"_":"telegram","driver":"kamheat","fabrication_no":"11223344","flow_return_temperature_difference_c":26.27,"forward_energy_m3c":162482,"id":"11223344","max_flow_m3h":0.164,"max_power_kw":4.9,"media":"heat/cooling load","meter_datetime":"2026-09-07 09:48","meter_type":"1B02","module_software_nr":17760301,"module_type_config_nr":2000102,"name":"MC603_heat_cool","on_time_at_error_h":47407,"on_time_h":17273,"power_kw":6.4,"return_energy_m3c":54880,"status":"OK","t1_temperature_c":49.36,"t2_temperature_c":23.09,"target_date":"2026-09-01","target_energy_cooling_kwh":0,"target_energy_kwh":123788.888889,"target_forward_energy_m3c":161225,"target_max_flow_m3h":0.164,"target_max_power_kw":4.9,"target_return_energy_m3c":54279,"target_volume_m3":1857.31,"target_volume_subunit1_m3":0,"target_volume_subunit2_m3":0,"timestamp":"1111-11-11T11:11:11Z","total_energy_consumption_kwh":124550,"total_energy_cooling_kwh":0,"total_volume_m3":1882.32,"total_volume_subunit1_m3":0,"total_volume_subunit2_m3":0,"volume_flow_m3h":0.211}'
            fields   = 'MC603_heat_cool;11223344;124550;1882.32;OK;1111-11-11 11:11.11'
        }
        test {
            comment  = 'KAM,1c,04 - Long Telegram'
            args     = 'kamheat_1c_04 kamheat 78152801 NOKEY'
            telegram = 7A442D2C012815781C048D206C70E7632234467802F9FF1511130406690B010004EEFF07C1BC020004EEFF0890D401000414A925040084401400000000848040140000000002FD170000026CB929426CBF284406100A01004414D81A0400C4401400000000C480401400000000043B3900000002592A17025D2912
            json     = '{"_":"telegram","media":"heat","driver":"kamheat","name":"kamheat_1c_04","id":"78152801","t1_temperature_c":59.3,"t2_temperature_c":46.49,"target_date":"2021-08-31","target_energy_kwh":68112,"target_volume_m3":2690.16,"target_volume_subunit1_m3":0,"target_volume_subunit2_m3":0,"total_energy_consumption_kwh":68457,"total_volume_m3":2717.85,"total_volume_subunit1_m3":0,"total_volume_subunit2_m3":0,"va_counter":179393,"vb_counter":119952,"volume_flow_m3h":0.057,"enhanced_id":"1311","meter_date":"2021-09-25","status":"OK","timestamp":"1111-11-11T11:11:11Z"}'
            fields   = 'kamheat_1c_04;78152801;68457;2717.85;OK;1111-11-11 11:11.11'
        }
        test {
            comment  = 'KAM,1c,04 - Compact Telegram'
            args     = 'kamheat_1c_04 kamheat 78152801 NOKEY'
            telegram = 4F442D2C012815781C048D207171E76322BE7679008430051113690B0100C1BC020090D40100A925040000000000000000000000B929BF28100A0100D81A04000000000000000000390000002A172912
            json     = '{"_":"telegram","media":"heat","driver":"kamheat","name":"kamheat_1c_04","id":"78152801","t1_temperature_c":59.3,"t2_temperature_c":46.49,"target_date":"2021-08-31","target_energy_kwh":68112,"target_volume_m3":2690.16,"target_volume_subunit1_m3":0,"target_volume_subunit2_m3":0,"total_energy_consumption_kwh":68457,"total_volume_m3":2717.85,"total_volume_subunit1_m3":0,"total_volume_subunit2_m3":0,"va_counter":179393,"vb_counter":119952,"volume_flow_m3h":0.057,"enhanced_id":"1311","meter_date":"2021-09-25","status":"OK","timestamp":"1111-11-11T11:11:11Z"}'
            fields   = 'kamheat_1c_04;78152801;68457;2717.85;OK;1111-11-11 11:11.11'
        }
    }
    test {
        args     = '303_wrong_flow kamheat 83076912 NOKEY'
        telegram = 52442d2c1269078340048d2067e08d1620d2ca7804060000000004140000000004ff070000000004ff080000000002592618025d2816023B000002ff220002026c393B440600000000441400000000426c213B
        json     = '{"_":"telegram","media":"heat","driver":"kamheat","name":"303_wrong_flow","id":"83076912","forward_energy_m3c":0,"return_energy_m3c":0,"t1_temperature_c":61.82,"t2_temperature_c":56.72,"target_date":"2025-11-01","target_energy_kwh":0,"target_volume_m3":0,"total_energy_consumption_kwh":0,"total_volume_m3":0,"volume_flow_m3h":0,"meter_date":"2025-11-25","status":"WRONG_FLOW_DIRECTION","timestamp":"1111-11-11T11:11:11Z"
                    }'
    }
    test {
        args     = '303_heat_cool kamheat 83010647 NOKEY'
        telegram = 5e442d2c47060183400d7a160050252f2f0406772e000004863c8c01000004149585020004ff0797d9000004ff08B6B200000259190a025d270a023B000002ff220000026c4a374406772e000044863c6d0100004414de810200426c41372f
        json     = '{"_":"telegram","media":"heat/cooling load","driver":"kamheat","name":"","id":"83010647","forward_energy_m3c":55703,"return_energy_m3c":45750,"t1_temperature_c":25.85,"t2_temperature_c":25.99,"target_date":"2026-07-01","target_energy_kwh":11895,"target_energy_backward_kwh":365,"target_volume_m3":1643.18,"total_energy_backward_kwh":396,"total_energy_consumption_kwh":11895,"total_volume_m3":1652.69,"volume_flow_m3h":0,"meter_date":"2026-07-10","status":"OK","timestamp":"2026-07-11T10:50:30Z"}'
    }
}