mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2025-01-27 09:01:38 +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.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.text.InputType;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
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.MaterialEditTextPreferenceDialogFragment;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.dialogs.MaterialListPreferenceDialogFragment;
|
import nodomain.freeyourgadget.gadgetbridge.util.dialogs.MaterialListPreferenceDialogFragment;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.dialogs.MaterialMultiSelectListPreferenceDialogFragment;
|
import nodomain.freeyourgadget.gadgetbridge.util.dialogs.MaterialMultiSelectListPreferenceDialogFragment;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.preferences.MinMaxTextWatcher;
|
||||||
|
|
||||||
public abstract class AbstractPreferenceFragment extends PreferenceFragmentCompat {
|
public abstract class AbstractPreferenceFragment extends PreferenceFragmentCompat {
|
||||||
protected static final Logger LOG = LoggerFactory.getLogger(AbstractPreferenceFragment.class);
|
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,
|
* 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
|
* 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_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_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 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.os.Bundle;
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||||
import androidx.preference.EditTextPreference;
|
import androidx.preference.EditTextPreference;
|
||||||
import androidx.preference.ListPreference;
|
import androidx.preference.ListPreference;
|
||||||
@ -882,6 +883,16 @@ public class DeviceSpecificSettingsFragment extends AbstractPreferenceFragment i
|
|||||||
|
|
||||||
addPreferenceHandlerFor("lock");
|
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);
|
String sleepTimeState = prefs.getString(PREF_SLEEP_TIME, PREF_DO_NOT_DISTURB_OFF);
|
||||||
boolean sleepTimeScheduled = sleepTimeState.equals(PREF_DO_NOT_DISTURB_SCHEDULED);
|
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_BANGLEJS_TEXT_BITMAP_SIZE, InputType.TYPE_CLASS_NUMBER);
|
||||||
setInputTypeFor(DeviceSettingsPreferenceConst.PREF_AUTO_REPLY_INCOMING_CALL_DELAY, InputType.TYPE_CLASS_NUMBER);
|
setInputTypeFor(DeviceSettingsPreferenceConst.PREF_AUTO_REPLY_INCOMING_CALL_DELAY, InputType.TYPE_CLASS_NUMBER);
|
||||||
setInputTypeFor("hplus_screentime", 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 PasswordCapabilityImpl().registerPreferences(getContext(), coordinator.getPasswordCapability(), this);
|
||||||
new HeartRateCapability().registerPreferences(getContext(), coordinator.getHeartRateMeasurementIntervals(), this);
|
new HeartRateCapability().registerPreferences(getContext(), coordinator.getHeartRateMeasurementIntervals(), this);
|
||||||
|
@ -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.lenovo.watchxplus.WatchXPlusDeviceCoordinator;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.liveview.LiveviewCoordinator;
|
import nodomain.freeyourgadget.gadgetbridge.devices.liveview.LiveviewCoordinator;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.makibeshr3.MakibesHR3Coordinator;
|
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.miband.MiBandCoordinator;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.mijia_lywsd.MijiaLywsd02Coordinator;
|
import nodomain.freeyourgadget.gadgetbridge.devices.mijia_lywsd.MijiaLywsd02Coordinator;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.mijia_lywsd.MijiaLywsd03Coordinator;
|
import nodomain.freeyourgadget.gadgetbridge.devices.mijia_lywsd.MijiaLywsd03Coordinator;
|
||||||
@ -581,6 +582,7 @@ public enum DeviceType {
|
|||||||
SCANNABLE(ScannableDeviceCoordinator.class),
|
SCANNABLE(ScannableDeviceCoordinator.class),
|
||||||
CYCLING_SENSOR(CyclingSensorCoordinator.class),
|
CYCLING_SENSOR(CyclingSensorCoordinator.class),
|
||||||
BLE_GATT_CLIENT(BleGattClientCoordinator.class),
|
BLE_GATT_CLIENT(BleGattClientCoordinator.class),
|
||||||
|
MARSTEK_B2500(MarstekB2500DeviceCoordinator.class),
|
||||||
TEST(TestDeviceCoordinator.class);
|
TEST(TestDeviceCoordinator.class);
|
||||||
|
|
||||||
private DeviceCoordinator coordinator;
|
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_title">Query all packages</string>
|
||||||
<string name="permission_query_all_packages_summary">Reading names and icons of all installed apps</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="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>
|
</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