And to reassure people, development continues, this is a new packet code:
21:58:47.229 || HGI:013393 | CTL:145038 | RQ | zone_type | 0000 || {'zone_type': 'configured_zones'}
21:58:47.256 || CTL:145038 | HGI:013393 | RP | zone_type | 0000F... || {'zone_mask': [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 'zone_type': 'configured_zones'}
21:58:47.289 || HGI:013393 | CTL:145038 | RQ | zone_type | 0008 || {'zone_type': 'radiator_valve'}
21:58:47.302 || CTL:145038 | HGI:013393 | RP | zone_type | 00088... || {'zone_mask': [0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1], 'zone_type': 'radiator_valve'}
21:58:47.339 || HGI:013393 | CTL:145038 | RQ | zone_type | 0009 || {'zone_type': 'ufh_controller'}
21:58:47.353 || CTL:145038 | HGI:013393 | RP | zone_type | 00094... || {'zone_mask': [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 'zone_type': 'ufh_controller'}
21:58:47.390 || HGI:013393 | CTL:145038 | RQ | zone_type | 000A || {'zone_type': 'zone_valve'}
21:58:47.404 || CTL:145038 | HGI:013393 | RP | zone_type | 000A2... || {'zone_mask': [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0], 'zone_type': 'zone_valve'}
21:58:47.441 || HGI:013393 | CTL:145038 | RQ | zone_type | 000B || {'zone_type': 'mixing_valve'}
21:58:47.455 || CTL:145038 | HGI:013393 | RP | zone_type | 000B1... || {'zone_mask': [0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0], 'zone_type': 'mixing_valve'}
21:58:47.492 || HGI:013393 | CTL:145038 | RQ | zone_type | 0011 || {'zone_type': 'electric_heat'}
21:58:47.506 || CTL:145038 | HGI:013393 | RP | zone_type | 00110... || {'zone_mask': [0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0], 'zone_type': 'electric_heat'}
The controller will tell you the type of each zone - working out this information (by simple eavesdropping normal traffic) is possible, but slow/painful otherwise. (edited)