Packet Trace: Alarms and Warnings
This document describes how to query and parse alarm/warning status from the ALPHA HWR pump.
Overview
The ALPHA HWR reports active alarms and warnings through Object 88 using the Active Query Response format. Unlike other telemetry that streams automatically via notifications, alarm/warning status must be queried explicitly.
Query Format
Alarms and warnings use the standard Class 10 READ operation (OpSpec 0x03):
Query Alarms (Object 88, Sub 0)
Register address: 0x580000
Breakdown:
- 27: Request start byte
- 07: Length (7 bytes total)
- E7: Source (Client)
- F8: Destination (Pump)
- 0A: Class 10
- 03: OpSpec (READ)
- 58 00 00: Register (Obj=88, Sub=0 for alarms)
- XX XX: CRC16
Query Warnings (Object 88, Sub 11)
Register address: 0x58000B
Breakdown:
- Same as alarms query
- 58 00 0B: Register (Obj=88, Sub=11 for warnings)
Response Format
The pump responds with OpSpec 0x09 (Active Query Response), using the same format as other register-read responses (0x30, 0x2B, 0x14):
[Start] [Length] [Dest] [Src] [Class] [OpSpec] [Seq-H] [Seq-L] [ID-H] [ID-L] [Res-H] [Res-L] [DataLen] [Data...] [CRC]
No Active Alarms Response
Validated on real hardware (ESPHome implementation):
Breakdown:
- 24: Response start byte
- 0D: Length (13 bytes)
- F8: Destination (Client)
- E7: Source (Pump)
- 0A: Class 10
- 09: OpSpec (Active Query Response)
- 00 02: Sequence number
- 3A 01: ID field (depends on register queried)
- 00 00: Reserved
- 02: DataLen (2 bytes of data)
- 00 00: Data (uint16 = 0x0000, meaning "no alarms")
- DC 50: CRC16
Interpretation: The data value 0x0000 means there are no active alarms or warnings. This is the normal/healthy state.
Active Alarms Response
Example with alarm codes 42 and 7:
Breakdown:
- 24: Response start byte
- 11: Length (17 bytes)
- F8: Destination (Client)
- E7: Source (Pump)
- 0A: Class 10
- 09: OpSpec (Active Query Response)
- 00 03: Sequence number
- 58 00: ID field (Obj=88, Sub=0 for alarms)
- 00 00: Reserved
- 06: DataLen (6 bytes of data)
- 00 2A: Alarm code 42 (uint16 big-endian)
- 00 07: Alarm code 7 (uint16 big-endian)
- 00 00: Terminating zero (filtered out)
- XX XX: CRC16
Interpretation: This packet indicates two active alarms with codes 42 and 7.
Active Warnings Response
Same format as alarms, but ID field reflects Object 88, Sub 11:
Breakdown:
- 58 0B: ID field (Obj=88, Sub=11 for warnings)
- 04: DataLen (4 bytes)
- 00 05: Warning code 5
- 00 00: Terminating zero (filtered out)
Data Format
Payload Structure
The data section contains an array of uint16 values in big-endian format:
Important Notes:
- Each alarm/warning code is a 2-byte unsigned integer
- Byte order is big-endian (high byte first)
- A code value of 0x0000 means "no alarm/warning"
- Zero codes should be filtered out when parsing
- The array is typically terminated with a zero value
Example Parsing (Python)
import struct
def parse_alarm_response(packet: bytes) -> list[int]:
"""Parse alarm/warning codes from OpSpec 0x09 response."""
if len(packet) < 13:
return []
# Extract data length at offset 12
data_len = packet[12]
# Parse uint16 array starting at offset 13
codes = []
offset = 13
while offset + 2 <= len(packet) - 2 and offset < 13 + data_len:
code = struct.unpack(">H", packet[offset:offset+2])[0]
if code != 0: # Filter out zero codes
codes.append(code)
offset += 2
return codes
# Example: No alarms
packet = bytes.fromhex("24 0D F8 E7 0A 09 00 02 3A 01 00 00 02 00 00 DC 50")
print(parse_alarm_response(packet)) # Output: []
# Example: Active alarms 42 and 7
# Final two bytes are CRC placeholders for this example and are ignored
packet = bytes.fromhex("24 11 F8 E7 0A 09 00 03 58 00 00 00 06 00 2A 00 07 00 00 00 00")
print(parse_alarm_response(packet)) # Output: [42, 7]
OpSpec 0x09 Details
OpSpec Byte Structure
The OpSpec byte 0x09 can be decoded as follows:
0x09 = 0b00001001
│││ └─┴─ Bits 0-4: Data length indicator (9)
││└──────── Bit 5: Reserved
│└───────── Bit 6: Error flag (0 = success)
└────────── Bit 7: Reserved
Active Query Response Format
OpSpec 0x09 uses the Active Query Response layout, which is shared with other register-read responses:
- OpSpec 0x30: Motor state response
- OpSpec 0x2B: Flow/pressure response
- OpSpec 0x14: Temperature response
- OpSpec 0x09: Alarm/warning response
All these OpSpecs use the 7-byte header before data:
The key difference is that OpSpec 0x09 contains uint16 codes rather than IEEE 754 floats.
Integration Notes
Polling Frequency
Unlike streaming telemetry, alarms/warnings must be polled:
- Recommended interval: 5-10 seconds
- Minimum interval: 1 second (avoid overwhelming the pump)
- On-demand: Query after pump mode changes or errors
Error Handling
- If the pump doesn't respond, retry after 2-3 seconds
- If you receive malformed data, log the raw packet hex for debugging
- Empty response (DataLen=0) should be treated as "no data available"
Home Assistant Integration
Example ESPHome text sensor configuration:
text_sensor:
- platform: ble_client
name: "Active Alarms"
id: active_alarms
# Updated when alarm query response received
- platform: ble_client
name: "Active Warnings"
id: active_warnings
# Updated when warning query response received
Historical Context
Initial Confusion (Now Resolved)
Early Python implementations incorrectly expected OpSpec 0x13 for alarm responses. This was based on speculation before hardware validation.
Hardware validation (ESPHome, Feb 2025) confirmed that the pump actually responds with OpSpec 0x09, using the standard Active Query Response format.
Key Discovery
The breakthrough came from analyzing 100+ real packet captures showing consistent OpSpec 0x09 responses with data value 0x0000, which was initially misinterpreted as "not supported." In reality, 0x0000 simply means "no active alarms."
References
- Protocol: Telemetry - General telemetry overview
- Protocol: Wire Format - GENI packet structure
- ESPHome Implementation - Reference C++ decoder
- Python Implementation - Reference Python decoder
Validation
This documentation is based on:
- 100+ real packet captures from ALPHA HWR pump (Feb 2025)
- Successful ESPHome C++ implementation (tested on ESP32-C3)
- Cross-validation between Python and ESPHome implementations
- Protocol documentation at https://eman.github.io/alpha-hwr/reimplementation/