From db92b5808364813e4e8883ed5b1b167bfbe56e21 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Wed, 24 Dec 2025 12:09:10 +0100 Subject: [PATCH] Zendure SolarFlow: parse firmware version, allow setting maximum charge --- .../DeviceSettingsPreferenceConst.java | 1 + .../DeviceSpecificSettingsFragment.java | 1 + .../zendure/SolarFlowDeviceCoordinator.java | 1 + .../zendure/SolarFlowDeviceSupport.java | 105 ++++++++++-------- app/src/main/res/values/strings.xml | 1 + .../devicesettings_battery_maximum_charge.xml | 10 ++ 6 files changed, 75 insertions(+), 44 deletions(-) create mode 100644 app/src/main/res/xml/devicesettings_battery_maximum_charge.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 d1e7e867b7..778fa9572a 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 @@ -677,6 +677,7 @@ public class DeviceSettingsPreferenceConst { public static final String PREF_BATTERY_DISCHARGE_INTERVALS_SET = "battery_discharge_intervals_set"; public static final String PREF_BATTERY_DISCHARGE_MANUAL = "battery_discharge_manual"; public static final String PREF_BATTERY_MINIMUM_CHARGE = "battery_minimum_charge"; + public static final String PREF_BATTERY_MAXIMUM_CHARGE = "battery_maximum_charge"; public static final String PREF_BATTERY_ALLOW_PASS_THROUGH = "battery_allow_pass_through"; public static final String PREF_DISPLAY_ENABLED = "display_enabled"; 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 dead06be09..ef5e5b2c27 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 @@ -1001,6 +1001,7 @@ public class DeviceSpecificSettingsFragment extends AbstractPreferenceFragment i addPreferenceHandlerFor("lock"); addPreferenceHandlerFor(PREF_BATTERY_MINIMUM_CHARGE); + addPreferenceHandlerFor(PREF_BATTERY_MAXIMUM_CHARGE); addPreferenceHandlerFor(PREF_BATTERY_ALLOW_PASS_THROUGH); addPreferenceHandlerFor(PREF_DISPLAY_ENABLED); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/zendure/SolarFlowDeviceCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/zendure/SolarFlowDeviceCoordinator.java index e2e72eaee7..4d2ae31976 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/zendure/SolarFlowDeviceCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/zendure/SolarFlowDeviceCoordinator.java @@ -90,6 +90,7 @@ public class SolarFlowDeviceCoordinator extends AbstractBLEDeviceCoordinator { public int[] getSupportedDeviceSpecificSettings(GBDevice device) { return new int[]{ R.xml.devicesettings_battery_minimum_charge, + R.xml.devicesettings_battery_maximum_charge, }; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/zendure/SolarFlowDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/zendure/SolarFlowDeviceSupport.java index c29a473a5f..4eaa7ec932 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/zendure/SolarFlowDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/zendure/SolarFlowDeviceSupport.java @@ -16,6 +16,7 @@ along with this program. If not, see . */ package nodomain.freeyourgadget.gadgetbridge.service.devices.zendure; +import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_BATTERY_MAXIMUM_CHARGE; import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_BATTERY_MINIMUM_CHARGE; import android.bluetooth.BluetoothGatt; @@ -59,6 +60,7 @@ public class SolarFlowDeviceSupport extends AbstractBTLESingleDeviceSupport { private int hyperTmp; private int electricLevel = -1; private String deviceId; + private int firmwareVersion = -1; public SolarFlowDeviceSupport() { super(LOG); @@ -74,47 +76,49 @@ public class SolarFlowDeviceSupport extends AbstractBTLESingleDeviceSupport { if (jsonMessage.has("method")) { String method = jsonMessage.getString("method"); - if (method.equals("BLESPP")) { - deviceId = jsonMessage.getString("deviceId"); - JSONObject sendMessage = new JSONObject() - .put("messageId", messageId++) - .put("method", "BLESPP_OK"); + switch (method) { + case "BLESPP" -> { + deviceId = jsonMessage.getString("deviceId"); + JSONObject sendMessage = new JSONObject() + .put("messageId", messageId++) + .put("method", "BLESPP_OK"); - sendMessage(sendMessage); + sendMessage(sendMessage); - JSONObject sendMessageGetInfo = new JSONObject() - .put("messageId", messageId++) - .put("method", "getInfo") - .put("timestamp", System.currentTimeMillis() / 1000); - sendMessage(sendMessageGetInfo); - - JSONObject sendMessageGetAllInfos = new JSONObject() - .put("messageId", messageId++) - .put("deviceId", deviceId) - .put("method", "read") - .put("properties", new JSONArray().put("getAll")) - .put("timestamp", System.currentTimeMillis() / 1000); - sendMessage(sendMessageGetAllInfos); - } else if (method.equals("report")) { - long messageIdReport = jsonMessage.getLong("messageId"); - if (messageIdReport != this.messageIdReport) { - if (this.messageIdReport != -1) { - reportToStatusActivity(); - } else { - TransactionBuilder builder = createTransactionBuilder("setInitialized"); - builder.setDeviceState(GBDevice.State.INITIALIZED); - builder.queue(); + JSONObject sendMessageGetInfo = new JSONObject() + .put("messageId", messageId++) + .put("method", "getInfo") + .put("timestamp", System.currentTimeMillis() / 1000); + sendMessage(sendMessageGetInfo); + } + case "getInfo-rsp" -> { + JSONObject sendMessageGetAllInfos = new JSONObject() + .put("messageId", messageId++) + .put("deviceId", deviceId) + .put("method", "read") + .put("properties", new JSONArray().put("getAll")) + .put("timestamp", System.currentTimeMillis() / 1000); + sendMessage(sendMessageGetAllInfos); + } + case "report" -> { + long messageIdReport = jsonMessage.getLong("messageId"); + if (messageIdReport != this.messageIdReport) { + if (this.messageIdReport != -1) { + reportToStatusActivity(); + } else { + TransactionBuilder builder = createTransactionBuilder("setInitialized"); + builder.setDeviceState(GBDevice.State.INITIALIZED); + builder.queue(); + } + this.messageIdReport = messageIdReport; + } + if (jsonMessage.has("properties")) { + return handleReportProperties(jsonMessage.getJSONObject("properties")); + } + if (jsonMessage.has("packData")) { + return handleReportPackData(jsonMessage.getJSONArray("packData")); } - this.messageIdReport = messageIdReport; - } - if (jsonMessage.has("properties")) { - return handleReportProperties(jsonMessage.getJSONObject("properties")); - } - if (jsonMessage.has("packData")) { - return handleReportPackData(jsonMessage.getJSONArray("packData")); - } - } } } catch (JSONException e) { @@ -144,14 +148,19 @@ public class SolarFlowDeviceSupport extends AbstractBTLESingleDeviceSupport { public void onSendConfiguration(final String config) { Prefs devicePrefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress())); switch (config) { - case PREF_BATTERY_MINIMUM_CHARGE: + case PREF_BATTERY_MINIMUM_CHARGE -> { int minSoc = devicePrefs.getInt(PREF_BATTERY_MINIMUM_CHARGE, 10); if (minSoc < 0) minSoc = 0; if (minSoc > 50) minSoc = 50; - sendWriteProperty("minSoc", minSoc*10); - return; - default: - LOG.warn("Unknown config changed: {}", config); + sendWriteProperty("minSoc", minSoc * 10); + } + case PREF_BATTERY_MAXIMUM_CHARGE -> { + int socSet = devicePrefs.getInt(PREF_BATTERY_MAXIMUM_CHARGE, 100); + if (socSet < 70) socSet = 70; + if (socSet > 100) socSet = 100; + sendWriteProperty("socSet", socSet * 10); + } + default -> LOG.warn("Unknown config changed: {}", config); } } @@ -199,13 +208,21 @@ public class SolarFlowDeviceSupport extends AbstractBTLESingleDeviceSupport { int electricLevel = properties.getInt("electricLevel"); if (electricLevel != this.electricLevel) { this.electricLevel = electricLevel; - getDevice().setBatteryLevel(electricLevel); - getDevice().sendDeviceUpdateIntent(getContext()); + getDevice().setBatteryLevel(electricLevel); // update event will be sent when firmware gets read } } if (properties.has("outputHomePower")) { outputHomePower = properties.getInt("outputHomePower"); } + if (properties.has("MASTER")) { + int firmwareVersion = properties.getInt("MASTER"); + if (firmwareVersion != this.firmwareVersion) { + this.firmwareVersion = firmwareVersion; + String firmwareString = ((firmwareVersion & 0xf000) >> 12) + "." + ((firmwareVersion & 0x0f00) >> 8) + "." + (firmwareVersion & 0x00ff); + getDevice().setFirmwareVersion(firmwareString); + getDevice().sendDeviceUpdateIntent(getContext()); + } + } } catch (JSONException e) { LOG.error("JSON error while parsing report: {}", e.getMessage()); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8d6cd4a720..6b300d7c7a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -4137,6 +4137,7 @@ Manual discharge intervals Send configuration below to device Minimum battery charge in % + Maximum battery charge in % When enabled, the battery can be charged while discharging Allow battery pass-through There should be at least one canned reply. diff --git a/app/src/main/res/xml/devicesettings_battery_maximum_charge.xml b/app/src/main/res/xml/devicesettings_battery_maximum_charge.xml new file mode 100644 index 0000000000..1ccf79a83e --- /dev/null +++ b/app/src/main/res/xml/devicesettings_battery_maximum_charge.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file