mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2025-01-10 17:11:56 +01:00
Add weather support for Huawei
This commit is contained in:
parent
3af5a412fe
commit
b2b176b65c
@ -144,7 +144,7 @@ public abstract class HuaweiBRCoordinator extends AbstractBLClassicDeviceCoordin
|
||||
|
||||
@Override
|
||||
public boolean supportsWeather() {
|
||||
return false;
|
||||
return huaweiCoordinator.supportsWeather();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ public abstract class HuaweiLECoordinator extends AbstractBLEDeviceCoordinator i
|
||||
|
||||
@Override
|
||||
public boolean supportsWeather() {
|
||||
return false;
|
||||
return huaweiCoordinator.supportsWeather();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user