From 50f086b03a13c634a3eaf909148e764c081ea958 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Wed, 25 Oct 2023 23:25:37 +0200 Subject: [PATCH] Xiaomi: Implement daily forecast Works on Mi Watch Lite --- .../xiaomi/services/XiaomiWeatherService.java | 72 +++++++++++++++---- app/src/main/proto/xiaomi.proto | 41 +++++++++-- 2 files changed, 97 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/services/XiaomiWeatherService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/services/XiaomiWeatherService.java index b7976ebc1..05fba895c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/services/XiaomiWeatherService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/xiaomi/services/XiaomiWeatherService.java @@ -31,13 +31,12 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.xiaomi.XiaomiSupport import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public class XiaomiWeatherService extends AbstractXiaomiService { - private static final Logger LOG = LoggerFactory.getLogger(XiaomiWeatherService.class); - public static final int COMMAND_TYPE = 10; - + private static final Logger LOG = LoggerFactory.getLogger(XiaomiWeatherService.class); private static final int CMD_TEMPERATURE_UNIT_GET = 9; private static final int CMD_TEMPERATURE_UNIT_SET = 10; private static final int CMD_SET_CURRENT_WEATHER = 0; + private static final int CMD_SET_DAILY_WEATHER = 1; public XiaomiWeatherService(final XiaomiSupport support) { super(support); @@ -65,12 +64,7 @@ public class XiaomiWeatherService extends AbstractXiaomiService { } public void onSendWeather(final WeatherSpec weatherSpec) { - String timestamp = new StringBuilder( - new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US) - .format(new Date(weatherSpec.timestamp * 1000L))) - .insert(22, ':') // FIXME: I bet this fails for some, but all this java date craps sucks - .toString(); - + String timestamp = unixTimetstampToISOWithColons(weatherSpec.timestamp); getSupport().sendCommand( "set current weather", @@ -105,7 +99,7 @@ public class XiaomiWeatherService extends AbstractXiaomiService { ) .setAQI(XiaomiProto.WeatherCurrentAQI.newBuilder() .setAQIText("Unknown") // some string like "Moderate" - .setAQI(weatherSpec.airQuality != null && weatherSpec.airQuality.aqi >=0 ? weatherSpec.airQuality.aqi : 0) + .setAQI(weatherSpec.airQuality != null && weatherSpec.airQuality.aqi >= 0 ? weatherSpec.airQuality.aqi : 0) ) .setWarning(XiaomiProto.WeatherCurrentWarning.newBuilder() .setCurrentWarning1(XiaomiProto.WeatherCurrentWarning1.newBuilder() @@ -114,10 +108,55 @@ public class XiaomiWeatherService extends AbstractXiaomiService { ) ) .setPressure(weatherSpec.pressure) - )) .build() ); + + + if (weatherSpec.forecasts != null) { + XiaomiProto.WeatherDailyList.Builder dailyListBuilder = XiaomiProto.WeatherDailyList.newBuilder(); + int daysToSend = Math.min(7, weatherSpec.forecasts.size()); + for (int i = 0; i < daysToSend; i++) { + dailyListBuilder.addForecastDay(XiaomiProto.WeatherDailyForecastDay.newBuilder() + .setUnk1(XiaomiProto.DailyUnk1.newBuilder() + .setUnk1("") + .setUnk2(0) + ) + .setUnk2(XiaomiProto.DailyUnk2.newBuilder() + .setUnk1(HuamiWeatherConditions.mapToAmazfitBipWeatherCode(weatherSpec.forecasts.get(i).conditionCode)) // TODO: verify + .setUnk2(0) + ) + .setHighLowTemp(XiaomiProto.DailyHighLowTemp.newBuilder() + .setHigh(weatherSpec.forecasts.get(i).maxTemp - 273) + .setLow(weatherSpec.forecasts.get(i).minTemp - 273) + ) + .setTemperatureSymbol("℃") + .setSunriseSunset(XiaomiProto.DailySunriseSunset.newBuilder() + .setSunrise(weatherSpec.forecasts.get(i).sunRise != 0 ? unixTimetstampToISOWithColons(weatherSpec.forecasts.get(i).sunRise) : "") + .setSunset(weatherSpec.forecasts.get(i).sunSet != 0 ? unixTimetstampToISOWithColons(weatherSpec.forecasts.get(i).sunSet) : "") + ) + ); + } + + getSupport().sendCommand( + "set daily forecast", + XiaomiProto.Command.newBuilder() + .setType(COMMAND_TYPE) + .setSubtype(CMD_SET_DAILY_WEATHER) + .setWeather(XiaomiProto.Weather.newBuilder().setDaily( + XiaomiProto.WeatherDaily.newBuilder() + .setTimeLocation(XiaomiProto.WeatherCurrentTimeLocation.newBuilder() + .setTimestamp(timestamp) + .setUnk2("") + .setCurrentLocationString(weatherSpec.location) + .setCurrentLocationCode("accu:123456") // FIXME:AccuWeather code (we do not have it here) + .setUnk5(true) + ) + .setDailyList(dailyListBuilder) + )) + .build() + ); + } } private void setMeasurementSystem() { @@ -138,4 +177,13 @@ public class XiaomiWeatherService extends AbstractXiaomiService { .build() ); } -} + + private String unixTimetstampToISOWithColons(int timestamp) { + return new StringBuilder( + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US) + .format(new Date(timestamp * 1000L))) + .insert(22, ':') // FIXME: I bet this fails for some, but all this java date craps sucks + .toString(); + + } +} \ No newline at end of file diff --git a/app/src/main/proto/xiaomi.proto b/app/src/main/proto/xiaomi.proto index 8649483ce..138a6911b 100644 --- a/app/src/main/proto/xiaomi.proto +++ b/app/src/main/proto/xiaomi.proto @@ -689,14 +689,47 @@ message WeatherCurrentWarning1 { optional string currentWarningSeverityText = 2; } - -message WeatherDaily { -} - message WeatherCurrentLocation { optional WeatherLocation location = 1; } +message WeatherDaily { + required WeatherCurrentTimeLocation timeLocation = 1; + required WeatherDailyList dailyList = 2; +} + +message WeatherDailyList { + repeated WeatherDailyForecastDay forecastDay = 1; +} + +message WeatherDailyForecastDay { + optional DailyUnk1 unk1 = 1; + optional DailyUnk2 unk2 = 2; + optional DailyHighLowTemp highLowTemp = 3; + optional string temperatureSymbol = 4; + optional DailySunriseSunset sunriseSunset = 5; +} + +message DailyUnk1 { + optional string unk1 = 1; + optional uint32 unk2 = 2; +} + +message DailyUnk2 { + optional uint32 unk1 = 1; + optional uint32 unk2 = 2; +} + +message DailyHighLowTemp { + optional sint32 low = 1; + optional sint32 high = 2; +} + +message DailySunriseSunset { + optional string sunrise = 1; + optional string sunset = 2; +} + message WeatherLocation { optional string code = 1; optional string name = 2;