You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(qn): add ble.qn_report_byte so the history-response byte can be tested
The handshake answers the scale's 0x21 config request with
`a0 0d 04 fe 00 ...`. That 0xFE comes from openScale's QNHandler, which took it
from an ES-30M capture and annotates it only as a payload byte.
Two vendor-app captures on other firmware in the family send 0xFC in the same
position: a GE CS 10 G on the 20-byte extended dialect (#235) and an Arboleaf
QN-Scale FW V39 on the 19-byte es26m dialect (#75). Both were taken from
sessions where the vendor app completed a weigh-in, on scales where this adapter
sees the entire handshake acknowledged and then silence. Two reporters reached
the same reading of the byte independently, that it chooses between a live
report stream and the stored-history path.
The default does not move, because that reading is not established: openScale
dispatches live 0x10 weight frames while sending 0xFE, and the 0x23 stored-record
path this adapter relies on for V10 Renpho and ES-CS20M firmware (#213) hangs off
the same exchange. A wrong value here is silent in exactly the way a wrong
qn_protocol_byte is, so guessing would trade a diagnosable failure for an
undiagnosable one. The setting lets the reporters run the experiment on their own
hardware, and the default changes when it produces a reading.
Both QN bytes are now reachable from the Home Assistant add-on as well. They
were previously custom_config only, which is not a usable escape hatch for the
reporters who need them, since all three run the add-on. They are text options so
that unset stays distinguishable from 0, and a value outside 0 to 255 is dropped
with a warning rather than written into a config that would then fail validation.
The A00D pair had no test coverage at all; it now has three tests, one of which
pins that the second frame does not move with the first.
Refs #235, #75, #331
Copy file name to clipboardExpand all lines: docs/guide/configuration.md
+32Lines changed: 32 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -60,6 +60,7 @@ ble:
60
60
# force_scale_adapter: 'Hutbit'
61
61
# session_timeout_sec: 20
62
62
# qn_protocol_byte: 0
63
+
# qn_report_byte: 252
63
64
```
64
65
65
66
| Field | Required | Default | Description |
@@ -72,6 +73,7 @@ ble:
72
73
|`force_scale_adapter`| No | Auto-detect | Name of the scale protocol adapter to use, bypassing auto-detection. Requires `scale_mac`. See below. |
73
74
|`session_timeout_sec`| No |`120`| Seconds one GATT session may wait for a complete reading (5 to 600). Native BLE handlers only; ignored on `mqtt-proxy` and `esphome-proxy`. See below. |
74
75
|`qn_protocol_byte`| No | Auto | QN-family scales only. Protocol byte the handshake echoes back to the scale (0 to 255). Set it when a QN scale runs the whole handshake and then reports nothing, or when its scale-info frame is lost in transit on a proxy transport. See below. |
76
+
|`qn_report_byte`| No |`254` (0xFE) | QN-family scales only. Payload byte of the history-response frame (0 to 255). Try `252` (0xFC) when a QN scale completes the handshake and then reports nothing. See below. |
75
77
|`mqtt_proxy`| If `handler: mqtt-proxy`| (none) | MQTT proxy connection (`broker_url`, `device_id`, `topic_prefix`, `username`, `password`, `auto_connect`, `embedded_broker_*`). See [ESP32 BLE Proxy](./esp32-proxy). |
76
78
|`esphome_proxy`| If `handler: esphome-proxy`| (none) | ESPHome Native API connection (`host`, `port`, `encryption_key` or `password`, `client_info`). See [ESPHome Bluetooth Proxy](./esphome-proxy). |
77
79
@@ -118,6 +120,36 @@ If a value makes your scale work, please say so in an issue with the model and t
118
120
119
121
:::
120
122
123
+
::: tip QN scales that still report nothing (`qn_report_byte`)
124
+
125
+
If `qn_protocol_byte` did not help, there is one more byte worth trying, and it is a separate one.
126
+
127
+
When the scale asks for its configuration (`0x21`), the handshake answers with a history-response frame:
128
+
129
+
```
130
+
a0 0d 04 fe 00 00 00 00 00 00 00 00 <checksum>
131
+
^^
132
+
```
133
+
134
+
That `fe` comes from openScale, which took it from a capture of an ES-30M and labels it only as a payload byte. Vendor-app captures of two other scales in the family send `fc` in the same position: a GE CS 10 G and an Arboleaf QN-Scale on firmware V39. Both captures are of sessions where the vendor app completed a weigh-in, on scales where this app sees the whole handshake acknowledged and then nothing.
135
+
136
+
What the byte actually selects is not known. Both reporters read it as choosing between a live weight stream and the stored-history path, which fits their symptoms, but openScale receives live weight frames while sending `fe`, so that reading cannot be the whole story. The default therefore stays where the evidence is:
137
+
138
+
```yaml
139
+
ble:
140
+
qn_report_byte: 252 # 0xFC, the value both vendor-app captures send
141
+
```
142
+
143
+
With debug logging on, a session running an overridden byte says so:
144
+
145
+
```
146
+
QN: history response byte forced to 0xfc (default 0xfe)
147
+
```
148
+
149
+
If `252` makes your scale produce a weight, please say so in an issue with the model, the dialect from the `QN: scale info` line and that log line. Two confirmations on different firmware would be enough to move the default.
150
+
151
+
:::
152
+
121
153
::: tip Shortening the session (`session_timeout_sec`)
122
154
Some scales will not run a standalone weigh-in while a host holds the GATT session open. The Beurer BF500 is the clearest example: it displays `APP` and waits, so only a measurement taken **between** sessions is picked up.
0 commit comments