// Copyright (C) 2026 Fredrik Öhrström (gpl-3.0-or-later)
driver {
name = apator162
meter_type = WaterMeter
default_fields = name,id,total_m3,timestamp
manufacturer = Apator
model = 162
detect {
mvt = APA,05,06
mvt = APA,05,07
}
library {
use = total_m3
}
fields {
field {
name = mfct_specific_data
quantity = Text
attributes = HIDE
match_entire_payload = true
/* An IXML grammar for decoding apator telegrams.
This grammar handles the overall structure but so far
only extracts the total volume in liters.
Sometimes the apator payload leads with a nice 0x0f which
means mft specific data. Sometimes the apator payload (older meters?)
lead with 0x80 and then we have a good crash test for the difvif parser. :-)
(Hint it hasn't crashed so far.) */
ixml = "decode = -byte, status, field*, pad_FF?, checksum.
-hex = ['A'-'F';'0'-'9'].
-byte = hex, hex.
-word = byte, byte.
-triplet = byte, byte, byte.
-quad = byte, byte, byte, byte.
status = byte, byte, byte, byte, byte, byte, byte.
-field = date | faults | total | flow | detectors | voltage | energy | days | woot_44 |
woot_71 | woot_72 | woot_73 | woot_74 | woot_75 | woot_76 | woot_77 | woot_78 | woot_79 |
woot_7A | woot_7B | woot_7C | woot_8x | woot_8xx | woot_8A | woot_8B | woot_8C | woot_8E |
woot_A0 | woot_A1 | woot_A2 | woot_A3 | woot_A4 | woot_A5 | woot_A6 | woot_A9 | woot_AF |
woot_Ax | woot_B0 |
woot_B1 | woot_B2 | woot_B3 | woot_B4 | woot_B5 | woot_Bx | woot_Cx | woot_Dx | woot_F0.
date = -'00', quad.
faults = -'01', triplet.
total = -'10', quad, @DV_0413.
flow = -'11', word.
detectors = -'40', triplet, triplet.
voltage = -'41', word.
energy = -'42', quad.
days = -'43', word.
woot_44 = -'44', triplet.
woot_71 = -'71', byte, quad, quad.
woot_72 = -'72', byte, quad, quad, quad.
woot_73 = -'73', byte, quad, quad, quad, quad.
woot_74 = -'74', byte, quad, quad, quad, quad, quad.
woot_75 = -'75', byte, quad, quad, quad, quad, quad, quad.
woot_76 = -'76', byte, quad, quad, quad, quad, quad, quad, quad.
woot_77 = -'77', byte, quad, quad, quad, quad, quad, quad, quad, quad.
woot_78 = -'78', byte, quad, quad, quad, quad, quad, quad, quad, quad, quad.
woot_79 = -'79', byte, quad, quad, quad, quad, quad, quad, quad, quad, quad, quad.
woot_7A = -'7A', byte, quad, quad, quad, quad, quad, quad, quad, quad, quad, quad, quad.
woot_7B = -'7B', byte, quad, quad, quad, quad, quad, quad, quad, quad, quad, quad, quad, quad.
woot_7C = -'7C', byte, quad, quad, quad, quad, quad, quad, quad, quad, quad, quad, quad, quad, quad.
woot_8x = eights, quad, quad, word.
-eights = -'80' | -'81' | -'82' | -'83' | -'84' | -'86' | -'87'.
woot_8xx = eightsx, quad, quad, triplet.
-eightsx = -'85' | -'88' | -'8F'.
woot_8A = -'8A', quad, quad, byte.
woot_8B = -'8B', triplet, triplet.
woot_8C = -'8C', triplet, triplet.
woot_8E = -'8E', quad, triplet.
woot_Ax = (-'A7' | -'A8' | -'AA' | -'AB' | -'AC' | -'AD'), word.
woot_A0 = -'A0', quad.
woot_A1 = -'A1', quad.
woot_A2 = -'A2', byte.
woot_A3 = -'A3', triplet, triplet, byte.
woot_A4 = -'A4', quad.
woot_A5 = -'A5', byte.
woot_A6 = -'A6', triplet.
woot_A9 = -'A9', byte.
woot_AF = -'AF', byte.
woot_B0 = -'B0', quad, byte.
woot_B1 = -'B1', quad, quad.
woot_B2 = -'B2', quad, quad, quad, quad.
woot_B3 = -'B3', quad, quad.
woot_B4 = -'B4', word.
woot_B5 = -'B5', quad, quad, quad, quad.
woot_Bx = (-'B6' | -'B7' | -'B8' | -'B9' | -'BA' | -'BB' | -'BC' | -'BD' | -'BE' | -'BF'), triplet.
woot_Cx = (-'C0' | -'C1' | -'C2' | -'C3' | -'C4' | -'C5' | -'C6' | -'C7'), triplet.
woot_Dx = (-'D0' | -'D3'), triplet.
woot_F0 = -'F0', quad.
pad_FF = 'FF'+.
checksum = word, word?.
DV_0413>dvk = +'0413'."
}
}
tests {
test {
args = 'Wasser apator162 20202020 NOKEY'
telegram = 6E4401062020202005077A9A006085|2F2F0F0A734393CC0000435B0183001A54E06F630291342510|030F00007B013E0B00003E0B00003E0B00003E0B00003E0B00003E0B00003E0B0000650000003D0000003D0000003D00000000000000A0910CB003FFFFFFFFFFFFFFFFFFFFA62B
json = '{"_":"telegram","media":"water","meter":"apator162","name":"Wasser","id":"20202020","total_m3":3.843,"timestamp":"1111-11-11T11:11:11Z"}'
fields = 'Wasser;20202020;3.843;1111-11-11 11:11.11'
}
test {
args = 'W2 apator162 02035240 NOKEY'
comment = 'Test telegram with no FF padding, last 2 bytes are checksum.'
telegram = 2E4401064052030205077A2D0020852F2F0F334DA39A00000071011ABF0D00039A0D00A01053850310CECC0D008943
json = '{"_": "telegram","id": "02035240","media": "water","meter": "apator162","name": "W2","timestamp": "1111-11-11T11:11:11Z","total_m3": 904.398}'
fields = 'W2;02035240;904.398;1111-11-11 11:11.11'
}
test {
args = 'W3 apator162 02035240 NOKEY'
comment = 'Test telegram with no FF padding, last 2 bytes are checksum.'
telegram = 2E4401064052030205077A320020852F2F0F354DA39A00000071011ABF0D00039A0D00A01053850310CECC0D005E6D
json = '{"_": "telegram","id": "02035240","media": "water","meter": "apator162","name": "W3","timestamp": "1111-11-11T11:11:11Z","total_m3": 904.398}'
fields = 'W3;02035240;904.398;1111-11-11 11:11.11'
}
test {
args = 'MyTapWatera apator162 21202020 NOKEY'
telegram = 4E4401062020202105077A130040852F2F0F6D4C389300020043840210351F040075012C0B040048D603003E630300CD2C03001EF402000ACE0200A098A39603FFFFFFFFFFFFFFFFFFFFFFFFFF1977
json = '{"_":"telegram","media":"water","meter":"apator162","name":"MyTapWatera","id":"21202020","total_m3":270.133,"timestamp":"1111-11-11T11:11:11Z"}'
fields = 'MyTapWatera;21202020;270.133;1111-11-11 11:11.11'
}
test {
args = 'Wasser5 apator162 00533603 NOKEY'
comment = 'Real meter telegram with woot_7C monthly history field (regression test for github issue).'
telegram = 6E4401060336530005077A210060852F2F0F141F539A12000243EE0E84E3BDD9B6593A040500001082C800007C01B2C4000064C10000B3BD00000DB900000EB500009FB0000054AB0000EDA30000A39D0000BF980000E394000038900000488B0000A034CB8C04FFFFFFFFFFFFFA8A
json = '{"_":"telegram","media":"water","meter":"apator162","name":"Wasser5","id":"00533603","total_m3":51.33,"timestamp":"1111-11-11T11:11:11Z"}'
fields = 'Wasser5;00533603;51.33;1111-11-11 11:11.11'
}
test {
args = 'MyTapWaterb apator162 22202020 NOKEY'
telegram = 4E4401062020202205077A4B004085|2F2F0FE566B99390000087C0B24B732679FF75350010|FCFB00004155594265086A0043B4017301DFF600006AE70000BFD5000051BC0000A0F56C2602FFFF1B1B
json = '{"_":"telegram","media":"water","meter":"apator162","name":"MyTapWaterb","id":"22202020","total_m3":64.508,"timestamp":"1111-11-11T11:11:11Z"}'
fields = 'MyTapWaterb;22202020;64.508;1111-11-11 11:11.11'
}
test {
args = 'MyTapWaterc apator162 23202020 NOKEY'
telegram = 4E4401062020202305077A9D004085|2F2F0F81902C9300000010|B82F010041555942BD2882004319027301BC2601005C180100CB0A0100DFF60000A0F56C2602FFFFFFFFFFFFFFFFFFFFFFFFFF5B7C
json = '{"_":"telegram","media":"water","meter":"apator162","name":"MyTapWaterc","id":"23202020","total_m3":77.752,"timestamp":"1111-11-11T11:11:11Z"}'
fields = 'MyTapWaterc;23202020;77.752;1111-11-11 11:11.11'
}
test {
args = 'MyTapWaterd apator162 24202020 NOKEY'
telegram = 4E4401062020202405077A6C0040852F2F|0F73B3E19410000084E15381E553810101000010|FA41010041555942BF4E8A00433B027301AD380100BC2601005C180100CB0A0100A0F56C2602FFFFD0D7
json = '{"_":"telegram","media":"water","meter":"apator162","name":"MyTapWaterd","id":"24202020","total_m3":82.426,"timestamp":"1111-11-11T11:11:11Z"}'
fields = 'MyTapWaterd;24202020;82.426;1111-11-11 11:11.11'
}
test {
args = 'MyTapWatere apator162 25202020 NOKEY'
telegram = 4E4401062020202505077AEF0040852F2F|0F|071122|94|100200|43|6103|84|8B745953486C09100000|10|81920200|75|01F1800200E5640200534A02003431020080150200D9000200|A0|DC939703|FFFFA434
json = '{"_":"telegram","media":"water","meter":"apator162","name":"MyTapWatere","id":"25202020","total_m3":168.577,"timestamp":"1111-11-11T11:11:11Z"}'
fields = 'MyTapWatere;25202020;168.577;1111-11-11 11:11.11'
}
test {
args = 'MyTapWatere apator162 26202020 NOKEY'
telegram = 6E4401062020202605077AAC0060852F2F|0F|0C4442|94|1A0000|43|B502|83|000A549B4159029C290F|10|AB440000|7B|012C440000BE3E00008838000072340000493000009B2C00001D2C0000822B00007428000010250000B7200000261C0000|A0|A4D9A103|FFFFFFFFFFFFFFFFFFFF7823
json = '{"_":"telegram","media":"water","meter":"apator162","name":"MyTapWatere","id":"26202020","total_m3":17.579,"timestamp":"1111-11-11T11:11:11Z"}'
fields = 'MyTapWatere;26202020;17.579;1111-11-11 11:11.11'
}
test {
args = 'MyTapWatere apator162 26202020 NOKEY'
telegram = 6E4401062020202605077AAD0060852F2F|0F|0E4442|94|1A0000|43|B502|84|4265594C655901010000|10|AB440000|7B|012C440000BE3E00008838000072340000493000009B2C00001D2C0000822B00007428000010250000B7200000261C0000|A0|A4D9A103|FFFFFFFFFFFFFFFFFFFF6C1B
json = '{"_":"telegram","media":"water","meter":"apator162","name":"MyTapWatere","id":"26202020","total_m3":17.579,"timestamp":"1111-11-11T11:11:11Z"}'
fields = 'MyTapWatere;26202020;17.579;1111-11-11 11:11.11'
}
test {
args = 'MyTapWatere apator162 26202020 NOKEY'
telegram = 6E4401062020202605077AAE0060852F2F|0F|0F4442|94|1A0000|43|B502|81|D87F57D87F5701010000|10|AB440000|7B|012C440000BE3E00008838000072340000493000009B2C00001D2C0000822B00007428000010250000B7200000261C0000|A0|A4D9A103|FFFFFFFFFFFFFFFFFFFF5F22
json = '{"_":"telegram","media":"water","meter":"apator162","name":"MyTapWatere","id":"26202020","total_m3":17.579,"timestamp":"1111-11-11T11:11:11Z"}'
fields = 'MyTapWatere;26202020;17.579;1111-11-11 11:11.11'
}
test {
args = 'MyTapWaterf apator162 03410514 NOKEY'
telegram = 3E4401061405410305077A190030852F2F|0F|86B4B8|95|290200|40|C6C1|B4|F0F3F3|41|5559|42|FA701000|F0|01010000|10|BC780000|FFFFFFFFFFFFFFFFFFFFFF2483
json = '{"_":"telegram","media":"water","meter":"apator162","name":"MyTapWaterf","id":"03410514","total_m3":30.908,"timestamp":"1111-11-11T11:11:11Z"}'
fields = 'MyTapWaterf;03410514;30.908;1111-11-11 11:11.11'
}
test {
args = 'MyTapWaterg apator162 27202020 NOKEY'
telegram = 6E4401062020202705077A3D0060852F2F|0F|151794|94|0A0200|43|0403|81|D87F57D87F5701010000|10|783E0000|7B01223C00009137000098320000392D000010290000F02600004C2400003422000004220000CB21000017200000C51C0000|A0|9AD9A103|FFFFFFFFFFFFFFFFFFFF367E
json = '{"_":"telegram","media":"water","meter":"apator162","name":"MyTapWaterg","id":"27202020","total_m3":15.992,"timestamp":"1111-11-11T11:11:11Z"}'
fields = 'MyTapWaterg;27202020;15.992;1111-11-11 11:11.11'
}
test {
args = 'NewAndOld apator162 00148686 NOKEY'
comment = 'New apator162 telegram which can be decoded.'
telegram = 4E4401068686140005077A350040852F2F_0F005B599600000010AA55000041545A42850BD800437D037301C5500000564B00009E4600006A410000A01778EC03FFFFFFFFFFFFFFFFFFFFFFFFFFE393
json = '{"_":"telegram","media":"water","meter":"apator162","name":"NewAndOld","id":"00148686","total_m3":21.93,"timestamp":"1111-11-11T11:11:11Z"}'
fields = 'NewAndOld;00148686;21.93;1111-11-11 11:11.11'
}
test {
args = 'NewAndOld apator162 00148686 NOKEY'
telegram = 4E4401068686140005077A350040852F2F_0F005B599600000010AA66000041545A42850BD800437D037301C5500000564B00009E4600006A410000A01778EC03FFFFFFFFFFFFFFFFFFFFFFFFFFE393
json = '{"_":"telegram","media":"water","meter":"apator162","name":"NewAndOld","id":"00148686","total_m3":26.282,"timestamp":"1111-11-11T11:11:11Z"}'
fields = 'NewAndOld;00148686;26.282;1111-11-11 11:11.11'
}
test {
args = 'has80 apator162 04040404 NOKEY'
telegram = 704401060404040405077A0E0060852F2F_0F766DFB96010000430600808F67DB8F67DB01010000102F1F01007B01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A05F5C1804FFFFFFFFFFFFFFFFFFFF26BCD649
json = '{"_":"telegram","media":"water","meter":"apator162","name":"has80","id":"04040404","total_m3":73.519,"timestamp":"1111-11-11T11:11:11Z"}'
fields = 'has80;04040404;73.519;1111-11-11 11:11.11'
}
test {
args = 'has79 apator162 04960212 NOKEY'
telegram = 5E4401061202960405077A790050852F2F0F78A599983B0200435000805771165771160103000010653A00007919321E0000620000006200000000000000000000000000000000000000000000000000000000000000A0422C6004FFFF2FBF
json = '{"_":"telegram","media":"water","meter":"apator162","name":"has79","id":"04960212","total_m3":14.949,"timestamp":"1111-11-11T11:11:11Z"}'
fields = 'has79;04960212;14.949;1111-11-11 11:11.11'
}
}
}