Skip to content

Commit 2c9784e

Browse files
authored
Support for OKOK Nameless (v3), Merge Yoda1 and OkOk handlers (#1233)
* Restore the support for OKOK Nameless scales * 2 digit precision * Merge OkOkHandler and Yoda1Handler --------- Co-authored-by: Florin9doi <Florin9doi@users.noreply.github.com>
1 parent 18e973d commit 2c9784e

6 files changed

Lines changed: 26 additions & 146 deletions

File tree

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ import com.health.openscale.core.bluetooth.scales.SppScaleAdapter
5454
import com.health.openscale.core.bluetooth.scales.StandardBeurerSanitasHandler
5555
import com.health.openscale.core.bluetooth.scales.TrisaBodyAnalyzeHandler
5656
import com.health.openscale.core.bluetooth.scales.TuningProfile
57-
import com.health.openscale.core.bluetooth.scales.Yoda1Handler
5857
import com.health.openscale.core.bluetooth.scales.YunmaiHandler
5958
import com.health.openscale.core.facade.MeasurementFacade
6059
import com.health.openscale.core.facade.SettingsFacade
@@ -86,7 +85,6 @@ class ScaleFactory @Inject constructor(
8685
private val modernKotlinHandlers: List<ScaleDeviceHandler> = listOf(
8786
YunmaiHandler(isMini = false),
8887
YunmaiHandler(isMini = true),
89-
Yoda1Handler(),
9088
TrisaBodyAnalyzeHandler(),
9189
SanitasSbf72Handler(),
9290
StandardBeurerSanitasHandler(),

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

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import com.health.openscale.core.utils.ConverterUtils
3030
* - "OKOK V20" (manufacturer id 0x20CA): stable flag + XOR checksum
3131
* - "OKOK V11" (manufacturer id 0x11CA): XOR checksum, unit & resolution in body properties
3232
* - "OKOK VF0" (manufacturer id 0xF0FF): simple weight field
33-
* - "OKOK Nameless" (any manufacturer id where low byte == 0xC0): MAC-embedded, unit & resolution in attrib
33+
* - "OKOK C0" (any manufacturer id where low byte == 0xC0): MAC-embedded, unit & resolution in attrib
3434
*
3535
* Link mode: BROADCAST_ONLY (no GATT connection).
3636
*/
@@ -59,31 +59,40 @@ class OkOkHandler : ScaleDeviceHandler() {
5959
private val IDX_VF0_WEIGHT_MSB = 3
6060
private val IDX_VF0_WEIGHT_LSB = 2
6161

62-
// Nameless/0xC0 indices
62+
// 0xC0 indices
6363
private val IDX_WEIGHT_MSB = 0
6464
private val IDX_WEIGHT_LSB = 1
6565
private val IDX_ATTRIB = 6
6666
private val UNIT_KG = 0
67+
private val UNIT_JIN = 1
6768
private val UNIT_LB = 2
6869
private val UNIT_STLB = 3
6970

71+
private val NamelessAlias = "OKOK Nameless"
72+
7073
/**
7174
* Decide support + build a *dynamic* displayName based on manufacturer data present
7275
* in the advertisement that matched this device.
7376
*/
7477
override fun supportFor(device: ScannedDeviceInfo): DeviceSupport? {
7578
val m = device.manufacturerData ?: return null
7679

80+
if (device.name.isEmpty() && containsLowByteC0(m))
81+
device.name = NamelessAlias
7782
val name = device.name
7883

79-
val supports = name.equals("NoName OkOk") || name.equals("ADV") || name.equals("Chipsea-BLE")
84+
val supports = name.equals(NamelessAlias)
85+
|| name.equals("ADV")
86+
|| name.equals("Chipsea-BLE")
87+
|| name.startsWith("Yoda0", ignoreCase = true)
88+
|| name.startsWith("Yoda1", ignoreCase = true)
8089
if (!supports) return null
8190

8291
val variantName = when {
8392
hasKey(m, MANUF_V20) -> "OKOK V20"
8493
hasKey(m, MANUF_V11) -> "OKOK V11"
8594
hasKey(m, MANUF_VF0) -> "OKOK VF0"
86-
containsLowByteC0(m) -> "OKOK Nameless"
95+
containsLowByteC0(m) -> "OKOK C0"
8796
else -> null
8897
} ?: return null
8998

@@ -128,8 +137,8 @@ class OkOkHandler : ScaleDeviceHandler() {
128137
return BroadcastAction.CONSUMED_STOP
129138
}
130139

131-
// Fallback: nameless 0xC0 vendor
132-
parseNameless(m)?.let { kg ->
140+
// Fallback: 0xC0 vendor
141+
parseC0(m)?.let { kg ->
133142
publish(ScaleMeasurement().apply { userId = user.id; weight = kg })
134143
return BroadcastAction.CONSUMED_STOP
135144
}
@@ -186,10 +195,10 @@ class OkOkHandler : ScaleDeviceHandler() {
186195

187196
// unit ((props >> 3) & 3)
188197
return when ((props shr 3) and 0x3) {
189-
0 -> weight / divider // kg
190-
1 -> weight / (divider * 2.0f) // jin → kg (approx.)
191-
2 -> (weight / divider) / 2.204623f // lb → kg
192-
3 -> { // st&lb
198+
UNIT_KG -> weight / divider
199+
UNIT_JIN -> weight / (divider * 2.0f)
200+
UNIT_LB -> (weight / divider) / 2.204623f
201+
UNIT_STLB -> {
193202
val stones = (weight shr 8)
194203
val pounds = (weight and 0xFF) / divider
195204
stones * 6.350293f + pounds * 0.453592f
@@ -205,7 +214,7 @@ class OkOkHandler : ScaleDeviceHandler() {
205214
return raw / 10.0f
206215
}
207216

208-
private fun parseNameless(m: SparseArray<ByteArray>): Float? {
217+
private fun parseC0(m: SparseArray<ByteArray>): Float? {
209218
val key = firstKeyWithLowByteC0(m) ?: return null
210219
val data = m.get(key) ?: return null
211220
if (data.size < 13) return null
@@ -226,6 +235,10 @@ class OkOkHandler : ScaleDeviceHandler() {
226235
val raw = u16be(data[IDX_WEIGHT_MSB], data[IDX_WEIGHT_LSB])
227236
raw / divider
228237
}
238+
UNIT_JIN -> {
239+
val raw = u16be(data[IDX_WEIGHT_MSB], data[IDX_WEIGHT_LSB])
240+
raw / divider / 2
241+
}
229242
UNIT_LB -> {
230243
val raw = u16be(data[IDX_WEIGHT_MSB], data[IDX_WEIGHT_LSB])
231244
ConverterUtils.toKilogram(raw / divider, WeightUnit.LB)

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

Lines changed: 0 additions & 129 deletions
This file was deleted.

android_app/app/src/main/java/com/health/openscale/core/service/BleScanner.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ import androidx.core.util.isNotEmpty
5252
* @property determinedHandlerDisplayName The display name of the handler determined for this device, if any.
5353
*/
5454
data class ScannedDeviceInfo(
55-
val name: String,
55+
var name: String,
5656
val address: String,
5757
val rssi: Int,
5858
val serviceUuids: List<UUID>,

android_app/app/src/main/java/com/health/openscale/core/utils/ConverterUtils.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ package com.health.openscale.core.utils
2020
import com.health.openscale.core.data.MeasureUnit
2121
import com.health.openscale.core.data.UnitType
2222
import com.health.openscale.core.data.WeightUnit
23-
import java.text.NumberFormat
24-
import java.util.Locale
2523
import kotlin.math.floor
2624
import kotlin.math.roundToInt
2725

android_app/app/src/main/java/com/health/openscale/core/utils/LocaleUtils.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ object LocaleUtils {
143143
val (st, lb) = ConverterUtils.decimalStToStLb(absVal)
144144
"$signPrefix$st st $lb lb"
145145
}
146-
UnitType.KG -> "$signPrefix${formatNumber(absVal, maxFraction = 1, locale)} kg"
146+
UnitType.KG -> "$signPrefix${formatNumber(absVal, maxFraction = 2, locale)} kg"
147147
UnitType.LB -> "$signPrefix${formatNumber(absVal, maxFraction = 1, locale)} lb"
148148
UnitType.PERCENT -> "$signPrefix${formatNumber(absVal, maxFraction = 1, locale)} %"
149149
UnitType.CM -> "$signPrefix${formatNumber(absVal, maxFraction = 1, locale)} cm"

0 commit comments

Comments
 (0)