feat(gateway): food/kitchen scale support (arboleaf CK10G) v1.6.0
- Generic parser now supports food scale weight ranges (1g-15kg) with candidates for gram, 0.1g, and 0.5g divisors - WebSocket sends grams (unit: 'g') for weights under 15kg - MainActivity displays grams for food-scale readings - Enhanced debug: raw byte dump on decode failure with index/decimal/hex - versionCode=5, versionName=1.6.0
This commit is contained in:
@@ -11,8 +11,8 @@ android {
|
||||
applicationId = "it.dadaloop.evershelf.scalegate"
|
||||
minSdk = 24
|
||||
targetSdk = 34
|
||||
versionCode = 4
|
||||
versionName = "1.5.0"
|
||||
versionCode = 5
|
||||
versionName = "1.6.0"
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
|
||||
+6
-1
@@ -423,7 +423,12 @@ class BleScaleManager(
|
||||
if (reading != null && reading.weightKg > 0f) {
|
||||
mainHandler.post { listener.onWeightReceived(reading) }
|
||||
} else {
|
||||
mainHandler.post { listener.onDebugEvent("⚠️ Peso non decodificato") }
|
||||
val rawDump = data.mapIndexed { i, b ->
|
||||
val v = b.toInt() and 0xFF
|
||||
val h = "%02X".format(v)
|
||||
"[$i]=$v(0x$h)"
|
||||
}.joinToString(" ")
|
||||
mainHandler.post { listener.onDebugEvent("⚠️ Peso non decodificato\n RAW: $rawDump") }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
-4
@@ -136,12 +136,18 @@ class GatewayWebSocketServer(
|
||||
}
|
||||
|
||||
private fun buildWeightJson(weightKg: Float, stable: Boolean): String {
|
||||
// Round to 2 decimal places
|
||||
val rounded = (weightKg * 100).toLong() / 100.0
|
||||
val obj = JSONObject()
|
||||
obj.put("type", "weight")
|
||||
obj.put("value", rounded)
|
||||
obj.put("unit", "kg")
|
||||
// Food scale (<15kg): send grams for better precision
|
||||
if (weightKg < 15f) {
|
||||
val grams = Math.round(weightKg * 1000f)
|
||||
obj.put("value", grams)
|
||||
obj.put("unit", "g")
|
||||
} else {
|
||||
val rounded = (weightKg * 100).toLong() / 100.0
|
||||
obj.put("value", rounded)
|
||||
obj.put("unit", "kg")
|
||||
}
|
||||
obj.put("stable", stable)
|
||||
obj.put("timestamp", System.currentTimeMillis())
|
||||
return obj.toString()
|
||||
|
||||
+8
-2
@@ -222,8 +222,14 @@ class MainActivity : AppCompatActivity(), BleScaleListener, ServerEventListener
|
||||
}
|
||||
|
||||
override fun onWeightReceived(reading: WeightReading) {
|
||||
val kg = "%.2f".format(reading.weightKg)
|
||||
binding.tvWeight.text = "$kg kg"
|
||||
val isFood = reading.weightKg < 15f
|
||||
if (isFood) {
|
||||
val grams = (reading.weightKg * 1000).toInt()
|
||||
binding.tvWeight.text = "$grams g"
|
||||
} else {
|
||||
val kg = "%.2f".format(reading.weightKg)
|
||||
binding.tvWeight.text = "$kg kg"
|
||||
}
|
||||
|
||||
val extras = buildString {
|
||||
reading.fatPct?.let { append("Grasso: ${"%.1f".format(it)}% ") }
|
||||
|
||||
+38
-17
@@ -267,7 +267,7 @@ object ScaleProtocol {
|
||||
return null
|
||||
}
|
||||
|
||||
// --- Safe generic fallback ---
|
||||
// --- Safe generic fallback (body + food scales) ---
|
||||
|
||||
fun parseGenericSafe(data: ByteArray, debug: ((String) -> Unit)? = null): WeightReading? {
|
||||
if (data.size < 4) {
|
||||
@@ -275,30 +275,51 @@ object ScaleProtocol {
|
||||
return null
|
||||
}
|
||||
|
||||
data class Candidate(val pos: Int, val div: Float, val be: Boolean, val label: String)
|
||||
data class Candidate(
|
||||
val pos: Int, val div: Float, val be: Boolean,
|
||||
val minKg: Float, val maxKg: Float, val label: String,
|
||||
)
|
||||
|
||||
val candidates = listOf(
|
||||
Candidate(1, 100f, true, "pos1 BE/100"),
|
||||
Candidate(1, 100f, false, "pos1 LE/100"),
|
||||
Candidate(3, 100f, true, "pos3 BE/100"),
|
||||
Candidate(3, 100f, false, "pos3 LE/100"),
|
||||
Candidate(2, 100f, true, "pos2 BE/100"),
|
||||
Candidate(2, 100f, false, "pos2 LE/100"),
|
||||
Candidate(1, 10f, true, "pos1 BE/10"),
|
||||
Candidate(1, 10f, false, "pos1 LE/10"),
|
||||
Candidate(3, 10f, true, "pos3 BE/10"),
|
||||
Candidate(3, 10f, false, "pos3 LE/10"),
|
||||
Candidate(1, 20f, true, "pos1 BE/20"),
|
||||
Candidate(1, 20f, false, "pos1 LE/20"),
|
||||
// Food scale: raw value in grams (div=1 -> kg=raw/1000 via pos)
|
||||
Candidate(1, 1000f, false, 0.001f, 15f, "pos1 LE/g"),
|
||||
Candidate(1, 1000f, true, 0.001f, 15f, "pos1 BE/g"),
|
||||
Candidate(2, 1000f, false, 0.001f, 15f, "pos2 LE/g"),
|
||||
Candidate(2, 1000f, true, 0.001f, 15f, "pos2 BE/g"),
|
||||
Candidate(3, 1000f, false, 0.001f, 15f, "pos3 LE/g"),
|
||||
Candidate(3, 1000f, true, 0.001f, 15f, "pos3 BE/g"),
|
||||
// Food scale: raw in 0.1g (div=10000)
|
||||
Candidate(1, 10000f, false, 0.001f, 15f, "pos1 LE/0.1g"),
|
||||
Candidate(1, 10000f, true, 0.001f, 15f, "pos1 BE/0.1g"),
|
||||
Candidate(2, 10000f, false, 0.001f, 15f, "pos2 LE/0.1g"),
|
||||
Candidate(2, 10000f, true, 0.001f, 15f, "pos2 BE/0.1g"),
|
||||
// Food scale: raw in 0.5g (div=2000)
|
||||
Candidate(1, 2000f, false, 0.001f, 15f, "pos1 LE/0.5g"),
|
||||
Candidate(1, 2000f, true, 0.001f, 15f, "pos1 BE/0.5g"),
|
||||
// Body scale: standard divisors
|
||||
Candidate(1, 100f, true, 2f, 250f, "pos1 BE/100"),
|
||||
Candidate(1, 100f, false, 2f, 250f, "pos1 LE/100"),
|
||||
Candidate(3, 100f, true, 2f, 250f, "pos3 BE/100"),
|
||||
Candidate(3, 100f, false, 2f, 250f, "pos3 LE/100"),
|
||||
Candidate(2, 100f, true, 2f, 250f, "pos2 BE/100"),
|
||||
Candidate(2, 100f, false, 2f, 250f, "pos2 LE/100"),
|
||||
Candidate(1, 10f, true, 2f, 250f, "pos1 BE/10"),
|
||||
Candidate(1, 10f, false, 2f, 250f, "pos1 LE/10"),
|
||||
Candidate(3, 10f, true, 2f, 250f, "pos3 BE/10"),
|
||||
Candidate(3, 10f, false, 2f, 250f, "pos3 LE/10"),
|
||||
Candidate(1, 20f, true, 2f, 250f, "pos1 BE/20"),
|
||||
Candidate(1, 20f, false, 2f, 250f, "pos1 LE/20"),
|
||||
)
|
||||
|
||||
for (c in candidates) {
|
||||
if (c.pos + 1 >= data.size) continue
|
||||
val raw = if (c.be) u16be(data, c.pos) else u16le(data, c.pos)
|
||||
if (raw == 0) continue
|
||||
val w = raw / c.div
|
||||
if (w in 2f..250f) {
|
||||
val wStr = "%.2f".format(w)
|
||||
debug?.invoke("generic [" + c.label + "]: raw=$raw -> ${wStr}kg (UNSTABLE)")
|
||||
if (w in c.minKg..c.maxKg) {
|
||||
val grams = (w * 1000).toInt()
|
||||
val wStr = "%.3f".format(w)
|
||||
debug?.invoke("generic [" + c.label + "]: raw=$raw -> ${wStr}kg (${grams}g) (UNSTABLE)")
|
||||
return WeightReading(w, stable = false)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user