mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2025-01-25 08:05:55 +01:00
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:
parent
7ff1e87ea8
commit
f79930fad9
@ -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
|
||||
|
@ -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";
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
};
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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>
|
||||
|
169
app/src/main/res/xml/devicesettings_battery_discharge_5.xml
Normal file
169
app/src/main/res/xml/devicesettings_battery_discharge_5.xml
Normal 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>
|
@ -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>
|
Loading…
Reference in New Issue
Block a user