Skip to content

Commit 60784a8

Browse files
committed
This commit expands the OneByoneHandler to support Eufy C1 (T9146) and Eufy P1 (T9147) scales. It also implements battery level monitoring by subscribing to the battery service and notifying the user when the battery level is low, see #1278
1 parent 7a76b06 commit 60784a8

1 file changed

Lines changed: 24 additions & 4 deletions

File tree

  • android_app/app/src/main/java/com/health/openscale/core/bluetooth/scales

android_app/app/src/main/java/com/health/openscale/core/bluetooth/scales/OneByoneHandler.kt

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ class OneByoneHandler : ScaleDeviceHandler() {
4949
private val SVC_FFF0 = uuid16(0xFFF0)
5050
private val CHR_FFF4 = uuid16(0xFFF4) // NOTIFY: mixed weight/body payloads (CF ...)
5151
private val CHR_FFF1 = uuid16(0xFFF1) // WRITE: command pipe (FD/ F1/ F2 ...)
52+
private val SVC_180F = uuid16(0x180F) //battery service
53+
private val CHR_2A19 = uuid16(0x2A19) //battery characteristic
5254

5355
// --- Small runtime state ---------------------------------------------------
5456

@@ -64,8 +66,13 @@ class OneByoneHandler : ScaleDeviceHandler() {
6466

6567
override fun supportFor(device: ScannedDeviceInfo): DeviceSupport? {
6668
val name = device.name.lowercase()
67-
val supports = name.equals("Health Scale".lowercase())
68-
if (!supports) return null
69+
70+
val model = when {
71+
"t9146" in name -> "Eufy C1"
72+
"t9147" in name -> "Eufy P1"
73+
"Health Scale".lowercase() in name -> "1byone (classic)"
74+
else -> return null
75+
}
6976

7077
val caps = buildSet {
7178
add(DeviceCapability.BODY_COMPOSITION)
@@ -76,7 +83,7 @@ class OneByoneHandler : ScaleDeviceHandler() {
7683
}
7784

7885
return DeviceSupport(
79-
displayName = "1byone (classic)",
86+
displayName = model,
8087
capabilities = caps,
8188
implemented = caps,
8289
linkMode = LinkMode.CONNECT_GATT
@@ -97,15 +104,28 @@ class OneByoneHandler : ScaleDeviceHandler() {
97104
waitAckClock = true
98105
writeTo(SVC_FFF0, CHR_FFF1, clock)
99106

107+
// 1) Battery: subscribe + read once
108+
setNotifyOn(SVC_180F, CHR_2A19)
109+
readFrom(SVC_180F, CHR_2A19)
110+
100111
// NOTE: After we receive the ACK, we will request history (F2 00) in onNotification().
101112
}
102113

103114
override fun onNotification(characteristic: UUID, data: ByteArray, user: ScaleUser) {
104-
if (characteristic != CHR_FFF4) {
115+
if (characteristic != CHR_FFF4 && characteristic != CHR_2A19) {
105116
logD("Unexpected notify from $characteristic ${data.toHexPreview(24)}")
106117
return
107118
}
108119

120+
if (characteristic == CHR_2A19) {
121+
val level = (data.first().toInt() and 0xFF)
122+
logD("Reported battery level: $level%")
123+
if (level <= 10) {
124+
userWarn(R.string.bluetooth_scale_warning_low_battery, level)
125+
}
126+
return
127+
}
128+
109129
// Two-byte ACKs appear during setup:
110130
if (data.size == 2) {
111131
when {

0 commit comments

Comments
 (0)