Marstek B2500: initial support

Supported
- setting the time
- setting/getting the minimum charge of the battery that shall remain
- setting/getting 5 time intervals with output wattage and enable/disable switch
- getting the firmware version

TODO:
- check if times overlap
- check if we can output less than 80W (offical app only supports 80-800)
- research about the "automatic mode"
- research about unknown values we get from the two info calls

This has been tested with Firmware V220
I only have a very brief capture of V210 which obviously had less feature. I tried to somehow support it but I am not sure
This commit is contained in:
Andreas Shimokawa 2024-12-15 00:34:46 +01:00
parent 7ff1e87ea8
commit f79930fad9
9 changed files with 548 additions and 1 deletions

View File

@ -18,6 +18,7 @@ package nodomain.freeyourgadget.gadgetbridge.activities;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.text.InputType;
import android.text.TextUtils;
import androidx.annotation.NonNull;
@ -53,6 +54,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.XTimePreferenceFragment;
import nodomain.freeyourgadget.gadgetbridge.util.dialogs.MaterialEditTextPreferenceDialogFragment;
import nodomain.freeyourgadget.gadgetbridge.util.dialogs.MaterialListPreferenceDialogFragment;
import nodomain.freeyourgadget.gadgetbridge.util.dialogs.MaterialMultiSelectListPreferenceDialogFragment;
import nodomain.freeyourgadget.gadgetbridge.util.preferences.MinMaxTextWatcher;
public abstract class AbstractPreferenceFragment extends PreferenceFragmentCompat {
protected static final Logger LOG = LoggerFactory.getLogger(AbstractPreferenceFragment.class);
@ -142,6 +144,17 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragmentCompa
}
}
public void setNumericInputTypeWithRangeFor(final String preferenceKey, int min, int max, boolean allowEmpty) {
final EditTextPreference textPreference = findPreference(preferenceKey);
if (textPreference != null) {
textPreference.setOnBindEditTextListener(editText -> {
editText.setInputType(InputType.TYPE_CLASS_NUMBER);
editText.addTextChangedListener(new MinMaxTextWatcher(editText, min, max, allowEmpty));
editText.setSelection(editText.getText().length());
});
}
}
/**
* Reload the preferences in the current screen. This is needed when the user enters or exists a PreferenceScreen,
* otherwise the settings won't be reloaded by the {@link SharedPreferencesChangeHandler}, as the preferences return

View File

@ -589,4 +589,13 @@ public class DeviceSettingsPreferenceConst {
public static final String PREFS_KEY_DEVICE_BLE_API_DEVICE_READ_WRITE = "prefs_device_ble_api_characteristic_read_write";
public static final String PREFS_KEY_DEVICE_BLE_API_DEVICE_NOTIFY = "prefs_device_ble_api_characteristic_notify";
public static final String PREFS_KEY_DEVICE_BLE_API_PACKAGE = "prefs_device_ble_api_package";
public static final String PREF_BATTERY_DISCHARGE_INTERVAL1_WATT = "battery_discharge_interval1_watt";
public static final String PREF_BATTERY_DISCHARGE_INTERVAL2_WATT = "battery_discharge_interval2_watt";
public static final String PREF_BATTERY_DISCHARGE_INTERVAL3_WATT = "battery_discharge_interval3_watt";
public static final String PREF_BATTERY_DISCHARGE_INTERVAL4_WATT = "battery_discharge_interval4_watt";
public static final String PREF_BATTERY_DISCHARGE_INTERVAL5_WATT = "battery_discharge_interval5_watt";
public static final String PREF_BATTERY_DISCHARGE_INTERVALS_SET = "battery_discharge_intervals_set";
public static final String PREF_BATTERY_DISCHARGE_MANAUAL = "battery_discharge_manual";
public static final String PREF_BATTERY_MINIMUM_CHARGE = "battery_minimum_charge";
}

View File

@ -42,6 +42,7 @@ import android.media.AudioManager;
import android.os.Bundle;
import android.text.InputType;
import androidx.annotation.NonNull;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.preference.EditTextPreference;
import androidx.preference.ListPreference;
@ -882,6 +883,16 @@ public class DeviceSpecificSettingsFragment extends AbstractPreferenceFragment i
addPreferenceHandlerFor("lock");
addPreferenceHandlerFor(PREF_BATTERY_MINIMUM_CHARGE);
final Preference dischargeIntervalsSet = findPreference(PREF_BATTERY_DISCHARGE_INTERVALS_SET);
if (dischargeIntervalsSet != null) {
dischargeIntervalsSet.setOnPreferenceClickListener(preference -> {
notifyPreferenceChanged(PREF_BATTERY_DISCHARGE_INTERVALS_SET);
return true;
});
}
String sleepTimeState = prefs.getString(PREF_SLEEP_TIME, PREF_DO_NOT_DISTURB_OFF);
boolean sleepTimeScheduled = sleepTimeState.equals(PREF_DO_NOT_DISTURB_SCHEDULED);
@ -1203,6 +1214,12 @@ public class DeviceSpecificSettingsFragment extends AbstractPreferenceFragment i
setInputTypeFor(DeviceSettingsPreferenceConst.PREF_BANGLEJS_TEXT_BITMAP_SIZE, InputType.TYPE_CLASS_NUMBER);
setInputTypeFor(DeviceSettingsPreferenceConst.PREF_AUTO_REPLY_INCOMING_CALL_DELAY, InputType.TYPE_CLASS_NUMBER);
setInputTypeFor("hplus_screentime", InputType.TYPE_CLASS_NUMBER);
setNumericInputTypeWithRangeFor(DeviceSettingsPreferenceConst.PREF_BATTERY_DISCHARGE_INTERVAL1_WATT, 80, 800, false);
setNumericInputTypeWithRangeFor(DeviceSettingsPreferenceConst.PREF_BATTERY_DISCHARGE_INTERVAL2_WATT, 80, 800, false);
setNumericInputTypeWithRangeFor(DeviceSettingsPreferenceConst.PREF_BATTERY_DISCHARGE_INTERVAL3_WATT, 80, 800, false);
setNumericInputTypeWithRangeFor(DeviceSettingsPreferenceConst.PREF_BATTERY_DISCHARGE_INTERVAL4_WATT, 80, 800, false);
setNumericInputTypeWithRangeFor(DeviceSettingsPreferenceConst.PREF_BATTERY_DISCHARGE_INTERVAL5_WATT, 80, 800, false);
setNumericInputTypeWithRangeFor(PREF_BATTERY_MINIMUM_CHARGE, 0, 100, false);
new PasswordCapabilityImpl().registerPreferences(getContext(), coordinator.getPasswordCapability(), this);
new HeartRateCapability().registerPreferences(getContext(), coordinator.getHeartRateMeasurementIntervals(), this);
@ -1382,7 +1399,7 @@ public class DeviceSpecificSettingsFragment extends AbstractPreferenceFragment i
DeviceSpecificSettingsScreen.DEVELOPER,
R.xml.devicesettings_settings_third_party_apps
);
if(coordinator.getConnectionType().usesBluetoothLE()) {
if (coordinator.getConnectionType().usesBluetoothLE()) {
deviceSpecificSettings.addRootScreen(
DeviceSpecificSettingsScreen.DEVELOPER,
R.xml.devicesettings_ble_api

View File

@ -0,0 +1,68 @@
package nodomain.freeyourgadget.gadgetbridge.devices.marstek;
import androidx.annotation.NonNull;
import java.util.regex.Pattern;
import nodomain.freeyourgadget.gadgetbridge.GBException;
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractDeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.marstek.MarstekB2500DeviceSupport;
public class MarstekB2500DeviceCoordinator extends AbstractDeviceCoordinator {
@Override
public int getDeviceNameResource() {
return R.string.devicetype_marstek_b2500;
}
@Override
public int getDefaultIconResource() {
return R.drawable.ic_device_vesc;
}
@Override
public int getDisabledIconResource() {
return R.drawable.ic_device_vesc_disabled;
}
@Override
public String getManufacturer() {
return "Marstek";
}
@NonNull
@Override
public Class<? extends DeviceSupport> getDeviceSupportClass() {
return MarstekB2500DeviceSupport.class;
}
@Override
protected Pattern getSupportedDeviceName() {
return Pattern.compile("HM_B2500_.*");
}
@Override
protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) throws GBException {
}
@Override
public int getBondingStyle() {
return BONDING_STYLE_NONE;
}
@Override
public int[] getSupportedDeviceSpecificSettings(GBDevice device) {
return new int[]{
R.xml.devicesettings_battery_minimum_charge,
R.xml.devicesettings_battery_discharge_5
};
}
}

View File

@ -218,6 +218,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.lefun.VivitarHrBpMonitorActi
import nodomain.freeyourgadget.gadgetbridge.devices.lenovo.watchxplus.WatchXPlusDeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.liveview.LiveviewCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.makibeshr3.MakibesHR3Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.marstek.MarstekB2500DeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.mijia_lywsd.MijiaLywsd02Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.mijia_lywsd.MijiaLywsd03Coordinator;
@ -581,6 +582,7 @@ public enum DeviceType {
SCANNABLE(ScannableDeviceCoordinator.class),
CYCLING_SENSOR(CyclingSensorCoordinator.class),
BLE_GATT_CLIENT(BleGattClientCoordinator.class),
MARSTEK_B2500(MarstekB2500DeviceCoordinator.class),
TEST(TestDeviceCoordinator.class);
private DeviceCoordinator coordinator;

View File

@ -0,0 +1,246 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.marstek;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_BATTERY_DISCHARGE_INTERVALS_SET;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_BATTERY_DISCHARGE_MANAUAL;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_BATTERY_MINIMUM_CHARGE;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.content.SharedPreferences;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.time.LocalTime;
import java.util.Calendar;
import java.util.SimpleTimeZone;
import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
public class MarstekB2500DeviceSupport extends AbstractBTLEDeviceSupport {
public static final UUID UUID_CHARACTERISTIC_MAIN = UUID.fromString("0000ff02-0000-1000-8000-00805f9b34fb");
public static final UUID UUID_SERVICE_MAIN = UUID.fromString("0000ff00-0000-1000-8000-00805f9b34fb");
private static final byte COMMAND_PREFIX = 0x73;
private static final byte[] COMMAND_GET_INFOS = new byte[]{COMMAND_PREFIX, 0x06, 0x23, 0x03, 0x01, 0x54};
private static final byte[] COMMAND_GET_INFOS2 = new byte[]{COMMAND_PREFIX, 0x06, 0x23, 0x13, 0x00, 0x45};
private static final Logger LOG = LoggerFactory.getLogger(MarstekB2500DeviceSupport.class);
private int firmwareVersion;
public MarstekB2500DeviceSupport() {
super(LOG);
addSupportedService(UUID_SERVICE_MAIN);
}
@Override
public boolean onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
UUID characteristicUUID = characteristic.getUuid();
byte[] value = characteristic.getValue();
LOG.info("Characteristic changed UUID: {}", characteristicUUID);
LOG.info("Characteristic changed value: {}", StringUtils.bytesToHex(value));
if (value[0] == COMMAND_PREFIX) {
if ((value[1] == 0x10) && (value[2] == 0x23) && (value[3] == 0x03)) {
firmwareVersion = value[12];
getDevice().setFirmwareVersion("V" + (firmwareVersion & 0xff));
getDevice().sendDeviceUpdateIntent(getContext());
int battery_minimum_charge = 100 - value[18];
Prefs devicePrefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress()));
SharedPreferences.Editor devicePrefsEdit = devicePrefs.getPreferences().edit();
devicePrefsEdit.putString(PREF_BATTERY_MINIMUM_CHARGE, String.valueOf(battery_minimum_charge));
devicePrefsEdit.apply();
devicePrefsEdit.commit();
return true;
} else if ((value[1] == 0x3a || value[1] == 0x22) && value[2] == 0x23 && value[3] == 0x13) {
decodeDischargeIntervalsToPreferences(value);
return true;
}
}
return false;
}
@Override
public void onTestNewFunction() {
sendCommand("test", COMMAND_GET_INFOS);
}
@Override
protected TransactionBuilder initializeDevice(TransactionBuilder builder) {
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZING, getContext()));
getDevice().setFirmwareVersion("N/A");
getDevice().setFirmwareVersion2("N/A");
builder.requestMtu(512);
builder.notify(getCharacteristic(UUID_CHARACTERISTIC_MAIN), true);
builder.wait(800);
builder.write(getCharacteristic(UUID_CHARACTERISTIC_MAIN), COMMAND_GET_INFOS);
builder.wait(800);
builder.write(getCharacteristic(UUID_CHARACTERISTIC_MAIN), COMMAND_GET_INFOS2);
builder.wait(800);
builder.write(getCharacteristic(UUID_CHARACTERISTIC_MAIN), encodeSetCurrentTime());
builder.wait(800);
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZED, getContext()));
return builder;
}
@Override
public boolean useAutoConnect() {
return false;
}
private void sendCommand(String taskName, byte[] contents) {
TransactionBuilder builder = new TransactionBuilder(taskName);
BluetoothGattCharacteristic characteristic = getCharacteristic(UUID_CHARACTERISTIC_MAIN);
if (characteristic != null && contents != null) {
builder.write(characteristic, contents);
builder.wait(800);
builder.queue(getQueue());
}
}
@Override
public void onSetTime() {
sendCommand("set time", encodeSetCurrentTime());
}
@Override
public void onSendConfiguration(final String config) {
if (config.equals(PREF_BATTERY_DISCHARGE_INTERVALS_SET)) {
sendCommand("set discharge intervals", encodeDischargeIntervalsFromPreferences());
return;
} else if (config.equals(PREF_BATTERY_MINIMUM_CHARGE)) {
sendCommand("set minimum charge", encodeMinimumChargeFromPreferences());
return;
}
LOG.warn("Unknown config changed: {}", config);
}
private void decodeDischargeIntervalsToPreferences(byte[] values) {
Prefs devicePrefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress()));
SharedPreferences.Editor devicePrefsEdit = devicePrefs.getPreferences().edit();
ByteBuffer buf = ByteBuffer.wrap(values);
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.position(5); // skip
for (int i = 1; i <= 5; i++) {
boolean enabled = buf.get() != 0x00;
int startHour = buf.get();
int startMinute = buf.get();
int endHour = buf.get();
int endMinute = buf.get();
int watt = buf.getShort();
devicePrefsEdit.putBoolean("battery_discharge_interval" + i + "_enabled", enabled);
devicePrefsEdit.putString("battery_discharge_interval" + i + "_start", DateTimeUtils.formatTime(startHour, startMinute));
devicePrefsEdit.putString("battery_discharge_interval" + i + "_end", DateTimeUtils.formatTime(endHour, endMinute));
devicePrefsEdit.putString("battery_discharge_interval" + i + "_watt", String.valueOf(watt));
if (i == 3) {
if (values.length == 0x22) // old fw only seems to return 3 settings and has 7 trailing bytes
break;
buf.position(buf.position() + 17); // skip 17 bytes, there is a hole with unknown data
}
}
devicePrefsEdit.apply();
devicePrefsEdit.commit();
}
private byte[] encodeMinimumChargeFromPreferences() {
Prefs devicePrefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress()));
int minimum_charge = devicePrefs.getInt(PREF_BATTERY_MINIMUM_CHARGE, 10);
int maximum_use = 100 - minimum_charge;
byte length = 6;
ByteBuffer buf = ByteBuffer.allocate(length);
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.put(COMMAND_PREFIX);
buf.put(length);
buf.put((byte) 0x23);
buf.put((byte) 0x0b);
buf.put((byte) maximum_use);
buf.put(getXORChecksum(buf.array()));
return buf.array();
}
private byte[] encodeSetCurrentTime() {
long ts = System.currentTimeMillis();
long ts_offset = (SimpleTimeZone.getDefault().getOffset(ts));
byte length = 13;
ByteBuffer buf = ByteBuffer.allocate(length);
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.put(COMMAND_PREFIX);
buf.put(length);
buf.put((byte) 0x23);
buf.put((byte) 0x14);
final Calendar calendar = DateTimeUtils.getCalendarUTC();
buf.put((byte) ((calendar.get(Calendar.YEAR) - 1900) & 0xff));
buf.put((byte) calendar.get(Calendar.MONTH));
buf.put((byte) calendar.get(Calendar.DAY_OF_MONTH));
buf.put((byte) calendar.get(Calendar.HOUR_OF_DAY));
buf.put((byte) calendar.get(Calendar.MINUTE));
buf.put((byte) calendar.get(Calendar.SECOND));
buf.putShort((short) (ts_offset / 60000));
buf.put(getXORChecksum(buf.array()));
return buf.array();
}
private byte[] encodeDischargeIntervalsFromPreferences() {
Prefs devicePrefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress()));
if (devicePrefs.getBoolean(PREF_BATTERY_DISCHARGE_MANAUAL, true)) {
int nr_invervals = (firmwareVersion >= 220) ? 5 : 3; // old firmware V210 only had 3 intervals it seems, so set only 3
int length = 5 + nr_invervals * 7;
ByteBuffer buf = ByteBuffer.allocate(length);
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.put(COMMAND_PREFIX);
buf.put((byte) length);
buf.put((byte) 0x23); // set power parameters ?
buf.put((byte) 0x12); // set discharge power timers ?
for (int i = 1; i <= nr_invervals; i++) {
boolean enabled = devicePrefs.getBoolean("battery_discharge_interval" + i + "_enabled", false);
LocalTime startTime = devicePrefs.getLocalTime("battery_discharge_interval" + i + "_start", "00:00");
LocalTime endTime = devicePrefs.getLocalTime("battery_discharge_interval" + i + "_end", "00:00");
short watt = (short) devicePrefs.getInt("battery_discharge_interval" + i + "_watt", 80);
buf.put((byte) (enabled ? 0x01 : 0x00));
buf.put((byte) startTime.getHour());
buf.put((byte) startTime.getMinute());
buf.put((byte) endTime.getHour());
buf.put((byte) endTime.getMinute());
buf.putShort(watt);
}
buf.put(getXORChecksum(buf.array()));
return buf.array();
}
return null;
}
private byte getXORChecksum(byte[] command) {
byte checksum = 0;
for (byte b : command) {
checksum ^= b;
}
return checksum;
}
}

View File

@ -3557,4 +3557,16 @@
<string name="permission_query_all_packages_title">Query all packages</string>
<string name="permission_query_all_packages_summary">Reading names and icons of all installed apps</string>
<string name="about_build_details_copied_to_clipboard">Build details copied to clipboard</string>
<string name="devicetype_marstek_b2500">Marstek B2500</string>
<string name="battery_discharge_intervals">Battery Discharge Intervals</string>
<string name="discharge_interval_1">Discharge Interval 1</string>
<string name="discharge_interval_2">Discharge Interval 2</string>
<string name="discharge_interval_3">Discharge Interval 3</string>
<string name="discharge_interval_4">Discharge Interval 4</string>
<string name="discharge_interval_5">Discharge Interval 5</string>
<string name="power_w">Power in W</string>
<string name="manual_discharge_summary">when disabled, this assumes intelligent discharge controlled by an external power meter (not supported by Gadgetbridge)</string>
<string name="manual_discharge">Manual Discharge Intervals</string>
<string name="summary_battery_discharge_intervals_set">Send configuration below to device</string>
<string name="battery_minimum_charge">Minimum allowed charge in %</string>
</resources>

View File

@ -0,0 +1,169 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceScreen
android:icon="@drawable/ic_battery"
android:key="screen_battery_discharge settings"
android:persistent="false"
android:title="@string/battery_discharge_intervals">
<Preference
android:icon="@drawable/ic_refresh"
android:key="battery_discharge_intervals_set"
android:summary="@string/summary_battery_discharge_intervals_set"
android:title="@string/pref_title_canned_messages_set" />
<SwitchPreferenceCompat
android:defaultValue="true"
android:key="battery_discharge_manual"
android:layout="@layout/preference_checkbox"
android:summary="@string/manual_discharge_summary"
android:title="@string/manual_discharge" />
<PreferenceCategory
android:dependency="battery_discharge_manual"
android:title="@string/discharge_interval_1">
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="battery_discharge_interval1_enabled"
android:layout="@layout/preference_checkbox"
android:title="@string/function_enabled" />
<nodomain.freeyourgadget.gadgetbridge.util.XTimePreference
android:defaultValue="00:00"
android:icon="@drawable/ic_access_time"
android:key="battery_discharge_interval1_start"
android:title="@string/mi2_prefs_do_not_disturb_start" />
<nodomain.freeyourgadget.gadgetbridge.util.XTimePreference
android:defaultValue="00:00"
android:icon="@drawable/ic_access_time"
android:key="battery_discharge_interval1_end"
android:title="@string/mi2_prefs_do_not_disturb_end" />
<EditTextPreference
android:defaultValue="80"
android:inputType="number"
android:key="battery_discharge_interval1_watt"
android:title="@string/power_w"
app:useSimpleSummaryProvider="true" />
</PreferenceCategory>
<PreferenceCategory
android:dependency="battery_discharge_manual"
android:title="@string/discharge_interval_2">
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="battery_discharge_interval2_enabled"
android:layout="@layout/preference_checkbox"
android:title="@string/function_enabled" />
<nodomain.freeyourgadget.gadgetbridge.util.XTimePreference
android:defaultValue="00:00"
android:icon="@drawable/ic_access_time"
android:key="battery_discharge_interval2_start"
android:title="@string/mi2_prefs_do_not_disturb_start" />
<nodomain.freeyourgadget.gadgetbridge.util.XTimePreference
android:defaultValue="00:00"
android:icon="@drawable/ic_access_time"
android:key="battery_discharge_interval2_end"
android:title="@string/mi2_prefs_do_not_disturb_end" />
<EditTextPreference
android:defaultValue="80"
android:inputType="number"
android:key="battery_discharge_interval2_watt"
android:title="@string/power_w"
app:useSimpleSummaryProvider="true" />
</PreferenceCategory>
<PreferenceCategory
android:dependency="battery_discharge_manual"
android:title="@string/discharge_interval_3">
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="battery_discharge_interval3_enabled"
android:layout="@layout/preference_checkbox"
android:title="@string/function_enabled" />
<nodomain.freeyourgadget.gadgetbridge.util.XTimePreference
android:defaultValue="00:00"
android:icon="@drawable/ic_access_time"
android:key="battery_discharge_interval3_start"
android:title="@string/mi2_prefs_do_not_disturb_start" />
<nodomain.freeyourgadget.gadgetbridge.util.XTimePreference
android:defaultValue="00:00"
android:icon="@drawable/ic_access_time"
android:key="battery_discharge_interval3_end"
android:title="@string/mi2_prefs_do_not_disturb_end" />
<EditTextPreference
android:defaultValue="80"
android:inputType="number"
android:key="battery_discharge_interval3_watt"
android:title="@string/power_w"
app:useSimpleSummaryProvider="true" />
</PreferenceCategory>
<PreferenceCategory
android:dependency="battery_discharge_manual"
android:title="@string/discharge_interval_4">
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="battery_discharge_interval4_enabled"
android:layout="@layout/preference_checkbox"
android:title="@string/function_enabled" />
<nodomain.freeyourgadget.gadgetbridge.util.XTimePreference
android:defaultValue="00:00"
android:icon="@drawable/ic_access_time"
android:key="battery_discharge_interval4_start"
android:title="@string/mi2_prefs_do_not_disturb_start" />
<nodomain.freeyourgadget.gadgetbridge.util.XTimePreference
android:defaultValue="00:00"
android:icon="@drawable/ic_access_time"
android:key="battery_discharge_interval4_end"
android:title="@string/mi2_prefs_do_not_disturb_end" />
<EditTextPreference
android:defaultValue="80"
android:inputType="number"
android:key="battery_discharge_interval4_watt"
android:title="@string/power_w"
app:useSimpleSummaryProvider="true" />
</PreferenceCategory>
<PreferenceCategory
android:dependency="battery_discharge_manual"
android:title="@string/discharge_interval_5">
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="battery_discharge_interval5_enabled"
android:layout="@layout/preference_checkbox"
android:title="@string/function_enabled" />
<nodomain.freeyourgadget.gadgetbridge.util.XTimePreference
android:defaultValue="00:00"
android:icon="@drawable/ic_access_time"
android:key="battery_discharge_interval5_start"
android:title="@string/mi2_prefs_do_not_disturb_start" />
<nodomain.freeyourgadget.gadgetbridge.util.XTimePreference
android:defaultValue="00:00"
android:icon="@drawable/ic_access_time"
android:key="battery_discharge_interval5_end"
android:title="@string/mi2_prefs_do_not_disturb_end" />
<EditTextPreference
android:defaultValue="80"
android:inputType="number"
android:key="battery_discharge_interval5_watt"
android:title="@string/power_w"
app:useSimpleSummaryProvider="true" />
</PreferenceCategory>
</PreferenceScreen>
</androidx.preference.PreferenceScreen>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<EditTextPreference
android:icon="@drawable/ic_battery"
android:defaultValue="10"
android:inputType="number"
android:key="battery_minimum_charge"
android:title="@string/battery_minimum_charge"
app:useSimpleSummaryProvider="true" />
</androidx.preference.PreferenceScreen>