// Copyright (C) 2026 Fredrik Öhrström (gpl-3.0-or-later)
driver {
    name           = apatoreitn
    meter_type     = HeatCostAllocationMeter
    default_fields = name,id,current_hca,previous_hca,current_date,season_start_date,esb_date,temp_room_avg_c,temp_room_prev_avg_c,timestamp
    manufacturer   = Apator
    detect {
        mvt = APA,04,08
        mvt = APT,04,08
    }
    fields {
        field {
            name     = current
            quantity = HCA
            info     = 'Energy consumption so far in this billing period.'
            match {
                difvifkey = 026E
            }
        }
        field {
            name     = previous
            quantity = HCA
            info     = 'Energy consumption in previous billing period.'
            match {
                difvifkey = 426E
            }
        }
        field {
            name           = temp_room_avg_raw
            quantity       = Dimensionless
            attributes     = HIDE
            vif_scaling    = None
            dif_signedness = Unsigned
            match {
                difvifkey = 02FB01
            }
        }
        field {
            name           = temp_room_prev_avg_raw
            quantity       = Dimensionless
            attributes     = HIDE
            vif_scaling    = None
            dif_signedness = Unsigned
            match {
                difvifkey = 02FB02
            }
        }
        field {
            name       = current_date_raw
            quantity   = Dimensionless
            attributes = HIDE
            match {
                difvifkey = 02FD3A
            }
        }
        field {
            name           = season_start_date_lo
            quantity       = Dimensionless
            attributes     = HIDE
            vif_scaling    = None
            dif_signedness = Unsigned
            match {
                difvifkey = 01FB00
            }
        }
        field {
            name       = esb_date_raw
            quantity   = Dimensionless
            attributes = HIDE
            null_value = 0
            match {
                difvifkey = 8200FD3A
            }
        }
        field {
            name       = season_start_date_raw
            quantity   = Dimensionless
            attributes = HIDE
            calculate  = '(160counter * 256counter) + season_start_date_lo_counter'
        }
        field {
            name       = current_day
            quantity   = Dimensionless
            attributes = HIDE
            calculate  = 'current_date_raw_counter % 32counter'
        }
        field {
            name       = current_month
            quantity   = Dimensionless
            attributes = HIDE
            calculate  = '(current_date_raw_counter >> 5counter) % 16counter'
        }
        field {
            name       = current_year
            quantity   = Dimensionless
            attributes = HIDE
            calculate  = '(current_date_raw_counter >> 9counter) % 32counter'
        }
        field {
            name       = season_start_day
            quantity   = Dimensionless
            attributes = HIDE
            calculate  = 'season_start_date_raw_counter % 32counter'
        }
        field {
            name       = season_start_month
            quantity   = Dimensionless
            attributes = HIDE
            calculate  = '(season_start_date_raw_counter >> 5counter) % 16counter'
        }
        field {
            name       = season_start_year
            quantity   = Dimensionless
            attributes = HIDE
            calculate  = '(season_start_date_raw_counter >> 9counter) % 32counter'
        }
        field {
            name       = esb_day
            quantity   = Dimensionless
            attributes = HIDE
            calculate  = 'esb_date_raw_counter % 32counter'
        }
        field {
            name       = esb_month
            quantity   = Dimensionless
            attributes = HIDE
            calculate  = '(esb_date_raw_counter >> 5counter) % 16counter'
        }
        field {
            name       = esb_year
            quantity   = Dimensionless
            attributes = HIDE
            calculate  = '(esb_date_raw_counter >> 9counter) % 32counter'
        }
        field {
            name      = temp_room_avg
            quantity  = Temperature
            info      = 'Average room temperature in current season.'
            calculate = '((temp_room_avg_raw_counter >> 8counter) + ((temp_room_avg_raw_counter % 256counter) / 256counter)) * 1c'
        }
        field {
            name      = temp_room_prev_avg
            quantity  = Temperature
            info      = 'Average room temperature in previous season.'
            calculate = '((temp_room_prev_avg_raw_counter >> 8counter) + ((temp_room_prev_avg_raw_counter % 256counter) / 256counter)) * 1c'
        }
        field {
            name         = current
            quantity     = PointInTime
            display_unit = date
            info         = 'Current date, as reported by meter.'
            calculate    = "'2000-01-01 00:00:00' +
                            (((current_year_counter * 12counter) + current_month_counter - 1counter) * 1month) +
                            ((current_day_counter - 1counter) * 24h)"
        }
        field {
            name         = season_start
            quantity     = PointInTime
            display_unit = date
            info         = 'Season start date.'
            calculate    = "'2000-01-01 00:00:00' +
                            (((season_start_year_counter * 12counter) + season_start_month_counter - 1counter) * 1month) +
                            ((season_start_day_counter - 1counter) * 24h)"
        }
        field {
            name         = esb
            quantity     = PointInTime
            display_unit = date
            null_string  = ''
            info         = 'Electronic seal protection break date.'
            calculate    = "'2000-01-01 00:00:00' +
                            (((esb_year_counter * 12counter) + esb_month_counter - 1counter) * 1month) +
                            ((esb_day_counter - 1counter) * 24h)"
        }
        field {
            name     = status
            quantity = Text
            info     = 'Seal integrity status: OK = intact, SEAL_BROKEN = ESB date is set.'
            match {
                difvifkey = 8200FD3A
            }
            lookup {
                name            = STATUS
                map_type        = BitToString
                mask_bits       = 0xffff
                default_message = OK
                map {
                    name  = SEAL_BROKEN
                    value = 0xffff
                    test  = Set
                }
            }
        }
        field {
            name                 = mfct_specific_data
            quantity             = Text
            attributes           = HIDE
            match_entire_payload = true
            ixml                 = "decode = frame_direct | frame_direct_with_a0 | frame_b6.
                                    frame_direct = SeasonStartDateLo,
                                                   pad,
                                                   PrevHCA,
                                                   ESBDate,
                                                   CurrHCA,
                                                   CurrentDate,
                                                   TempPrevAvg,
                                                   TempAvg.
                                    frame_direct_with_a0 = -'A0', frame_direct.
                                    frame_b6 = frame_b6_00 | frame_b6_01 | frame_b6_02 | frame_b6_03 |
                                               frame_b6_04 | frame_b6_05 | frame_b6_06 | frame_b6_07 |
                                               frame_b6_08 | frame_b6_09 | frame_b6_0A | frame_b6_0B |
                                               frame_b6_0C | frame_b6_0D | frame_b6_0E | frame_b6_0F.
                                    frame_b6_00 = -'00', -'A0', frame_direct.
                                    frame_b6_01 = -'01', byte, -'A0', frame_direct.
                                    frame_b6_02 = -'02', byte, byte, -'A0', frame_direct.
                                    frame_b6_03 = -'03', byte, byte, byte, -'A0', frame_direct.
                                    frame_b6_04 = -'04', byte, byte, byte, byte, -'A0', frame_direct.
                                    frame_b6_05 = -'05', byte, byte, byte, byte, byte, -'A0', frame_direct.
                                    frame_b6_06 = -'06', byte, byte, byte, byte, byte, byte, -'A0', frame_direct.
                                    frame_b6_07 = -'07', byte, byte, byte, byte, byte, byte, byte, -'A0', frame_direct.
                                    frame_b6_08 = -'08', byte, byte, byte, byte, byte, byte, byte, byte, -'A0', frame_direct.
                                    frame_b6_09 = -'09', byte, byte, byte, byte, byte, byte, byte, byte, byte, -'A0', frame_direct.
                                    frame_b6_0A = -'0A', byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, -'A0', frame_direct.
                                    frame_b6_0B = -'0B', byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, -'A0', frame_direct.
                                    frame_b6_0C = -'0C', byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, -'A0', frame_direct.
                                    frame_b6_0D = -'0D', byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, -'A0', frame_direct.
                                    frame_b6_0E = -'0E', byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, -'A0', frame_direct.
                                    frame_b6_0F = -'0F', byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, byte, -'A0', frame_direct.

                                    pad = byte, byte.
                                    SeasonStartDateLo = byte, @DV_season_start_date_lo.
                                    PrevHCA = word, @DV_previous_hca.
                                    ESBDate = word, @DV_esb_date_raw.
                                    CurrHCA = word, @DV_current_hca.
                                    CurrentDate = word, @DV_current_date_raw.
                                    TempPrevAvg = word, @DV_temp_room_prev_avg.
                                    TempAvg = word, @DV_temp_room_avg.

                                    -hex  = ['A'-'F';'0'-'9'].
                                    -byte = hex, hex.
                                    -word = byte, byte.

                                    DV_current_hca>dvk = +'026E'.
                                    DV_previous_hca>dvk = +'426E'.
                                    DV_current_date_raw>dvk = +'02FD3A'.
                                    DV_season_start_date_lo>dvk = +'01FB00'.
                                    DV_esb_date_raw>dvk = +'8200FD3A'.
                                    DV_temp_room_avg>dvk = +'02FB01'.
                                    DV_temp_room_prev_avg>dvk = +'02FB02'."
        }
    }
    tests {
        test {
            args     = 'HCA1 apatoreitn 37373731 NOKEY'
            telegram = 19440186313737370408A0A1000059001C270100322DE413B415
            json     = '{"_":"telegram","media":"heat cost allocation","meter":"apatoreitn","name":"HCA1","id":"37373731","current_hca":1,"previous_hca":89,"current_date":"2022-09-18","season_start_date":"2016-05-01","esb_date":"2019-08-28","status":"SEAL_BROKEN","temp_room_avg_c":21.703125,"temp_room_prev_avg_c":19.890625,"timestamp":"1111-11-11T11:11:11Z"}'
            fields   = 'HCA1;37373731;1;89;2022-09-18;2016-05-01;2019-08-28;21.703125;19.890625;1111-11-11 11:11.11'
        }
        test {
            args     = 'HCA2 apatoreitn 37373732 NOKEY'
            telegram = 25441486323737370408B60AFFFFF5450186F41B9D58A0A100007809000000001F2D6416C819
            json     = '{"_":"telegram","media":"heat cost allocation","meter":"apatoreitn","name":"HCA2","id":"37373732","current_hca":0,"previous_hca":2424,"current_date":"2022-08-31","season_start_date":"2016-05-01","esb_date":null,"status":"OK","temp_room_avg_c":25.78125,"temp_room_prev_avg_c":22.390625,"timestamp":"1111-11-11T11:11:11Z"}'
            fields   = 'HCA2;37373732;0;2424;2022-08-31;2016-05-01;null;25.78125;22.390625;1111-11-11 11:11.11'
        }
        test {
            args     = 'HCA3 apatoreitn 37373733 NOKEY'
            telegram = 29441486333737370408B60EFFFFF1460186EC1B934EE91BA57BA0A1000059009C250100322DE413B415
            json     = '{"_":"telegram","media":"heat cost allocation","meter":"apatoreitn","name":"HCA3","id":"37373733","current_hca":1,"previous_hca":89,"current_date":"2022-09-18","season_start_date":"2016-05-01","esb_date":"2018-12-28","status":"SEAL_BROKEN","temp_room_avg_c":21.703125,"temp_room_prev_avg_c":19.890625,"timestamp":"1111-11-11T11:11:11Z"}'
            fields   = 'HCA3;37373733;1;89;2022-09-18;2016-05-01;2018-12-28;21.703125;19.890625;1111-11-11 11:11.11'
        }
    }
}