igsport: rebase device code to master ad34fec706

This commit is contained in:
Thomas Kuehne
2026-05-13 23:33:24 +02:00
committed by José Rebelo
parent 39cf720fdd
commit 014b180a30
9 changed files with 183 additions and 60 deletions
@@ -1,3 +1,19 @@
/* Copyright (C) 2025 Vitaliy Tomin, Thomas Kuehne
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.igpsport;
import android.app.Activity;
@@ -49,7 +65,7 @@ public abstract class IGPSportAbstractCoordinator extends AbstractBLEDeviceCoord
}
@Override
public boolean supportsActivityTracks() {
public boolean supportsActivityTracks(final GBDevice device) {
return true;
}
@@ -59,12 +75,12 @@ public abstract class IGPSportAbstractCoordinator extends AbstractBLEDeviceCoord
}
@Override
public boolean supportsAppListFetching() {
public boolean supportsAppListFetching(final GBDevice device) {
return true;
}
@Override
public Class<? extends Activity> getAppsManagementActivity() {
public Class<? extends Activity> getAppsManagementActivity(final GBDevice device) {
return AppManagerActivity.class;
}
@@ -1,8 +1,27 @@
/* Copyright (C) 2025 Vitaliy Tomin, Thomas Kuehne
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.igpsport;
import android.app.Activity;
import android.content.Context;
import android.net.Uri;
import androidx.annotation.NonNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -14,6 +33,7 @@ import java.util.Arrays;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.FwAppInstallerActivity;
import nodomain.freeyourgadget.gadgetbridge.activities.InstallActivity;
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
@@ -62,6 +82,12 @@ public class IGPSportRouteInstallHandler implements InstallHandler {
}
}
@NonNull
@Override
public Class<? extends Activity> getInstallActivity() {
return FwAppInstallerActivity.class;
}
@Override
public boolean isValid() {
if (routeExtensions.contains(extension))
@@ -1,3 +1,19 @@
/* Copyright (C) 2025 Vitaliy Tomin, Thomas Kuehne
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.igpsport;
import org.slf4j.Logger;
@@ -6,6 +22,7 @@ import org.slf4j.LoggerFactory;
import java.util.regex.Pattern;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
public class IGPSportiGS630Coordinator extends IGPSportAbstractCoordinator {
private static final Logger LOG = LoggerFactory.getLogger(IGPSportiGS630Coordinator.class);
@@ -21,7 +38,7 @@ public class IGPSportiGS630Coordinator extends IGPSportAbstractCoordinator {
}
@Override
public boolean supportsWeather() {
public boolean supportsWeather(final GBDevice device) {
return true;
}
}
@@ -316,6 +316,8 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huawei.huaweiwatchultimate.H
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.huaweiwatchultimate2.HuaweiWatchUltimate2Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.id115.ID115Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.idasen.IdasenCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.igpsport.IGPSportBSC200Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.igpsport.IGPSportiGS630Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.itag.ITagCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.jyou.BFH16DeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.jyou.TeclastH30.TeclastH30Coordinator;
@@ -941,6 +943,8 @@ public enum DeviceType {
SANITAS_SBM_67(SanitasSBM67Coordinator.class),
SILVERCREST_SBM_67(SilverCrestSBM67Coordinator.class),
BRAUN_BPW4500(BraunBPW4500DeviceCoordinator.class),
IGPSPORT_BSC200(IGPSportBSC200Coordinator.class),
IGPSPORT_IGS630(IGPSportiGS630Coordinator.class),
TEST(TestDeviceCoordinator.class);
private DeviceCoordinator coordinator;
@@ -1,3 +1,19 @@
/* Copyright (C) 2025 Vitaliy Tomin, Thomas Kuehne
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.igpsport;
@@ -8,8 +24,11 @@ import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.widget.Toast;
import androidx.annotation.NonNull;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
@@ -47,11 +66,9 @@ import nodomain.freeyourgadget.gadgetbridge.proto.igpsport.Firmware;
import nodomain.freeyourgadget.gadgetbridge.proto.igpsport.Ins;
import nodomain.freeyourgadget.gadgetbridge.proto.igpsport.PeripheralCommon;
import nodomain.freeyourgadget.gadgetbridge.proto.igpsport.RoutePlan;
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLESingleDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattService;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetProgressAction;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.IntentListener;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.battery.BatteryInfo;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.battery.BatteryInfoProfile;
@@ -63,7 +80,7 @@ import nodomain.freeyourgadget.gadgetbridge.proto.igpsport.Common;
import nodomain.freeyourgadget.gadgetbridge.proto.igpsport.Factory;
public class IGPSportDeviceSupport extends AbstractBTLEDeviceSupport {
public class IGPSportDeviceSupport extends AbstractBTLESingleDeviceSupport {
private static final Logger LOG = LoggerFactory.getLogger(IGPSportDeviceSupport.class);
public BluetoothGattCharacteristic readCharacteristic;
@@ -147,7 +164,7 @@ public class IGPSportDeviceSupport extends AbstractBTLEDeviceSupport {
@Override
protected TransactionBuilder initializeDevice(TransactionBuilder builder) {
// mark the device as initializing
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZING, getContext()));
builder.setDeviceState(GBDevice.State.INITIALIZING);
readCharacteristic = getCharacteristic(IGPSportConstants.UUID_IGPSPORT_CHARACTERISTIC_FIRST_RX);
writeCharacteristic = getCharacteristic(IGPSportConstants.UUID_IGPSPORT_CHARACTERISTIC_FIRST_TX);
writeCharacteristicThird = getCharacteristic(IGPSportConstants.UUID_IGPSPORT_CHARACTERISTIC_THIRD_TX);
@@ -201,7 +218,7 @@ public class IGPSportDeviceSupport extends AbstractBTLEDeviceSupport {
getDevice().setFirmwareVersion2("N/A");
// mark the device as initialized
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZED, getContext()));
builder.setDeviceState(GBDevice.State.INITIALIZED);
return builder;
}
@@ -323,25 +340,15 @@ public class IGPSportDeviceSupport extends AbstractBTLEDeviceSupport {
if (mainOperation == Common.SERVICE_OPERATE_TYPE.enum_SERVICE_OPERATE_TYPE_ADD_VALUE) {
gbDevice.unsetBusyTask();
gbDevice.sendDeviceUpdateIntent(getContext());
TransactionBuilder builder = new TransactionBuilder("Route upload finished");
TransactionBuilder builder = createTransactionBuilder("Route upload finished");
if (result == 0) {
builder.add(new SetProgressAction(
"Route upload completed",
false,
100,
getContext()
));
builder.setProgress(R.string.route_upload_completed, false, 100);
handleGBDeviceEvent(new GBDeviceEventDisplayMessage("Route upload completed", Toast.LENGTH_LONG, GB.INFO));
} else {
builder.add(new SetProgressAction(
"Route upload failed",
false,
0,
getContext()
));
builder.setProgress(R.string.route_upload_failed, false, 0);
handleGBDeviceEvent(new GBDeviceEventDisplayMessage("Failed to upload route", Toast.LENGTH_LONG, GB.ERROR));
}
builder.queue(getQueue());
builder.queue();
}
break;
@@ -476,7 +483,7 @@ public class IGPSportDeviceSupport extends AbstractBTLEDeviceSupport {
@Override
public void onNotification(NotificationSpec notificationSpec) {
LOG.debug("iGPSport notification: " + notificationSpec.type);
TransactionBuilder builder = new TransactionBuilder("notification");
TransactionBuilder builder = createTransactionBuilder("notification");
Ins.ins_msg.Builder insMsgBuilder = Ins.ins_msg.newBuilder();
insMsgBuilder.setServiceType(Common.service_type_index.enum_SERVICE_TYPE_INDEX_INS);
@@ -501,13 +508,13 @@ public class IGPSportDeviceSupport extends AbstractBTLEDeviceSupport {
insMsgBuilder.setInsDataMsg(insDataMsgBuilder);
byte[] callData = craftData(insMsgBuilder.getServiceType().getNumber(), insMsgBuilder.getInsServiceType().getNumber(), insMsgBuilder.getInsOperateType().getNumber(), insMsgBuilder.build().toByteArray());
builder.write(writeCharacteristic, callData);
builder.queue(getQueue());
builder.queue();
}
@Override
public void onSetCallState(CallSpec callSpec) {
LOG.debug("iGPSport send call notification");
TransactionBuilder builder = new TransactionBuilder("CALL");
TransactionBuilder builder = createTransactionBuilder("CALL");
Ins.ins_msg.Builder insMsgBuilder = Ins.ins_msg.newBuilder();
insMsgBuilder.setServiceType(Common.service_type_index.enum_SERVICE_TYPE_INDEX_INS);
insMsgBuilder.setInsServiceType(Ins.INS_SERVICE_TYPE.enum_INS_SERVICE_TYPE_CALL);
@@ -529,7 +536,7 @@ public class IGPSportDeviceSupport extends AbstractBTLEDeviceSupport {
insMsgBuilder.setInsDataMsg(insDataMsgBuilder);
byte[] callData = craftData(insMsgBuilder.getServiceType().getNumber(), insMsgBuilder.getInsServiceType().getNumber(), insMsgBuilder.getInsOperateType().getNumber(), insMsgBuilder.build().toByteArray());
builder.write(writeCharacteristic, callData);
builder.queue(getQueue());
builder.queue();
}
@Override
@@ -545,7 +552,7 @@ public class IGPSportDeviceSupport extends AbstractBTLEDeviceSupport {
byte[] cycleDataMsgBytes = craftData(cycleDataMsg.getServiceType().getNumber(), 0xff, cycleDataMsg.getCyclingDataOperateType().getNumber(), cycleDataMsg.build().toByteArray(), true);
builder.write(writeCharacteristicThird, cycleDataMsgBytes);
builder.queue(getQueue());
builder.queue();
}
@@ -566,7 +573,7 @@ public class IGPSportDeviceSupport extends AbstractBTLEDeviceSupport {
setMeasurementSystem(builder);
break;
}
builder.queue(getQueue());
builder.queue();
} catch (IOException e) {
GB.toast(getContext(), "Error sending configuration: " + e.getLocalizedMessage(), Toast.LENGTH_LONG, GB.ERROR);
}
@@ -627,7 +634,7 @@ public class IGPSportDeviceSupport extends AbstractBTLEDeviceSupport {
}
@Override
public void onInstallApp(Uri uri) {
public void onInstallApp(Uri uri, @NonNull final Bundle options) {
//final IGPSportGpxRouteInstallHandler gpxRouteHandler = new IGPSportGpxRouteInstallHandler(uri, getContext());
final IGPSportRouteInstallHandler routeHandler = new IGPSportRouteInstallHandler(uri, getContext());
if (routeHandler.isValid()) {
@@ -665,7 +672,7 @@ public class IGPSportDeviceSupport extends AbstractBTLEDeviceSupport {
private void handleWeather() {
// Send weather
final ArrayList<WeatherSpec> specs = new ArrayList<>(nodomain.freeyourgadget.gadgetbridge.model.Weather.getInstance().getWeatherSpecs());
final ArrayList<WeatherSpec> specs = new ArrayList<>(nodomain.freeyourgadget.gadgetbridge.model.weather.Weather.getWeatherSpecs());
if (!specs.isEmpty()) {
weatherManager.handleWeather(specs.get(0));
}
@@ -1,3 +1,19 @@
/* Copyright (C) 2025 Vitaliy Tomin, Thomas Kuehne
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.igpsport;
import com.google.protobuf.InvalidProtocolBufferException;
@@ -68,7 +84,7 @@ public class IGPSportDownloadManager {
byte[] cycleDataMsgBytes = IGPSportDeviceSupport.craftData(cycleDataMsg.getServiceType().getNumber(), 0xff, cycleDataMsg.getCyclingDataOperateType().getNumber(), cycleDataMsg.build().toByteArray(), true);
builder.write(support.writeCharacteristicThird, cycleDataMsgBytes);
builder.queue(support.getQueue());
builder.queue();
// } else {
// syncNextFile();
// }
@@ -1,3 +1,19 @@
/* Copyright (C) 2025 Vitaliy Tomin, Thomas Kuehne
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.igpsport;
import android.widget.Toast;
@@ -14,6 +30,7 @@ import java.util.List;
import java.util.Random;
import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppInfo;
import nodomain.freeyourgadget.gadgetbridge.devices.igpsport.IGPSportRouteInstallHandler;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp;
@@ -109,9 +126,8 @@ public class IGPSportRoutesManager {
fileOperationbuilder.build().toByteArray(),
handler.getBytes());
builder.writeChunkedData(support.writeCharacteristicFourth, fileOperationBytes, support.getMTU());
support.getDevice().setBusyTask("Installing route");
support.getDevice().sendDeviceUpdateIntent(support.getContext());
builder.queue(support.getQueue());
builder.setBusyTask(R.string.task_installing_route);
builder.queue();
} catch (final Exception e) {
GB.toast(support.getContext(), "Gpx install error: " + e.getMessage(), Toast.LENGTH_LONG, GB.ERROR, e);
@@ -129,7 +145,7 @@ public class IGPSportRoutesManager {
byte[] routePlanBytes = support.craftData(routePlanBuilder.getServiceType().getNumber(), 0xff, routePlanBuilder.getRoutePlanOperateType().getNumber(), routePlanBuilder.build().toByteArray());
builder.write(support.writeCharacteristicFourth, routePlanBytes);
builder.queue(support.getQueue());
builder.queue();
} catch (IOException e) {
GB.toast(support.getContext(), "Gpx get list error: " + e.getMessage(), Toast.LENGTH_LONG, GB.ERROR, e);
@@ -191,7 +207,7 @@ public class IGPSportRoutesManager {
private void requestFiles() {
int endFile = (fileNumber > fileListSupportNumMax ? fileListSupportNumMax - 1 : fileNumber)+startFile;
TransactionBuilder builder = new TransactionBuilder("get files list");
TransactionBuilder builder = support.createTransactionBuilder("get files list");
RoutePlan.route_plan_data_msg.Builder routePlan2ndBuilder = RoutePlan.route_plan_data_msg.newBuilder();
@@ -205,7 +221,7 @@ public class IGPSportRoutesManager {
fileNumber -= fileListSupportNumMax;
builder.write(support.writeCharacteristicFourth, routePlan2ndBytes);
builder.queue(support.getQueue());
builder.queue();
}
public void handleRouteNumber(byte[] pbData) throws InvalidProtocolBufferException {
@@ -235,7 +251,7 @@ public class IGPSportRoutesManager {
routePlanBuilder.addRoutePlanInfoMsg(installedRouteHash.get(uuid).toMessage());
byte[] routePlanBytes = support.craftData(routePlanBuilder.getServiceType().getNumber(), 0xff, routePlanBuilder.getRoutePlanOperateType().getNumber(), routePlanBuilder.build().toByteArray());
builder.write(support.writeCharacteristicFourth, routePlanBytes);
builder.queue(support.getQueue());
builder.queue();
} catch (IOException e) {
GB.toast(support.getContext(), "Failed to start gpx navigation: " + e.getMessage(), Toast.LENGTH_LONG, GB.ERROR, e);
}
@@ -250,7 +266,7 @@ public class IGPSportRoutesManager {
routePlanBuilder.addRoutePlanInfoMsg(installedRouteHash.get(uuid).toMessage());
byte[] routePlanBytes = support.craftData(routePlanBuilder.getServiceType().getNumber(), 0xff, routePlanBuilder.getRoutePlanOperateType().getNumber(), routePlanBuilder.build().toByteArray());
builder.write(support.writeCharacteristicFourth, routePlanBytes);
builder.queue(support.getQueue());
builder.queue();
} catch (IOException e) {
GB.toast(support.getContext(), "Failed to delete gpx navigation: " + e.getMessage(), Toast.LENGTH_LONG, GB.ERROR, e);
}
@@ -1,3 +1,19 @@
/* Copyright (C) 2025 Vitaliy Tomin, Thomas Kuehne
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.igpsport;
import java.io.IOException;
@@ -119,27 +135,27 @@ public class IGPSportWeather {
TransactionBuilder builder = support.performInitialized("set weather");
Back.back_msg.Builder weatherMsg = Back.back_msg.newBuilder();
Back.weather_current_data_message.Builder currentWeatherMsg =Back.weather_current_data_message.newBuilder();
currentWeatherMsg.setCurDayMinTemp(weatherSpec.todayMinTemp-273);
currentWeatherMsg.setCurDayMaxTemp(weatherSpec.todayMaxTemp-273);
currentWeatherMsg.setCurTemperature(weatherSpec.currentTemp-273);
currentWeatherMsg.setCurWeather(IGPSportWeather.convertOWMtoQWeather(weatherSpec.currentConditionCode));
currentWeatherMsg.setWindDeg(String.valueOf(weatherSpec.windDirection));
currentWeatherMsg.setWindSpd(String.valueOf(Math.round(weatherSpec.windSpeed)));
currentWeatherMsg.setCurDayMinTemp(weatherSpec.getTodayMinTemp()-273);
currentWeatherMsg.setCurDayMaxTemp(weatherSpec.getTodayMaxTemp()-273);
currentWeatherMsg.setCurTemperature(weatherSpec.getCurrentTemp()-273);
currentWeatherMsg.setCurWeather(IGPSportWeather.convertOWMtoQWeather(weatherSpec.getCurrentConditionCode()));
currentWeatherMsg.setWindDeg(String.valueOf(weatherSpec.getWindDirection()));
currentWeatherMsg.setWindSpd(String.valueOf(Math.round(weatherSpec.getWindSpeed())));
currentWeatherMsg.setTime(formatterHourly.format(currentTime));
int currentDay=0;
for (final WeatherSpec.Daily forecast : weatherSpec.forecasts) {
for (final WeatherSpec.Daily forecast : weatherSpec.getForecasts()) {
LocalDateTime now = LocalDateTime.now();
currentDay++;
LocalDateTime tomorrow = now.plusDays(currentDay);
DateTimeFormatter formatterDaily = DateTimeFormatter.ISO_LOCAL_DATE; //"yyyy-MM-dd"
weatherMsg.addThreeDaysMsg(Back.weather_three_days_data_message.newBuilder()
.setWeatherIndex(IGPSportWeather.convertOWMtoQWeather(forecast.conditionCode))
.setRainProb(forecast.precipProbability)
.setMaxTemp(forecast.maxTemp-273)
.setMinTemp(forecast.minTemp-273)
.setWeatherIndex(IGPSportWeather.convertOWMtoQWeather(forecast.getConditionCode()))
.setRainProb(forecast.getPrecipProbability())
.setMaxTemp(forecast.getMaxTemp()-273)
.setMinTemp(forecast.getMinTemp()-273)
.setDate(tomorrow.format(formatterDaily)).build());
if (currentDay > 2) //we only need 3 days
@@ -147,14 +163,14 @@ public class IGPSportWeather {
}
int currentHour=0;
for (final WeatherSpec.Hourly hourly : weatherSpec.hourly) {
for (final WeatherSpec.Hourly hourly : weatherSpec.getHourly()) {
weatherMsg.addThreeHoursMsg(Back.weather_three_hour_data_memsage.newBuilder()
.setWatherIndex(IGPSportWeather.convertOWMtoQWeather(hourly.conditionCode))
.setRainProb(hourly.precipProbability)
.setTemp(hourly.temp-273)
.setTime(formatterHourly.format(Instant.ofEpochMilli(hourly.timestamp * 1000L)))
.setWindDeg(String.valueOf(hourly.windDirection))
.setWindSpd(String.valueOf(Math.round(hourly.windSpeed))).build());
.setWatherIndex(IGPSportWeather.convertOWMtoQWeather(hourly.getConditionCode()))
.setRainProb(hourly.getPrecipProbability())
.setTemp(hourly.getTemp()-273)
.setTime(formatterHourly.format(Instant.ofEpochMilli(hourly.getTimestamp() * 1000L)))
.setWindDeg(String.valueOf(hourly.getWindDirection()))
.setWindSpd(String.valueOf(Math.round(hourly.getWindSpeed()))).build());
currentHour++;
if (currentHour > 3 ) // its called three hour weather but shows actually 4 entries
@@ -174,7 +190,7 @@ public class IGPSportWeather {
weatherMsg.getBackOperateType().getNumber(),
weatherMsg.build().toByteArray());
builder.writeChunkedData(support.writeCharacteristicFourth, weatherBytes, support.getMTU());
builder.queue(support.getQueue());
builder.queue();
} catch (IOException e) {
throw new RuntimeException(e);
+5
View File
@@ -2250,6 +2250,11 @@
<string name="devicetype_earfun_air_s" translatable="false">EarFun Air S</string>
<string name="devicetype_earfun_air_pro_4" translatable="false">EarFun Air Pro 4</string>
<string name="devicetype_atc_ble_oepl" translatable="false">ATC_BLE_OEPL</string>
<string name="devicetype_igpsport_bsc200">IGPSPORT BSC200</string>
<string name="devicetype_igpsport_igs630">IGPSPORT iGS630</string>
<string name="task_installing_route">Installing route</string>
<string name="route_upload_completed">Route upload completed</string>
<string name="route_upload_failed">Route upload failed</string>
<string name="choose_auto_export_location">Choose export location</string>
<string name="notification_channel_name">General</string>
<string name="notification_channel_high_priority_name">High-priority</string>