// Copyright (C) 2019-2022 Fredrik Öhrström (gpl-3.0-or-later)
driver {
name = fhkvdataiii
meter_type = HeatCostAllocationMeter
default_fields = name,id,current_hca,current_date,previous_hca,previous_date,temp_room_c,temp_radiator_c,timestamp
detect {
mvt = TCH,69,80
mvt = TCH,94,80
}
fields {
field {
name = mfct_specific
quantity = Text
attributes = HIDE
match_entire_payload = true
ixml = "decode = version_01 | version_69 | version_94.
version_01 = '01', PrevDate, PrevHca, CurrDate, CurrHca, TempRoom, TempRad, byte*.
version_69 = '11', PrevDate, PrevHca, CurrDate, CurrHca, TempRoom, TempRad, byte*.
version_94 = '0F', PrevDate, PrevHca, CurrDate, CurrHca, Extra, TempRoom, TempRad, byte*.
PrevDate = word, @DV_prev_date_raw.
PrevHca = word, @DV_prev_hca.
CurrDate = word, @DV_curr_date_raw.
CurrHca = word, @DV_curr_hca.
-Extra = byte.
TempRoom = word, @DV_temp_room.
TempRad = word, @DV_temp_rad.
-hex = ['A'-'F';'0'-'9'].
-byte = hex, hex.
-word = byte, byte.
DV_prev_date_raw>dvk = +'02FD3A'.
DV_prev_hca>dvk = +'426E'.
DV_curr_date_raw>dvk = +'42FD3A'.
DV_curr_hca>dvk = +'026E'.
DV_temp_room>dvk = +'0265'.
DV_temp_rad>dvk = +'025D'."
}
field {
name = current
quantity = HCA
info = 'Energy consumption so far in this billing period.'
match {
measurement_type = Instantaneous
vif_range = HeatCostAllocation
}
}
field {
name = previous
quantity = HCA
info = 'Energy consumption in previous billing period.'
match {
measurement_type = Instantaneous
vif_range = HeatCostAllocation
storage_nr = 1
}
}
field {
name = previous_date_raw
quantity = Dimensionless
attributes = HIDE
match {
difvifkey = 02FD3A
}
}
field {
name = current_date_raw
quantity = Dimensionless
attributes = HIDE
match {
difvifkey = 42FD3A
}
}
field {
name = previous_day
quantity = Dimensionless
attributes = HIDE
calculate = 'previous_date_raw_counter % 32counter'
}
field {
name = previous_month
quantity = Dimensionless
attributes = HIDE
calculate = '(previous_date_raw_counter >> 5counter) % 16counter'
}
field {
name = previous_year
quantity = Dimensionless
attributes = HIDE
calculate = 'previous_date_raw_counter >> 9counter'
}
field {
name = current_day
quantity = Dimensionless
attributes = HIDE
calculate = '((current_date_raw_counter >> 4counter) % 32counter) + ((((current_date_raw_counter >> 4counter) % 32counter) <= 0counter) * 1counter)'
}
field {
name = current_month
quantity = Dimensionless
attributes = HIDE
calculate = '((current_date_raw_counter >> 9counter) % 16counter) + ((((current_date_raw_counter >> 9counter) % 16counter) <= 0counter) * 12counter)'
}
field {
name = current_year
quantity = Dimensionless
attributes = HIDE
info = 'Current billing year is previous year unless month/day rolled over.'
calculate = 'previous_year_counter + ((current_month_counter < previous_month_counter) || ((current_month_counter == previous_month_counter) && (current_day_counter <= previous_day_counter)))'
}
field {
name = current
quantity = PointInTime
display_unit = date
info = 'Date of current billing period.'
calculate = "'2000-01-01' +
(((current_year_counter * 12counter) + current_month_counter - 1counter) * 1month) +
((current_day_counter - 1counter) * 24h)"
}
field {
name = previous
quantity = PointInTime
display_unit = date
info = 'Date of last billing period.'
calculate = "'2000-01-01' +
(((previous_year_counter * 12counter) + previous_month_counter - 1counter) * 1month) +
((previous_day_counter - 1counter) * 24h)"
}
field {
name = temp_room
quantity = Temperature
info = 'Current room temperature.'
match {
measurement_type = Instantaneous
vif_range = ExternalTemperature
}
}
field {
name = temp_radiator
quantity = Temperature
info = 'Current radiator temperature.'
match {
measurement_type = Instantaneous
vif_range = ReturnTemperature
}
}
}
tests {
test {
args = 'Room fhkvdataiii 11776622 NOKEY'
telegram = 31446850226677116980A0119F27020480048300C408F709143C003D341A2B0B2A0707000000000000062D114457563D71A1850000
json = '{"_":"telegram","media":"heat cost allocator","meter":"fhkvdataiii","name":"Room","id":"11776622","current_hca":131,"current_date":"2020-02-08","previous_hca":1026,"previous_date":"2019-12-31","temp_room_c":22.44,"temp_radiator_c":25.51,"timestamp":"1111-11-11T11:11:11Z"}'
fields = 'Room;11776622;131;2020-02-08;1026;2019-12-31;22.44;25.51;1111-11-11 11:11.11'
}
test {
args = 'Rooom fhkvdataiii 11111234 NOKEY'
telegram = 33446850341211119480A2_0F9F292D005024040011BD08380904000000070000000000000000000000000001000000000003140E
json = '{"_":"telegram","media":"heat cost allocator","meter":"fhkvdataiii","name":"Rooom","id":"11111234","current_hca":4,"current_date":"2021-02-05","previous_hca":45,"previous_date":"2020-12-31","temp_room_c":22.37,"temp_radiator_c":23.6,"timestamp":"1111-11-11T11:11:11Z"}'
fields = 'Rooom;11111234;4;2021-02-05;45;2020-12-31;22.37;23.6;1111-11-11 11:11.11'
}
test {
args = 'Version01 fhkvdataiii 41059605 NOKEY'
comment = 'Test another, perhaps older, telegram which starts with 01 instead of 11.'
telegram = 32446850059605416980A0_019F334805400CFE029808B1080000000000060F4F3467AEA9A88D7B8D503E000000000000000000
json = '{"_": "telegram","current_date": "2026-06-04","current_hca": 766,"id": "41059605","media": "heat cost allocator","meter": "fhkvdataiii","name": "Version01","previous_date": "2025-12-31","previous_hca": 1352,"temp_radiator_c": 22.25,"temp_room_c": 22,"timestamp": "1111-11-11T11:11:11Z"}'
fields = 'Version01;41059605;766;2026-06-04;1352;2025-12-31;22;22.25;1111-11-11 11:11.11'
}
}
}