Skip to content

weather 0.28: Fix UV positioning, hide when 0 #3908

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion apps/weather/ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@
0.24: Redraw clock_info on update and provide color field for condition
0.25: Added monochrome parameter to drawIcon in lib
0.26: Expose update function (for use by iOS integration)
0.27: Add UV index display
0.27: Add UV index display
0.28: Fix UV positioning, hide when 0
8 changes: 6 additions & 2 deletions apps/weather/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ It also adds a ClockInfo list to Bangle.js.
You can view the full report through the app:

![Screenshot](screenshot.png)

## iOS Setup
Use the iOS shortcut [here](https://www.icloud.com/shortcuts/dbf7159200d945179e0938c15e64f102). The shortcut uses Apple Weather for weather updates, and sends a notification, which is read by Bangle.js. To push weather every hour, or interval, you will need to create a shortcut automation for every time you want to push the weather.

Use the iOS shortcut [here](https://www.icloud.com/shortcuts/73be0ce1076446f3bdc45a5707de5c4d). The shortcut uses Apple Weather for weather updates, and sends a notification, which is read by Bangle.js. To push weather every hour, or interval, you will need to create a shortcut automation for every time you want to push the weather.

## Android Setup

1. Install [Gadgetbridge for Android](https://f-droid.org/packages/nodomain.freeyourgadget.gadgetbridge/) on your phone.
Expand Down Expand Up @@ -51,15 +54,16 @@ When you first load QuickWeather, it will take you through the setup process. Yo

**Note:** at one time, the Weather Notification app also worked with Gadgetbridge. However, many users are reporting it's no longer seeing the OpenWeatherMap API key as valid. The app has not received any updates since August of 2020, and may be unmaintained.


## Clock Infos

Tap on any clockInfo when focused to directly open the weather app.
Adds:
* Condition ClockInfo with condition icon
* Temperature ClockInfo with condition icon.
* Wind speed ClockInfo.
* Chance of rain ClockInfo.
* Temperature ClockInfo without condition icon.

## Settings

* Expiration timespan can be set after which the local weather data is considered as invalid
Expand Down
59 changes: 31 additions & 28 deletions apps/weather/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,54 +9,56 @@ Bangle.loadWidgets();
var layout = new Layout({type:"v", bgCol: g.theme.bg, c: [
{filly: 1},
{type: "h", filly: 0, c: [
{type: "v", width: g.getWidth()/2, c: [ // Vertical container for icon + UV
{type: "v", width: g.getWidth()/2, c: [ // Vertical container for icon
{type: "custom", fillx: 1, height: g.getHeight()/2 - 30, valign: -1, txt: "unknown", id: "icon",
render: l => weather.drawIcon(l, l.x+l.w/2, l.y+l.h/2, l.w/2-10)},
{type: "custom", fillx: 1, height: 20, id: "uvDisplay",
render: l => weather.drawIcon(l, l.x+l.w/2, l.y+l.h/2, l.w/2-5)},
]},
{type: "v", fillx: 1, c: [
{type: "h", pad: 2, c: [
{type: "txt", font: "18%", id: "temp", label: "000"},
{type: "txt", font: "12%", valign: -1, id: "tempUnit", label: "°C"},
]},
{filly: 1},
{type: "txt", font: "6x8", pad: 2, halign: 1, label: /*LANG*/"Humidity"},
{type: "txt", font: "9%", pad: 2, halign: 1, id: "hum", label: "000%"},
{type: "txt", font: "6x8", pad: [2, 2, 2, 2], halign: -1, label: /*LANG*/"Wind"},
{type: "h", pad: [0, 2, 2, 2], halign: -1, c: [
{type: "txt", font: "9%", pad: 2, id: "wind", label: "00"},
{type: "txt", font: "6x8", pad: 2, valign: -1, id: "windUnit", label: "km/h"},
]},
{type: "custom", fillx: 1, height: 15, id: "uvDisplay",
render: l => {
if (!current || current.uv === undefined) return;
if (!current || current.uv === undefined || current.uv === 0) return;
const uv = Math.min(parseInt(current.uv), 11); // Cap at 11

// UV color thresholds: [max_value, color] based on WHO standards
const colors = [[2,"#0F0"], [5,"#FF0"], [7,"#F80"], [10,"#F00"], [11,"#F0F"]];
const color = colors.find(c => uv <= c[0])[1];
const blockH = 8, blockW = 3;

// Setup and measure label
// Draw UV title and blocks on same line
g.setFont("6x8").setFontAlign(-1, 0);
const label = "UV: ";
const label = "UV";
const labelW = g.stringWidth(label);

// Calculate centered position (4px block + 1px spacing) * blocks - last spacing
const totalW = labelW + uv * 5 - (uv > 0 ? 1 : 0);
const x = l.x + (l.w - totalW) / 2;
const y = l.y + l.h;
const x = l.x + 2;
const y = l.y + l.h / 2;

// Draw label
// Draw title
g.setColor(g.theme.fg).drawString(label, x, y);

// Draw UV blocks
// Draw UV blocks after title
g.setColor(color);
for (let i = 0; i < uv; i++) {
g.fillRect(x + labelW + i * 5, y - 3, x + labelW + i * 5 + 3, y + 3);
const blockX = x + labelW + 4 + i * (blockW + 2);
g.fillRect(blockX, y - blockH/2, blockX + blockW, y + blockW/2);
}

// Reset graphics state to prevent interference
g.reset();
}
},
]},
{type: "v", fillx: 1, c: [
{type: "h", pad: 2, c: [
{type: "txt", font: "18%", id: "temp", label: "000"},
{type: "txt", font: "12%", valign: -1, id: "tempUnit", label: "°C"},
]},
{filly: 1},
{type: "txt", font: "6x8", pad: 2, halign: 1, label: /*LANG*/"Humidity"},
{type: "txt", font: "9%", pad: 2, halign: 1, id: "hum", label: "000%"},
{filly: 1},
{type: "txt", font: "6x8", pad: 2, halign: -1, label: /*LANG*/"Wind"},
{type: "h", halign: -1, c: [
{type: "txt", font: "9%", pad: 2, id: "wind", label: "00"},
{type: "txt", font: "6x8", pad: 2, valign: -1, id: "windUnit", label: "km/h"},
]},
]},
]},
{filly: 1},
{type: "txt", font: "9%", wrap: true, height: g.getHeight()*0.18, fillx: 1, id: "cond", label: /*LANG*/"Weather condition"},
Expand Down Expand Up @@ -91,6 +93,7 @@ function draw() {
layout.loc.label = current.loc;
layout.updateTime.label = `${formatDuration(Date.now() - current.time)} ago`; // How to autotranslate this and similar?
layout.update();
layout.forgetLazyState();
layout.render();
}

Expand Down
2 changes: 1 addition & 1 deletion apps/weather/metadata.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "weather",
"name": "Weather",
"version": "0.27",
"version": "0.28",
"description": "Show Gadgetbridge/iOS weather report",
"icon": "icon.png",
"screenshots": [{"url":"screenshot.png"}],
Expand Down