Add weather support for Huawei

This commit is contained in:
Martin.JM 2024-01-18 19:38:59 +01:00 committed by José Rebelo
parent 3af5a412fe
commit b2b176b65c
16 changed files with 830 additions and 2 deletions

View File

@ -144,7 +144,7 @@ public abstract class HuaweiBRCoordinator extends AbstractBLClassicDeviceCoordin
@Override
public boolean supportsWeather() {
return false;
return huaweiCoordinator.supportsWeather();
}
@Override

View File

@ -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);
}

View File

@ -144,7 +144,7 @@ public abstract class HuaweiLECoordinator extends AbstractBLEDeviceCoordinator i
@Override
public boolean supportsWeather() {
return false;
return huaweiCoordinator.supportsWeather();
}
@Override

View File

@ -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:

View File

@ -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 <https://www.gnu.org/licenses/>. */
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;
}
}
}
}

View File

@ -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?
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}
}

View File

@ -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 <https://www.gnu.org/licenses/>. */
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<byte[]> 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);
}
}
}

View File

@ -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 <https://www.gnu.org/licenses/>. */
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<byte[]> 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);
}
}
}

View File

@ -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 <https://www.gnu.org/licenses/>. */
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<byte[]> 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");
}
}
}

View File

@ -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 <https://www.gnu.org/licenses/>. */
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<byte[]> 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");
}
}
}

View File

@ -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 <https://www.gnu.org/licenses/>. */
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<byte[]> 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");
}
}
}

View File

@ -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 <https://www.gnu.org/licenses/>. */
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<byte[]> 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");
}
}
}

View File

@ -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 <https://www.gnu.org/licenses/>. */
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<byte[]> createRequest() throws RequestCreationException {
try {
return new Weather.WeatherUnitRequest(this.paramsProvider).serialize();
} catch (HuaweiPacket.CryptoException e) {
throw new RequestCreationException(e);
}
}
}