Skip to content

Commit c58d503

Browse files
committed
Weather: Add support for only extended weather data without forecast
Android only support for now. With extended data we can parse feels like temperature with GB same as on iOS.
1 parent 42bf5b3 commit c58d503

File tree

3 files changed

+42
-18
lines changed

3 files changed

+42
-18
lines changed

apps/weather/README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ Adds:
7777

7878
* Expiration time span can be set after which the local weather data is considered as invalid
7979
* Automatic weather data request interval can be set (weather data are pushed to Bangle automatically, but this can help in cases when it fails) (requires Gadgetbridge v0.86+)
80-
* Forecast weather data can be enabled (this requires other App to use the data, Weather App itself doesn't show the forecast data) (requires Gadgetbridge v0.86+)
80+
* Extended or forecast weather data can be enabled (this requires other App to use this data, Weather App itself doesn't show the forecast data) (requires Gadgetbridge v0.86+)
8181
* Widget can be hidden
8282
* To change the units for wind speed, you can install the [`Languages app`](https://banglejs.com/apps/?id=locale) which
8383
allows you to choose the units used for speed/distance/temperature and so on.
@@ -89,15 +89,17 @@ allows you to choose the units used for speed/distance/temperature and so on.
8989

9090
## Weather App API
9191

92+
Note: except `getWeather()` and `get()` it is android only for now
93+
9294
Weather App can provide weather and forecast data to other Apps.
9395

94-
* Get weather data without forecast:
96+
* Get weather data without forecast/extended:
9597
```javascript
9698
const weather = require("weather");
9799
weatherData = weather.getWeather(false); // or weather.get()
98100
```
99101

100-
* Get weather data with forecast (needs forecast enabled in settings):
102+
* Get weather data with forecast/extended (needs forecast/extended enabled in settings):
101103
```javascript
102104
const weather = require("weather");
103105
weatherData = weather.getWeather(true);

apps/weather/lib.js

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,13 @@ function update(weatherEvent) {
6161
storage.write("weather.json", json);
6262
exports.emit("update", weather);
6363

64-
// Request forecast if supported by GadgetBridge and set in settings
65-
if (weatherEvent.v != null && (weatherSetting.forecast ?? false)) {
64+
// Request extended/forecast if supported by Weather Provider and set in settings
65+
if (weatherEvent.v != null && (weatherSetting.dataType ?? "basic") !== "basic") {
6666
updateWeather(true);
6767
}
6868

69-
// Either GadgetBridge doesn't support v2 and/or we don't need forecast, so we use this event for refresh scheduling
70-
if (weatherEvent.v == null || (weatherSetting.forecast ?? false) === false) {
69+
// Either Weather Provider doesn't support v2 and/or we don't need extended/forecast, so we use this event for refresh scheduling
70+
if (weatherEvent.v == null || (weatherSetting.dataType ?? "basic") === "basic") {
7171
weatherSetting.time = Date.now();
7272
storage.write("weatherSetting.json", weatherSetting);
7373

@@ -93,6 +93,12 @@ function update(weatherEvent) {
9393
// Store simpler weather for apps that doesn't need forecast or backward compatibility
9494
const weather = downgradeWeatherV2(weather2);
9595
storage.write("weather.json", weather);
96+
exports.emit("update", weather);
97+
} else if (weather1.weather != null && weather1.weather.feels === undefined) {
98+
// Grab feels like temperature as we have it in v2
99+
weather1.weather.feels = decodeWeatherV2FeelsLike(weatherEvent);
100+
storage.write("weather.json", weather);
101+
exports.emit("update", weather);
96102
}
97103

98104
cloned = undefined; // Clear memory
@@ -111,15 +117,15 @@ function updateWeather(force) {
111117

112118
// More than 5 minutes
113119
if (force || Date.now() - lastFetch >= 5 * 60 * 1000) {
114-
Bluetooth.println("");
115-
Bluetooth.println(JSON.stringify({ t: "weather", v: 2, f: settings.forecast ?? false }));
120+
Bluetooth.println(""); // This empty line is important for correct communication with Weather Provider
121+
Bluetooth.println(JSON.stringify({ t: "weather", v: 2, f: settings.dataType === "forecast" }));
116122
}
117123
}
118124

119-
function getWeather(forecast) {
125+
function getWeather(extended) {
120126
const weatherSetting = storage.readJSON("weatherSetting.json") || {};
121127

122-
if (forecast === false || !(weatherSetting.forecast ?? false)) {
128+
if (extended === false || (weatherSetting.dataType ?? "basic") === "basic") {
123129
// biome-ignore lint/complexity/useOptionalChain: not supported by Espruino
124130
return (storage.readJSON("weather.json") ?? {}).weather;
125131
} else {
@@ -169,7 +175,7 @@ function decodeWeatherV2(jsonData, canDestroyArgument, parseForecast) {
169175
return { t: "weather2", v: 2, time: time };
170176
}
171177

172-
// This needs to be kept in sync with GadgetBridge
178+
// This needs to be kept in sync with Weather Provider
173179
const weatherCodes = [
174180
[200, 201, 202, 210, 211, 212, 221, 230, 231, 232],
175181
[300, 301, 302, 310, 311, 312, 313, 314, 321],
@@ -214,7 +220,7 @@ function decodeWeatherV2(jsonData, canDestroyArgument, parseForecast) {
214220
moonrise: dataView.getUint32(27, true),
215221
moonset: dataView.getUint32(31, true),
216222
moonphase: dataView.getUint16(35, true),
217-
feel: dataView.getInt8(37, true),
223+
feels: dataView.getInt8(37, true),
218224
};
219225
weather.wrose = windDirection(weather.wdir);
220226

@@ -256,6 +262,16 @@ function decodeWeatherV2(jsonData, canDestroyArgument, parseForecast) {
256262
return weather;
257263
}
258264

265+
function decodeWeatherV2FeelsLike(jsonData) {
266+
if (jsonData == null || jsonData.d == null) {
267+
return undefined;
268+
}
269+
270+
const buffer = E.toArrayBuffer(atob(jsonData.d));
271+
272+
return new DataView(buffer).getInt8(37, true);
273+
}
274+
259275
function downgradeWeatherV2(weather2) {
260276
const json = { t: "weather" };
261277

@@ -274,6 +290,7 @@ function downgradeWeatherV2(weather2) {
274290
wdir: weather2.wdir,
275291
wrose: weather2.wrose,
276292
loc: weather2.loc,
293+
feels: weather2.feels,
277294
};
278295

279296
return json;

apps/weather/settings.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
storage.write("weatherSetting.json", settings);
2020
}
2121

22+
const DATA_TYPE = ["basic", "extended", "forecast"];
23+
2224
E.showMenu({
2325
"": { "title": "Weather" },
2426
"Expiry": {
@@ -45,11 +47,14 @@
4547
},
4648
onchange: (x) => save("refresh", x),
4749
},
48-
Forecast: {
49-
value: "forecast" in settings ? settings.forecast : false,
50-
onchange: () => {
51-
settings.forecast = !settings.forecast;
52-
save("forecast", settings.forecast);
50+
"Data type": {
51+
value: DATA_TYPE.indexOf(settings.dataType ?? "basic"),
52+
format: (v) => DATA_TYPE[v],
53+
min: 0,
54+
max: DATA_TYPE.length - 1,
55+
onchange: (v) => {
56+
settings.dataType = DATA_TYPE[v];
57+
save("dataType", settings.dataType);
5358
},
5459
},
5560
"Hide Widget": {

0 commit comments

Comments
 (0)