From ea579c02fe99f669fcad8b0fce9823ac2b91bf18 Mon Sep 17 00:00:00 2001 From: Krisjans Blukis Date: Mon, 26 Jul 2021 18:06:11 +0300 Subject: [PATCH] BluetoothSwpSBF77 experimental support for SBF77 based on BF600 and BF105; --- .../core/bluetooth/BluetoothFactory.java | 3 + .../core/bluetooth/BluetoothSwpSBF77.java | 171 ++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothSwpSBF77.java diff --git a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothFactory.java b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothFactory.java index bb040d55..528eef83 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothFactory.java +++ b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothFactory.java @@ -128,6 +128,9 @@ public class BluetoothFactory { if (deviceName.equals("BF600") || deviceName.equals("BF850") || deviceName.equals("BF950")) { return new BluetoothBeurerBF600(context, deviceName); } + if (deviceName.equals("SBF77")) { + return new BluetoothSwpSBF77(context); + } return null; } } diff --git a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothSwpSBF77.java b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothSwpSBF77.java new file mode 100644 index 00000000..1b2bb995 --- /dev/null +++ b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothSwpSBF77.java @@ -0,0 +1,171 @@ +/* Copyright (C) 2019 olie.xdev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + + /* + * Based on source-code by weliem/blessed-android + */ +package com.health.openscale.core.bluetooth; + +import android.content.Context; +import android.util.Pair; + +import com.health.openscale.core.datatypes.ScaleMeasurement; +import com.health.openscale.core.datatypes.ScaleUser; +import com.health.openscale.core.utils.Converters; +import com.welie.blessed.BluetoothBytesParser; + +import java.text.DateFormat; +import java.util.Arrays; +import java.util.GregorianCalendar; +import java.util.UUID; +import java.util.Vector; + +import timber.log.Timber; + +import static com.welie.blessed.BluetoothBytesParser.FORMAT_UINT16; +import static com.welie.blessed.BluetoothBytesParser.FORMAT_UINT8; + +class BluetoothGattUuidSBF77 extends BluetoothGattUuid { + public static final UUID SERVICE_CUSTOM_SBF77 = fromShortCode(0xffff); + public static final UUID CHARACTERISTIC_SBF77_USER_LIST = fromShortCode(0x0001); +} + +public class BluetoothSwpSBF77 extends BluetoothStandardWeightProfile { + + ScaleMeasurement scaleMeasurement; + private Vector scaleUserList; + static final int SBF77_MAX_USERS = 8; + + public BluetoothSwpSBF77(Context context) { + super(context); + scaleMeasurement = new ScaleMeasurement(); + scaleUserList = new Vector(); + } + + @Override + public String driverName() { + return "SBF77"; + } + + @Override + protected void writeBirthday() { + BluetoothBytesParser parser = new BluetoothBytesParser(); + parser.setDateTime(dateToCalender(this.selectedUser.getBirthday())); + writeBytes(BluetoothGattUuid.SERVICE_USER_DATA, BluetoothGattUuid.CHARACTERISTIC_USER_DATE_OF_BIRTH, + Arrays.copyOfRange(parser.getValue(), 0, 3)); + } + + @Override + protected void setNotifyVendorSpecificUserList() { + setNotificationOn(BluetoothGattUuidSBF77.SERVICE_CUSTOM_SBF77, + BluetoothGattUuidSBF77.CHARACTERISTIC_SBF77_USER_LIST); + } + + @Override + protected synchronized void requestVendorSpecificUserList() { + scaleUserList.clear(); + BluetoothBytesParser parser = new BluetoothBytesParser(); + parser.setIntValue(0x00, FORMAT_UINT8); + writeBytes(BluetoothGattUuidSBF77.SERVICE_CUSTOM_SBF77, BluetoothGattUuidSBF77.CHARACTERISTIC_SBF77_USER_LIST, + parser.getValue()); + stopMachineState(); + } + + @Override + public void onBluetoothNotify(UUID characteristic, byte[] value) { + if (characteristic.equals(BluetoothGattUuidSBF77.CHARACTERISTIC_SBF77_USER_LIST)) { + Timber.d(String.format("Got user data: <%s>", byteInHex(value))); + BluetoothBytesParser parser = new BluetoothBytesParser(value); + int userListStatus = parser.getIntValue(FORMAT_UINT8); + if (userListStatus == 2) { + Timber.d("scale have no users!"); + storeUserScaleConsentCode(selectedUser.getId(), -1); + storeUserScaleIndex(selectedUser.getId(), -1); + jumpNextToStepNr(SM_STEPS.REGISTER_NEW_SCALE_USER.ordinal()); + resumeMachineState(); + return; + } + else if (userListStatus == 1) { + for (int i = 0; i < scaleUserList.size(); i++) { + if (i == 0) { + Timber.d("scale user list:"); + } + Timber.d("\n" + (i + 1) + ". " + scaleUserList.get(i)); + } + if ((scaleUserList.size() == 0)) { + storeUserScaleConsentCode(selectedUser.getId(), -1); + storeUserScaleIndex(selectedUser.getId(), -1); + jumpNextToStepNr(SM_STEPS.REGISTER_NEW_SCALE_USER.ordinal()); + resumeMachineState(); + return; + } + if (getUserScaleIndex(selectedUser.getId()) == -1 || getUserScaleConsent(selectedUser.getId()) == -1) { + chooseExistingScaleUser(scaleUserList); + return; + } + resumeMachineState(); + return; + } + int index = parser.getIntValue(FORMAT_UINT8); + String initials = parser.getStringValue(); + int end = 3 > initials.length() ? initials.length() : 3; + initials = initials.substring(0, end); + parser.setOffset(5); + int year = parser.getIntValue(FORMAT_UINT16); + int month = parser.getIntValue(FORMAT_UINT8); + int day = parser.getIntValue(FORMAT_UINT8); + int height = parser.getIntValue(FORMAT_UINT8); + int gender = parser.getIntValue(FORMAT_UINT8); + int activityLevel = parser.getIntValue(FORMAT_UINT8); + GregorianCalendar calendar = new GregorianCalendar(year, month - 1, day); + ScaleUser scaleUser = new ScaleUser(initials, calendar.getTime(), height, gender, activityLevel - 1); + scaleUser.setId(index); + scaleUserList.add(scaleUser); + if (scaleUserList.size() == SBF77_MAX_USERS) { + chooseExistingScaleUser(scaleUserList); + } + } + else { + super.onBluetoothNotify(characteristic, value); + } + } + + protected void chooseExistingScaleUser(Vector userList) { + final DateFormat dateFormat = DateFormat.getDateInstance(); + int choicesCount = userList.size(); + if (userList.size() < SBF77_MAX_USERS) { + choicesCount = userList.size() + 1; + } + CharSequence[] choiceStrings = new String[choicesCount]; + int indexArray[] = new int[choicesCount]; + int selectedItem = -1; + for (int i = 0; i < userList.size(); ++i) { + ScaleUser u = userList.get(i); + choiceStrings[i] = "P-0" + u.getId() + + " " + (u.getGender().isMale() ? "male" : "female") + + " " + "height:" + u.getBodyHeight() + + " birthday:" + dateFormat.format(u.getBirthday()) + + " " + "AL:" + (u.getActivityLevel().toInt() + 1); + indexArray[i] = u.getId(); + } + if (userList.size() < SBF77_MAX_USERS) { + choiceStrings[userList.size()] = "Create new user on scale."; + indexArray[userList.size()] = -1; + } + Pair choices = new Pair(choiceStrings, indexArray); + chooseScaleUserUi(choices); + } +}