diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiBRCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiBRCoordinator.java
index 677a88a89..ef27fc992 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiBRCoordinator.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiBRCoordinator.java
@@ -144,7 +144,7 @@ public abstract class HuaweiBRCoordinator extends AbstractBLClassicDeviceCoordin
@Override
public boolean supportsWeather() {
- return false;
+ return huaweiCoordinator.supportsWeather();
}
@Override
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiCoordinator.java
index fe6c36c05..6e0d34856 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiCoordinator.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiCoordinator.java
@@ -336,6 +336,30 @@ public class HuaweiCoordinator {
return supportsCommandForService(0x0c, 0x01);
}
+ public boolean supportsWeather() {
+ return supportsCommandForService(0x0f, 0x01);
+ }
+
+ public boolean supportsWeatherUnit() {
+ return supportsCommandForService(0x0f, 0x05);
+ }
+
+ public boolean supportsWeatherExtended() {
+ return supportsCommandForService(0x0f, 0x05);
+ }
+
+ public boolean supportsWeatherForecasts() {
+ return supportsCommandForService(0x0f, 0x08);
+ }
+
+ public boolean supportsWeatherMoonRiseSet() {
+ return supportsCommandForService(0x0f, 0x0a);
+ }
+
+ public boolean supportsWeatherTides() {
+ return supportsCommandForService(0x0f, 0x0b);
+ }
+
public boolean supportsWorkouts() {
return supportsCommandForService(0x17, 0x01);
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiLECoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiLECoordinator.java
index 782159327..1ea56d7fc 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiLECoordinator.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiLECoordinator.java
@@ -144,7 +144,7 @@ public abstract class HuaweiLECoordinator extends AbstractBLEDeviceCoordinator i
@Override
public boolean supportsWeather() {
- return false;
+ return huaweiCoordinator.supportsWeather();
}
@Override
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiPacket.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiPacket.java
index 624a2b739..7527380f8 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiPacket.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiPacket.java
@@ -32,6 +32,7 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Alarms;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.AccountRelated;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Calls;
+import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Weather;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Workout;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.DeviceConfig;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FindPhone;
@@ -475,6 +476,20 @@ public class HuaweiPacket {
return new FindPhone.Response(paramsProvider).fromPacket(this);
this.isEncrypted = this.attemptDecrypt(); // Helps with debugging
return this;
+ case Weather.id:
+ switch (this.commandId) {
+ case Weather.WeatherSupport.id:
+ return new Weather.WeatherSupport.Response(paramsProvider).fromPacket(this);
+ case Weather.WeatherExtendedSupport.id:
+ return new Weather.WeatherExtendedSupport.Response(paramsProvider).fromPacket(this);
+ case Weather.WeatherStart.id:
+ return new Weather.WeatherStart.Response(paramsProvider).fromPacket(this);
+ case Weather.WeatherSunMoonSupport.id:
+ return new Weather.WeatherSunMoonSupport.Response(paramsProvider).fromPacket(this);
+ default:
+ this.isEncrypted = this.attemptDecrypt(); // Helps with debugging
+ return this;
+ }
case Workout.id:
switch (this.commandId) {
case Workout.WorkoutCount.id:
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/Weather.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/Weather.java
new file mode 100644
index 000000000..53866dfe8
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/Weather.java
@@ -0,0 +1,275 @@
+/* Copyright (C) 2024 Martin.JM
+
+ This file is part of Gadgetbridge.
+
+ Gadgetbridge is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Gadgetbridge is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see . */
+package nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets;
+
+import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
+import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiTLV;
+
+public class Weather {
+ public static final byte id = 0x0f;
+
+ public static class Settings {
+ // WeatherSupport
+ public boolean weatherSupported = false;
+ public boolean windSupported = false;
+ public boolean pm25Supported = false;
+ public boolean temperatureSupported = false;
+ public boolean locationNameSupported = false;
+ public boolean currentTemperatureSupported = false;
+ public boolean unitSupported = false;
+ public boolean airQualityIndexSupported = false;
+
+ // WeatherExtendedSupport
+ public boolean timeSupported = false;
+ public boolean sourceSupported = false;
+ public boolean weatherIconSupported = false;
+
+ // WeatherSunMoonSupport
+ public boolean sunRiseSetSupported = false;
+ public boolean moonPhaseSupported = false;
+ }
+
+ public static class CurrentWeatherRequest extends HuaweiPacket {
+ public static final byte id = 0x01;
+
+ public CurrentWeatherRequest(
+ ParamsProvider paramsProvider,
+ Settings settings,
+ Byte windDirection,
+ Byte windSpeed,
+ Byte lowestTemperature,
+ Byte highestTemperature,
+ Short pm25, // TODO: might be float?
+ String locationName,
+ Byte currentTemperature,
+ Byte temperatureUnit,
+ Short airQualityIndex,
+ Integer observationTime,
+ String sourceName
+ ) {
+ super(paramsProvider);
+
+ this.serviceId = Weather.id;
+ this.commandId = id;
+ this.tlv = new HuaweiTLV();
+
+ if (lowestTemperature != null && highestTemperature != null && settings.temperatureSupported) {
+ this.tlv.put(0x85, new HuaweiTLV()
+ .put(0x06, lowestTemperature)
+ .put(0x07, highestTemperature)
+ );
+ }
+ if (windDirection != null && windSpeed != null && settings.windSupported)
+ this.tlv.put(0x03, (short) ((((short) windDirection) << 8) | ((short) windSpeed)));
+ if (pm25 != null && settings.pm25Supported)
+ this.tlv.put(0x04, pm25);
+ if (locationName != null && settings.locationNameSupported)
+ this.tlv.put(0x08, locationName);
+ if (currentTemperature != null && settings.currentTemperatureSupported)
+ this.tlv.put(0x09, currentTemperature);
+ if (temperatureUnit != null && settings.unitSupported)
+ this.tlv.put(0x0a, temperatureUnit);
+ if (airQualityIndex != null && settings.airQualityIndexSupported)
+ this.tlv.put(0x0b, airQualityIndex);
+ if (observationTime != null && settings.timeSupported)
+ this.tlv.put(0x0c, observationTime);
+ if (sourceName != null && settings.sourceSupported)
+ this.tlv.put(0x0e, sourceName);
+ this.tlv.put(0x0f, (byte) 0);
+
+ this.isEncrypted = true;
+ this.complete = true;
+ }
+ }
+
+ public static class WeatherSupport {
+ public static final byte id = 0x02;
+
+ public static class Request extends HuaweiPacket {
+ public Request(ParamsProvider paramsProvider) {
+ super(paramsProvider);
+
+ this.serviceId = Weather.id;
+ this.commandId = id;
+ this.tlv = new HuaweiTLV().put(0x01);
+ this.isEncrypted = true;
+ this.complete = true;
+ }
+ }
+
+ public static class Response extends HuaweiPacket {
+ public byte supportedBitmap = 0;
+
+ public boolean weatherSupported = false;
+ public boolean windSupported = false;
+ public boolean pm25Supported = false;
+ public boolean temperatureSupported = false;
+ public boolean locationNameSupported = false;
+ public boolean currentTemperatureSupported = false;
+ public boolean unitSupported = false;
+ public boolean airQualityIndexSupported = false;
+
+ public Response(ParamsProvider paramsProvider) {
+ super(paramsProvider);
+ this.serviceId = Weather.id;
+ this.commandId = id;
+ }
+
+ @Override
+ public void parseTlv() throws ParseException {
+ if (!this.tlv.contains(0x01))
+ throw new MissingTagException(0x01);
+ this.supportedBitmap = this.tlv.getByte(0x01);
+
+ this.weatherSupported = (this.supportedBitmap & 0x01) != 0;
+ this.windSupported = (this.supportedBitmap & 0x02) != 0;
+ this.pm25Supported = (this.supportedBitmap & 0x04) != 0;
+ this.temperatureSupported = (this.supportedBitmap & 0x08) != 0;
+ this.locationNameSupported = (this.supportedBitmap & 0x10) != 0;
+ this.currentTemperatureSupported = (this.supportedBitmap & 0x20) != 0;
+ this.unitSupported = (this.supportedBitmap & 0x40) != 0;
+ this.airQualityIndexSupported = (this.supportedBitmap & 0x80) != 0;
+ }
+ }
+ }
+
+ public static class WeatherUnitRequest extends HuaweiPacket {
+ public static final byte id = 0x05;
+
+ public WeatherUnitRequest(ParamsProvider paramsProvider) {
+ super(paramsProvider);
+
+ this.serviceId = Weather.id;
+ this.commandId = id;
+ this.tlv = new HuaweiTLV().put(0x01, (byte) 0); // TODO: find out what unit is what
+ this.isEncrypted = true;
+ this.complete = true;
+ }
+ }
+
+ public static class WeatherExtendedSupport {
+ public static final byte id = 0x06;
+
+ public static class Request extends HuaweiPacket {
+ public Request(ParamsProvider paramsProvider) {
+ super(paramsProvider);
+
+ this.serviceId = Weather.id;
+ this.commandId = id;
+ this.tlv = new HuaweiTLV().put(0x01);
+ this.isEncrypted = true;
+ this.complete = true;
+ }
+ }
+
+ public static class Response extends HuaweiPacket {
+ public short supportedBitmap = 0;
+
+ public boolean timeSupported = false;
+ public boolean sourceSupported = false;
+ public boolean weatherIconSupported = false;
+
+ public Response(ParamsProvider paramsProvider) {
+ super(paramsProvider);
+ this.serviceId = Weather.id;
+ this.commandId = id;
+ }
+
+ @Override
+ public void parseTlv() throws ParseException {
+ if (!this.tlv.contains(0x01))
+ throw new MissingTagException(0x01);
+ this.supportedBitmap = this.tlv.getShort(0x01);
+
+ this.timeSupported = (this.supportedBitmap & 0x01) != 0;
+ this.sourceSupported = (this.supportedBitmap & 0x02) != 0;
+ this.weatherIconSupported = (this.supportedBitmap & 0x04) != 0;
+ }
+ }
+ }
+
+ public static class WeatherStart {
+ public static final byte id = 0x09;
+
+ public static class Request extends HuaweiPacket {
+
+ public Request(ParamsProvider paramsProvider) {
+ super(paramsProvider);
+
+ this.serviceId = Weather.id;
+ this.commandId = id;
+ this.tlv = new HuaweiTLV().put(0x01, (byte) 0x03); // TODO: find out what this means
+ this.isEncrypted = true;
+ this.complete = true;
+ }
+ }
+
+ public static class Response extends HuaweiPacket {
+ public boolean success = false;
+
+ public Response(ParamsProvider paramsProvider) {
+ super(paramsProvider);
+ this.serviceId = Weather.id;
+ this.commandId = id;
+ }
+
+ @Override
+ public void parseTlv() throws ParseException {
+ this.success = this.tlv.getInteger(0x7f) == 0x000186A0;
+ }
+ }
+ }
+
+ public static class WeatherSunMoonSupport {
+ public static final byte id = 0x0a;
+
+ public static class Request extends HuaweiPacket {
+ public Request(ParamsProvider paramsProvider) {
+ super(paramsProvider);
+
+ this.serviceId = Weather.id;
+ this.commandId = id;
+ this.tlv = new HuaweiTLV().put(0x01);
+ this.isEncrypted = true;
+ this.complete = true;
+ }
+ }
+
+ public static class Response extends HuaweiPacket {
+ public byte supportedBitmap = 0;
+
+ public boolean sunRiseSetSupported = false;
+ public boolean moonPhaseSupported = false;
+
+ public Response(ParamsProvider paramsProvider) {
+ super(paramsProvider);
+ this.serviceId = Weather.id;
+ this.commandId = id;
+ }
+
+ @Override
+ public void parseTlv() throws ParseException {
+ if (!this.tlv.contains(0x01))
+ throw new MissingTagException(0x01);
+ this.supportedBitmap = this.tlv.getByte(0x01);
+
+ this.sunRiseSetSupported = (this.supportedBitmap & 0x01) != 0;
+ this.moonPhaseSupported = (this.supportedBitmap & 0x02) != 0;
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/AsynchronousResponse.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/AsynchronousResponse.java
index 64d15b647..85590477a 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/AsynchronousResponse.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/AsynchronousResponse.java
@@ -47,9 +47,11 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.DeviceConfig;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FindPhone;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Menstrual;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.MusicControl;
+import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Weather;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.Request;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetPhoneInfoRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendMenstrualModifyTimeRequest;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendWeatherDeviceRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SetMusicStatusRequest;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
@@ -95,6 +97,7 @@ public class AsynchronousResponse {
handleCallControls(response);
handlePhoneInfo(response);
handleMenstrualModifyTime(response);
+ handleWeatherCheck(response);
} catch (Request.ResponseParseException e) {
LOG.error("Response parse exception", e);
}
@@ -378,4 +381,18 @@ public class AsynchronousResponse {
}
}
+
+ private void handleWeatherCheck(HuaweiPacket response) {
+ if (response.serviceId == Weather.id && response.commandId == 0x04) {
+ // Send back ok
+ try {
+ SendWeatherDeviceRequest sendWeatherDeviceRequest = new SendWeatherDeviceRequest(this.support);
+ sendWeatherDeviceRequest.doPerform();
+ } catch (IOException e) {
+ e.printStackTrace(); // TODO: Change
+ }
+
+ // TODO: send back weather?
+ }
+ }
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiBRSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiBRSupport.java
index 2a40a9f00..2fed2850e 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiBRSupport.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiBRSupport.java
@@ -25,6 +25,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
+import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
import nodomain.freeyourgadget.gadgetbridge.service.btbr.AbstractBTBRDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.btbr.TransactionBuilder;
@@ -117,4 +118,9 @@ public class HuaweiBRSupport extends AbstractBTBRDeviceSupport {
if (!start)
supportProvider.onStopFindPhone();
}
+
+ @Override
+ public void onSendWeather(WeatherSpec weatherSpec) {
+ supportProvider.onSendWeather(weatherSpec);
+ }
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiLESupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiLESupport.java
index f2b920b8f..4c81445a0 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiLESupport.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiLESupport.java
@@ -29,6 +29,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
+import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattService;
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
@@ -125,4 +126,9 @@ public class HuaweiLESupport extends AbstractBTLEDeviceSupport {
if (!start)
supportProvider.onStopFindPhone();
}
+
+ @Override
+ public void onSendWeather(WeatherSpec weatherSpec) {
+ supportProvider.onSendWeather(weatherSpec);
+ }
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java
index 5f8cb6a27..2323245d8 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java
@@ -50,6 +50,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiCoordinatorSupp
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiCrypto;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiSampleProvider;
+import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Weather;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Workout;
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst;
import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary;
@@ -73,11 +74,18 @@ import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
import nodomain.freeyourgadget.gadgetbridge.model.RecordedDataTypes;
+import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetEventAlarmList;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetNotificationConstraintsRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetSmartAlarmList;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendWeatherCurrentRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendNotifyHeartRateCapabilityRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendNotifyRestHeartRateCapabilityRequest;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendWeatherExtendedSupportRequest;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendWeatherStartRequest;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendWeatherSunMoonSupportRequest;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendWeatherSupportRequest;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendWeatherUnitRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SetAutomaticHeartrateRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SetAutomaticSpoRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SetDisconnectNotification;
@@ -156,6 +164,8 @@ public class HuaweiSupportProvider {
private MusicStateSpec musicStateSpec = null;
private MusicSpec musicSpec = null;
+ private Weather.Settings weatherSettings = null;
+
private final HuaweiPacket.ParamsProvider paramsProvider = new HuaweiPacket.ParamsProvider();
protected ResponseManager responseManager = new ResponseManager(this);
@@ -1637,4 +1647,75 @@ public class HuaweiSupportProvider {
LOG.error("Failed to set language settings request", e);
}
}
+
+ public void onSendWeather(WeatherSpec weatherSpec) {
+ if (weatherSettings != null && weatherSettings.weatherSupported) {
+ try {
+ SendWeatherCurrentRequest sendWeatherCurrentRequest = new SendWeatherCurrentRequest(
+ this,
+ weatherSettings,
+ weatherSpec
+ );
+ sendWeatherCurrentRequest.doPerform();
+ } catch (IOException e) {
+ // TODO: Use translatable string
+ GB.toast(context, "Failed to send weather", Toast.LENGTH_SHORT, GB.ERROR, e);
+ LOG.error("Failed to send weather", e);
+ }
+ } else {
+ // Initialize weather settings
+ if (!getHuaweiCoordinator().supportsWeather()) {
+ // TODO: exception?
+ return;
+ }
+
+ this.weatherSettings = new Weather.Settings();
+
+ RequestCallback requestCallback = new RequestCallback(this) {
+ @Override
+ public void call() {
+ this.support.weatherSettings.weatherSupported = true;
+ this.support.onSendWeather(weatherSpec);
+ }
+ };
+
+ SendWeatherStartRequest weatherStartRequest = new SendWeatherStartRequest(this);
+ weatherStartRequest.setFinalizeReq(requestCallback);
+ Request lastRequest = weatherStartRequest;
+
+ if (getHuaweiCoordinator().supportsWeatherUnit()) {
+ SendWeatherUnitRequest weatherUnitRequest = new SendWeatherUnitRequest(this);
+ weatherUnitRequest.setFinalizeReq(requestCallback);
+ lastRequest.nextRequest(weatherUnitRequest);
+ lastRequest = weatherUnitRequest;
+ }
+
+ SendWeatherSupportRequest weatherSupportRequest = new SendWeatherSupportRequest(this, weatherSettings);
+ weatherSupportRequest.setFinalizeReq(requestCallback);
+ lastRequest.nextRequest(weatherSupportRequest);
+ lastRequest = weatherSupportRequest;
+
+ if (getHuaweiCoordinator().supportsWeatherExtended()) {
+ SendWeatherExtendedSupportRequest weatherExtendedSupportRequest = new SendWeatherExtendedSupportRequest(this, weatherSettings);
+ weatherExtendedSupportRequest.setFinalizeReq(requestCallback);
+ lastRequest.nextRequest(weatherExtendedSupportRequest);
+ lastRequest = weatherExtendedSupportRequest;
+ }
+
+ if (getHuaweiCoordinator().supportsWeatherMoonRiseSet()) {
+ SendWeatherSunMoonSupportRequest weatherSunMoonSupportRequest = new SendWeatherSunMoonSupportRequest(this, weatherSettings);
+ weatherSunMoonSupportRequest.setFinalizeReq(requestCallback);
+ lastRequest.nextRequest(weatherSunMoonSupportRequest);
+// lastRequest = weatherSunMoonSupportRequest;
+ }
+
+ try {
+ weatherStartRequest.doPerform();
+ } catch (IOException e) {
+ // TODO: Use translatable string
+ GB.toast(context, "Failed to send initialize weather requests", Toast.LENGTH_SHORT, GB.ERROR, e);
+ LOG.error("Failed to send initialize weather requests", e);
+ }
+ }
+ }
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendWeatherCurrentRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendWeatherCurrentRequest.java
new file mode 100644
index 000000000..cd41c2b7b
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendWeatherCurrentRequest.java
@@ -0,0 +1,67 @@
+/* Copyright (C) 2024 Martin.JM
+
+ This file is part of Gadgetbridge.
+
+ Gadgetbridge is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Gadgetbridge is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see . */
+package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests;
+
+import java.util.List;
+
+import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
+import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Weather;
+import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
+
+public class SendWeatherCurrentRequest extends Request {
+ Weather.Settings settings;
+ WeatherSpec weatherSpec;
+
+ public SendWeatherCurrentRequest(HuaweiSupportProvider support, Weather.Settings settings, WeatherSpec weatherSpec) {
+ super(support);
+ this.serviceId = Weather.id;
+ this.commandId = Weather.CurrentWeatherRequest.id;
+ this.settings = settings;
+ this.weatherSpec = weatherSpec;
+ }
+
+ @Override
+ protected List createRequest() throws RequestCreationException {
+ try {
+ // TODO: support multiple units
+ Short pm25 = null;
+ Short aqi = null;
+ if (weatherSpec.airQuality != null) {
+ pm25 = (short) weatherSpec.airQuality.pm25; // TODO: does this work?
+ aqi = (short) weatherSpec.airQuality.aqi;
+ }
+ return new Weather.CurrentWeatherRequest(
+ this.paramsProvider,
+ settings,
+ (byte) weatherSpec.windDirection,
+ (byte) weatherSpec.windSpeed,
+ (byte) (weatherSpec.todayMinTemp - 273),
+ (byte) (weatherSpec.todayMaxTemp - 273),
+ pm25,
+ weatherSpec.location,
+ (byte) (weatherSpec.currentTemp - 273),
+ (byte) 0,
+ aqi,
+ weatherSpec.timestamp,
+ "Gadgetbridge"
+ ).serialize();
+ } catch (HuaweiPacket.CryptoException e) {
+ throw new RequestCreationException(e);
+ }
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendWeatherDeviceRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendWeatherDeviceRequest.java
new file mode 100644
index 000000000..64a3c2ce0
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendWeatherDeviceRequest.java
@@ -0,0 +1,50 @@
+/* Copyright (C) 2024 Martin.JM
+
+ This file is part of Gadgetbridge.
+
+ Gadgetbridge is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Gadgetbridge is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see . */
+package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests;
+
+import java.util.List;
+
+import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
+import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiTLV;
+import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Weather;
+import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
+
+public class SendWeatherDeviceRequest extends Request {
+ WeatherSpec weatherSpec;
+
+ public SendWeatherDeviceRequest(HuaweiSupportProvider support) {
+ super(support);
+ this.serviceId = Weather.id;
+ this.commandId = 0x04;
+ }
+
+ @Override
+ protected List createRequest() throws RequestCreationException {
+ try {
+ // TODO: move this to the weather packet class
+ HuaweiPacket response = new HuaweiPacket(supportProvider.getParamsProvider());
+ response.serviceId = this.serviceId;
+ response.commandId = this.commandId;
+ response.setTlv(new HuaweiTLV().put(0x01, 0x186a0));
+ response.setEncryption(false);
+ return response.serialize();
+ } catch (HuaweiPacket.CryptoException e) {
+ throw new RequestCreationException(e);
+ }
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendWeatherExtendedSupportRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendWeatherExtendedSupportRequest.java
new file mode 100644
index 000000000..cd750904e
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendWeatherExtendedSupportRequest.java
@@ -0,0 +1,59 @@
+/* Copyright (C) 2024 Martin.JM
+
+ This file is part of Gadgetbridge.
+
+ Gadgetbridge is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Gadgetbridge is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see . */
+package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
+import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Weather;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
+
+public class SendWeatherExtendedSupportRequest extends Request {
+ private static final Logger LOG = LoggerFactory.getLogger(SendWeatherExtendedSupportRequest.class);
+
+ private Weather.Settings settings;
+
+ public SendWeatherExtendedSupportRequest(HuaweiSupportProvider support, Weather.Settings settings) {
+ super(support);
+ this.serviceId = Weather.id;
+ this.commandId = Weather.WeatherExtendedSupport.id;
+ this.settings = settings;
+ }
+
+ @Override
+ protected List createRequest() throws RequestCreationException {
+ try {
+ return new Weather.WeatherExtendedSupport.Request(this.paramsProvider).serialize();
+ } catch (HuaweiPacket.CryptoException e) {
+ throw new RequestCreationException(e);
+ }
+ }
+
+ @Override
+ protected void processResponse() throws ResponseParseException {
+ if (receivedPacket instanceof Weather.WeatherExtendedSupport.Response) {
+ this.settings.timeSupported = ((Weather.WeatherExtendedSupport.Response) receivedPacket).timeSupported;
+ this.settings.sourceSupported = ((Weather.WeatherExtendedSupport.Response) receivedPacket).sourceSupported;
+ this.settings.weatherIconSupported = ((Weather.WeatherExtendedSupport.Response) receivedPacket).weatherIconSupported;
+ } else {
+ LOG.error("WeatherExtendedSupport response is not of type WeatherExtendedSupport response");
+ }
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendWeatherStartRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendWeatherStartRequest.java
new file mode 100644
index 000000000..cc40c854f
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendWeatherStartRequest.java
@@ -0,0 +1,65 @@
+/* Copyright (C) 2024 Martin.JM
+
+ This file is part of Gadgetbridge.
+
+ Gadgetbridge is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Gadgetbridge is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see . */
+package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests;
+
+import android.widget.Toast;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
+import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Weather;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
+import nodomain.freeyourgadget.gadgetbridge.util.GB;
+
+public class SendWeatherStartRequest extends Request {
+ private static final Logger LOG = LoggerFactory.getLogger(SendWeatherStartRequest.class);
+
+ public int response = -1;
+
+ public SendWeatherStartRequest(HuaweiSupportProvider support) {
+ super(support);
+ this.serviceId = Weather.id;
+ this.commandId = Weather.WeatherStart.id;
+ }
+
+ @Override
+ protected List createRequest() throws RequestCreationException {
+ try {
+ return new Weather.WeatherStart.Request(this.paramsProvider).serialize();
+ } catch (HuaweiPacket.CryptoException e) {
+ throw new RequestCreationException(e);
+ }
+ }
+
+ @Override
+ protected void processResponse() throws ResponseParseException {
+ if (receivedPacket instanceof Weather.WeatherStart.Response) {
+ if (!((Weather.WeatherStart.Response) receivedPacket).success) {
+ this.stopChain();
+ GB.toast(supportProvider.getContext(), "Received non-ok status for WeatherStart response", Toast.LENGTH_SHORT, GB.INFO);
+ LOG.info("Received non-ok status for WeatherStart response");
+ }
+ } else {
+ this.stopChain();
+ GB.toast(supportProvider.getContext(), "WeatherStart response is not of type WeatherStart response", Toast.LENGTH_SHORT, GB.ERROR);
+ LOG.error("WeatherStart response is not of type WeatherStart response");
+ }
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendWeatherSunMoonSupportRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendWeatherSunMoonSupportRequest.java
new file mode 100644
index 000000000..ee6884222
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendWeatherSunMoonSupportRequest.java
@@ -0,0 +1,58 @@
+/* Copyright (C) 2024 Martin.JM
+
+ This file is part of Gadgetbridge.
+
+ Gadgetbridge is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Gadgetbridge is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see . */
+package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
+import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Weather;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
+
+public class SendWeatherSunMoonSupportRequest extends Request {
+ private static final Logger LOG = LoggerFactory.getLogger(SendWeatherSunMoonSupportRequest.class);
+
+ private Weather.Settings settings;
+
+ public SendWeatherSunMoonSupportRequest(HuaweiSupportProvider support, Weather.Settings settings) {
+ super(support);
+ this.serviceId = Weather.id;
+ this.commandId = Weather.WeatherSunMoonSupport.id;
+ this.settings = settings;
+ }
+
+ @Override
+ protected List createRequest() throws RequestCreationException {
+ try {
+ return new Weather.WeatherSunMoonSupport.Request(this.paramsProvider).serialize();
+ } catch (HuaweiPacket.CryptoException e) {
+ throw new RequestCreationException(e);
+ }
+ }
+
+ @Override
+ protected void processResponse() throws ResponseParseException {
+ if (receivedPacket instanceof Weather.WeatherSunMoonSupport.Response) {
+ this.settings.sunRiseSetSupported = ((Weather.WeatherSunMoonSupport.Response) receivedPacket).sunRiseSetSupported;
+ this.settings.moonPhaseSupported = ((Weather.WeatherSunMoonSupport.Response) receivedPacket).moonPhaseSupported;
+ } else {
+ LOG.error("WeatherExtendedSupport response is not of type WeatherExtendedSupport response");
+ }
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendWeatherSupportRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendWeatherSupportRequest.java
new file mode 100644
index 000000000..f06ca9219
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendWeatherSupportRequest.java
@@ -0,0 +1,64 @@
+/* Copyright (C) 2024 Martin.JM
+
+ This file is part of Gadgetbridge.
+
+ Gadgetbridge is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Gadgetbridge is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see . */
+package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
+import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Weather;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
+
+public class SendWeatherSupportRequest extends Request {
+ private static final Logger LOG = LoggerFactory.getLogger(SendWeatherSupportRequest.class);
+
+ private Weather.Settings settings;
+
+ public SendWeatherSupportRequest(HuaweiSupportProvider support, Weather.Settings settings) {
+ super(support);
+ this.serviceId = Weather.id;
+ this.commandId = Weather.WeatherSupport.id;
+ this.settings = settings;
+ }
+
+ @Override
+ protected List createRequest() throws RequestCreationException {
+ try {
+ return new Weather.WeatherSupport.Request(this.paramsProvider).serialize();
+ } catch (HuaweiPacket.CryptoException e) {
+ throw new RequestCreationException(e);
+ }
+ }
+
+ @Override
+ protected void processResponse() throws ResponseParseException {
+ if (receivedPacket instanceof Weather.WeatherSupport.Response) {
+ this.settings.weatherSupported = ((Weather.WeatherSupport.Response) receivedPacket).weatherSupported;
+ this.settings.windSupported = ((Weather.WeatherSupport.Response) receivedPacket).windSupported;
+ this.settings.pm25Supported = ((Weather.WeatherSupport.Response) receivedPacket).pm25Supported;
+ this.settings.temperatureSupported = ((Weather.WeatherSupport.Response) receivedPacket).temperatureSupported;
+ this.settings.locationNameSupported = ((Weather.WeatherSupport.Response) receivedPacket).locationNameSupported;
+ this.settings.currentTemperatureSupported = ((Weather.WeatherSupport.Response) receivedPacket).currentTemperatureSupported;
+ this.settings.unitSupported = ((Weather.WeatherSupport.Response) receivedPacket).unitSupported;
+ this.settings.airQualityIndexSupported = ((Weather.WeatherSupport.Response) receivedPacket).airQualityIndexSupported;
+ } else {
+ LOG.error("WeatherSupport response is not of type WeatherSupport response");
+ }
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendWeatherUnitRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendWeatherUnitRequest.java
new file mode 100644
index 000000000..647b88b4e
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendWeatherUnitRequest.java
@@ -0,0 +1,41 @@
+/* Copyright (C) 2024 Martin.JM
+
+ This file is part of Gadgetbridge.
+
+ Gadgetbridge is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Gadgetbridge is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see . */
+package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests;
+
+import java.util.List;
+
+import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
+import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Weather;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
+
+public class SendWeatherUnitRequest extends Request {
+
+ public SendWeatherUnitRequest(HuaweiSupportProvider support) {
+ super(support);
+ this.serviceId = Weather.id;
+ this.commandId = Weather.WeatherUnitRequest.id;
+ }
+
+ @Override
+ protected List createRequest() throws RequestCreationException {
+ try {
+ return new Weather.WeatherUnitRequest(this.paramsProvider).serialize();
+ } catch (HuaweiPacket.CryptoException e) {
+ throw new RequestCreationException(e);
+ }
+ }
+}