From edce45dcc31b6b84f9423b1ccb8a832d562c0865 Mon Sep 17 00:00:00 2001 From: Davis Mosenkovs Date: Sun, 17 Sep 2023 12:02:58 +0300 Subject: [PATCH] Mijia LYWSD02: Battery + setting temperature scale Implement reading battery percentage. Implement setting temperature scale used on clock display. Communication protocol taken from: https://github.com/h4/lywsd02 --- .../DeviceSettingsPreferenceConst.java | 2 + .../DeviceSpecificSettingsFragment.java | 2 + .../MijiaLywsd02Coordinator.java | 8 +++ .../mijia_lywsd02/MijiaLywsd02Support.java | 51 ++++++++++++++++++- app/src/main/res/values/arrays.xml | 9 ++++ app/src/main/res/values/strings.xml | 5 ++ .../devicesettings_temperature_scale_cf.xml | 9 ++++ 7 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 app/src/main/res/xml/devicesettings_temperature_scale_cf.xml diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSettingsPreferenceConst.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSettingsPreferenceConst.java index 1557f19e8..dc2e01a1b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSettingsPreferenceConst.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSettingsPreferenceConst.java @@ -360,4 +360,6 @@ public class DeviceSettingsPreferenceConst { public static final String PREF_HOURLY_CHIME_END = "hourly_chime_end"; public static final String PREF_VOICE_SERVICE_LANGUAGE = "voice_service_language"; + + public static final String PREF_TEMPERATURE_SCALE_CF = "temperature_scale_cf"; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSpecificSettingsFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSpecificSettingsFragment.java index cfe211cbc..2a1074029 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSpecificSettingsFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSpecificSettingsFragment.java @@ -545,6 +545,8 @@ public class DeviceSpecificSettingsFragment extends AbstractPreferenceFragment i addPreferenceHandlerFor(PREF_VOICE_SERVICE_LANGUAGE); + addPreferenceHandlerFor(PREF_TEMPERATURE_SCALE_CF); + addPreferenceHandlerFor("lock"); String sleepTimeState = prefs.getString(PREF_SLEEP_TIME, PREF_DO_NOT_DISTURB_OFF); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/mijia_lywsd02/MijiaLywsd02Coordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/mijia_lywsd02/MijiaLywsd02Coordinator.java index c5b57ef63..3846a3c5f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/mijia_lywsd02/MijiaLywsd02Coordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/mijia_lywsd02/MijiaLywsd02Coordinator.java @@ -23,6 +23,7 @@ import android.net.Uri; import androidx.annotation.NonNull; +import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.devices.AbstractBLEDeviceCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler; import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider; @@ -142,6 +143,13 @@ public class MijiaLywsd02Coordinator extends AbstractBLEDeviceCoordinator { return MijiaLywsd02Support.class; } + @Override + public int[] getSupportedDeviceSpecificSettings(GBDevice device) { + return new int[]{ + R.xml.devicesettings_temperature_scale_cf, + }; + } + @Override protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) { // nothing to delete, yet diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/mijia_lywsd02/MijiaLywsd02Support.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/mijia_lywsd02/MijiaLywsd02Support.java index a0a160a60..ce664ca5c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/mijia_lywsd02/MijiaLywsd02Support.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/mijia_lywsd02/MijiaLywsd02Support.java @@ -1,5 +1,5 @@ /* Copyright (C) 2016-2021 Andreas Shimokawa, Carsten Pfeiffer, Sebastian - Kranz + Kranz, Davis Mosenkovs This file is part of Gadgetbridge. @@ -21,15 +21,19 @@ import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCharacteristic; import android.content.Intent; import android.net.Uri; +import android.widget.Toast; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.IOException; import java.util.ArrayList; import java.util.Objects; import java.util.SimpleTimeZone; import java.util.UUID; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; @@ -48,10 +52,14 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateA import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.IntentListener; import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.battery.BatteryInfoProfile; import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfoProfile; +import nodomain.freeyourgadget.gadgetbridge.util.GB; public class MijiaLywsd02Support extends AbstractBTLEDeviceSupport { private static final Logger LOG = LoggerFactory.getLogger(MijiaLywsd02Support.class); + private static final UUID UUID_TIME = UUID.fromString("ebe0ccb7-7a0a-4b0c-8a1a-6ff2997da3a6"); + private static final UUID UUID_BATTERY = UUID.fromString("ebe0ccc4-7a0a-4b0c-8a1a-6ff2997da3a6"); + private static final UUID UUID_SCALE = UUID.fromString("ebe0ccbe-7a0a-4b0c-8a1a-6ff2997da3a6"); private final DeviceInfoProfile deviceInfoProfile; private final GBDeviceEventVersionInfo versionCmd = new GBDeviceEventVersionInfo(); private final GBDeviceEventBatteryInfo batteryCmd = new GBDeviceEventBatteryInfo(); @@ -81,12 +89,13 @@ public class MijiaLywsd02Support extends AbstractBTLEDeviceSupport { builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZING, getContext())); requestDeviceInfo(builder); setTime(builder); + getBatteryInfo(builder); setInitialized(builder); return builder; } private void setTime(TransactionBuilder builder) { - BluetoothGattCharacteristic timeCharacteristc = getCharacteristic(UUID.fromString("ebe0ccb7-7a0a-4b0c-8a1a-6ff2997da3a6")); + BluetoothGattCharacteristic timeCharacteristc = getCharacteristic(MijiaLywsd02Support.UUID_TIME); long ts = System.currentTimeMillis(); byte offsetHours = (byte) (SimpleTimeZone.getDefault().getOffset(ts) / (1000 * 60 * 60)); ts /= 1000; @@ -98,6 +107,24 @@ public class MijiaLywsd02Support extends AbstractBTLEDeviceSupport { offsetHours}); } + private void getBatteryInfo(TransactionBuilder builder) { + BluetoothGattCharacteristic batteryCharacteristc = getCharacteristic(MijiaLywsd02Support.UUID_BATTERY); + builder.read(batteryCharacteristc); + } + + private void setTemperatureScale(TransactionBuilder builder, String scale) { + BluetoothGattCharacteristic scaleCharacteristc = getCharacteristic(MijiaLywsd02Support.UUID_SCALE); + builder.write(scaleCharacteristc, new byte[]{ (byte) ("f".equals(scale) ? 0x01 : 0xff) }); + builder.queue(getQueue()); + } + + private void handleBatteryInfo(byte[] value, int status) { + if (status == BluetoothGatt.GATT_SUCCESS) { + batteryCmd.level = ((short) value[0]); + handleGBDeviceEvent(batteryCmd); + } + } + private void requestDeviceInfo(TransactionBuilder builder) { LOG.debug("Requesting Device Info!"); deviceInfoProfile.requestDeviceInfo(builder); @@ -144,7 +171,27 @@ public class MijiaLywsd02Support extends AbstractBTLEDeviceSupport { } UUID characteristicUUID = characteristic.getUuid(); + if(MijiaLywsd02Support.UUID_BATTERY.equals(characteristicUUID)) { + handleBatteryInfo(characteristic.getValue(), status); + return true; + } LOG.info("Unhandled characteristic read: " + characteristicUUID); return false; } + + @Override + public void onSendConfiguration(String config) { + TransactionBuilder builder; + try { + switch (config) { + case DeviceSettingsPreferenceConst.PREF_TEMPERATURE_SCALE_CF: + String temperatureScale = GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()).getString(DeviceSettingsPreferenceConst.PREF_TEMPERATURE_SCALE_CF, ""); + builder = performInitialized("Sending configuration for option: " + config); + setTemperatureScale(builder, temperatureScale); + break; + } + } catch (IOException e) { + GB.toast("Error setting configuration", Toast.LENGTH_LONG, GB.ERROR, e); + } + } } diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 76a3dc6dd..3fb277a00 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -3394,4 +3394,13 @@ purple white + + + @string/temperature_scale_celsius + @string/temperature_scale_fahrenheit + + + c + f + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index dce2225c8..23da5e57d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2351,4 +2351,9 @@ Siren Short No LED + + Temperature scale + Select whether device uses Celsius or Fahrenheit scale. + Celsius + Fahrenheit diff --git a/app/src/main/res/xml/devicesettings_temperature_scale_cf.xml b/app/src/main/res/xml/devicesettings_temperature_scale_cf.xml new file mode 100644 index 000000000..f17c947a2 --- /dev/null +++ b/app/src/main/res/xml/devicesettings_temperature_scale_cf.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file