diff --git a/docs/_Sidebar.md b/docs/_Sidebar.md index 766da7eb..48bdf62f 100644 --- a/docs/_Sidebar.md +++ b/docs/_Sidebar.md @@ -20,6 +20,7 @@ ## Custom - [Power Menu](power-menu) +- [Weather](weather) # Modules diff --git a/docs/examples/custom/Weather.md b/docs/examples/custom/Weather.md new file mode 100644 index 00000000..370994d6 --- /dev/null +++ b/docs/examples/custom/Weather.md @@ -0,0 +1,468 @@ +Creates a button on the bar which displays the current weather condition and temperature. +Clicking the button opens a popup with forecast information for the next few days. + +Weather information is fetched from [wttr.in](https://wttr.in) via an external script. +You will need to set up the script to be run as a service. + +![custom weather widget, with popup open](https://f.jstanger.dev/github/ironbar/custom-weather.png) + +## Configuration + +
+JSON + +```json +{ + "end": [ + { + "type": "custom", + "class": "weather", + "bar": [ + { + "type": "button", + "label": "#weather_current", + "on_click": "popup:toggle" + } + ], + "popup": [ + { + "type": "box", + "orientation": "vertical", + "widgets": [ + { + "type": "label", + "name": "header", + "label": "Forecast" + }, + { + "type": "box", + "widgets": [ + { + "type": "box", + "name": "dates", + "orientation": "vertical", + "widgets": [ + { + "type": "label", + "class": "weather-date", + "label": "#weather_date_0" + }, + { + "type": "label", + "class": "weather-date", + "label": "#weather_date_1" + }, + { + "type": "label", + "class": "weather-date", + "label": "#weather_date_2" + } + ] + }, + { + "type": "box", + "name": "temps", + "orientation": "vertical", + "widgets": [ + { + "type": "box", + "widgets": [ + { + "type": "label", + "class": "weather-high", + "label": " #weather_high_0" + }, + { + "type": "label", + "class": "weather-avg", + "label": " #weather_avg_0" + }, + { + "type": "label", + "class": "weather-low", + "label": " #weather_low_0" + } + ] + }, + { + "type": "box", + "widgets": [ + { + "type": "label", + "class": "weather-high", + "label": " #weather_high_1" + }, + { + "type": "label", + "class": "weather-avg", + "label": " #weather_avg_1" + }, + { + "type": "label", + "class": "weather-low", + "label": " #weather_low_1" + } + ] + }, + { + "type": "box", + "widgets": [ + { + "type": "label", + "class": "weather-high", + "label": " #weather_high_2" + }, + { + "type": "label", + "class": "weather-avg", + "label": " #weather_avg_2" + }, + { + "type": "label", + "class": "weather-low", + "label": " #weather_low_2" + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] +} +``` + +
+ +
+TOML + +```toml +[[end]] +type = "custom" +class = "weather" + +[[end.bar]] +type = "button" +label = "#weather_current" +on_click = "popup:toggle" + +[[end.popup]] +type = "box" +orientation = "vertical" + +[[end.popup.widgets]] +type = "label" +name = "header" +label = "Forecast" + +[[end.popup.widgets]] +type = "box" + +[[end.popup.widgets.widgets]] +type = "box" +name = "dates" +orientation = "vertical" + +[[end.popup.widgets.widgets.widgets]] +type = "label" +class = "weather-date" +label = "#weather_date_0" + +[[end.popup.widgets.widgets.widgets]] +type = "label" +class = "weather-date" +label = "#weather_date_1" + +[[end.popup.widgets.widgets.widgets]] +type = "label" +class = "weather-date" +label = "#weather_date_2" + +[[end.popup.widgets.widgets]] +type = "box" +name = "temps" +orientation = "vertical" + +[[end.popup.widgets.widgets.widgets]] +type = "box" + +[[end.popup.widgets.widgets.widgets.widgets]] +type = "label" +class = "weather-high" +label = " #weather_high_0" + +[[end.popup.widgets.widgets.widgets.widgets]] +type = "label" +class = "weather-avg" +label = " #weather_avg_0" + +[[end.popup.widgets.widgets.widgets.widgets]] +type = "label" +class = "weather-low" +label = " #weather_low_0" + +[[end.popup.widgets.widgets.widgets]] +type = "box" + +[[end.popup.widgets.widgets.widgets.widgets]] +type = "label" +class = "weather-high" +label = " #weather_high_1" + +[[end.popup.widgets.widgets.widgets.widgets]] +type = "label" +class = "weather-avg" +label = " #weather_avg_1" + +[[end.popup.widgets.widgets.widgets.widgets]] +type = "label" +class = "weather-low" +label = " #weather_low_1" + +[[end.popup.widgets.widgets.widgets]] +type = "box" + +[[end.popup.widgets.widgets.widgets.widgets]] +type = "label" +class = "weather-high" +label = " #weather_high_2" + +[[end.popup.widgets.widgets.widgets.widgets]] +type = "label" +class = "weather-avg" +label = " #weather_avg_2" + +[[end.popup.widgets.widgets.widgets.widgets]] +type = "label" +class = "weather-low" +label = " #weather_low_2" +``` + +
+ +
+YAML + +```yaml +end: +- type: custom + class: weather + bar: + - type: button + label: '#weather_current' + on_click: popup:toggle + popup: + - type: box + orientation: vertical + widgets: + - type: label + name: header + label: Forecast + - type: box + widgets: + - type: box + name: dates + orientation: vertical + widgets: + - type: label + class: weather-date + label: '#weather_date_0' + - type: label + class: weather-date + label: '#weather_date_1' + - type: label + class: weather-date + label: '#weather_date_2' + - type: box + name: temps + orientation: vertical + widgets: + - type: box + widgets: + - type: label + class: weather-high + label: ' #weather_high_0' + - type: label + class: weather-avg + label: ' #weather_avg_0' + - type: label + class: weather-low + label: ' #weather_low_0' + - type: box + widgets: + - type: label + class: weather-high + label: ' #weather_high_1' + - type: label + class: weather-avg + label: ' #weather_avg_1' + - type: label + class: weather-low + label: ' #weather_low_1' + - type: box + widgets: + - type: label + class: weather-high + label: ' #weather_high_2' + - type: label + class: weather-avg + label: ' #weather_avg_2' + - type: label + class: weather-low + label: ' #weather_low_2' +``` + +
+ +
+Corn + + +```corn +let { + $weather = { + type = "custom" + class = "weather" + + bar = [ { type = "button" label = "#weather_current" on_click = "popup:toggle" } ] + popup = [ { + type = "box" + orientation = "vertical" + + widgets = [ + { type = "label" name = "header" label = "Forecast" } + { + type = "box" + widgets = [ + { type = "box" name="dates" orientation = "vertical" widgets = [ + { type = "label" class="weather-date" label = "#weather_date_0" } + { type = "label" class="weather-date" label = "#weather_date_1" } + { type = "label" class="weather-date" label = "#weather_date_2" } + ]} + { type = "box" name="temps" orientation = "vertical" widgets = [ + { + type = "box" + widgets = [ + { type = "label" class="weather-high" label = " #weather_high_0" } + { type = "label" class="weather-avg" label = " #weather_avg_0" } + { type = "label" class="weather-low" label = " #weather_low_0" } + ] + } + { + type = "box" + widgets = [ + { type = "label" class="weather-high" label = " #weather_high_1" } + { type = "label" class="weather-avg" label = " #weather_avg_1" } + { type = "label" class="weather-low" label = " #weather_low_1" } + ] + } + { + type = "box" + widgets = [ + { type = "label" class="weather-high" label = " #weather_high_2" } + { type = "label" class="weather-avg" label = " #weather_avg_2" } + { type = "label" class="weather-low" label = " #weather_low_2" } + ] + } + ] } + ] + } + ] + } ] + } +} in { + end = [ $weather ] +} +``` + +
+ +## Script + +Run the following script on a timer. Ensure to fill out your city name. + +```js +#!/usr/bin/env zx + +const location = "Canterbury"; + + // JS uses Sunday as first day +const weekday = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]; + +// bar logic + + +const data = await fetch(`https://wttr.in/${location}?format=%c %t|%m %t|%S|%s`) + .then(r => r.text()); + +const [day, night, sunrise, sunset] = data.replaceAll("+", "").split("|"); +const [sunriseH, sunriseM, sunriseS] = sunrise.split(":"); +const [sunsetH, sunsetM, sunsetS] = sunset.split(":"); + +const currentTime = new Date(); + +const sunriseTime = new Date(currentTime); +sunriseTime.setHours(sunriseH); +sunriseTime.setMinutes(sunriseM); +sunriseTime.setSeconds(sunriseS); + +const sunsetTime = new Date(currentTime); +sunsetTime.setHours(sunsetH); +sunsetTime.setMinutes(sunsetM); +sunsetTime.setSeconds(sunsetS); + +let value = day; +if(currentTime < sunriseTime || currentTime > sunsetTime) value = night; + +await $`ironbar set weather_current ${value}`; + +// popup logic + +const forecast = await fetch(`https://wttr.in/${location}?format=j1`).then(r => r.json()); + +for (const i in forecast.weather) { + const report = forecast.weather[i]; + + const day = weekday[new Date(report.date).getDay()]; + + await $`ironbar set weather_date_${i} ${day}`; + await $`ironbar set weather_avg_${i} ${report.avgtempC.padStart(2, "0")}`; + await $`ironbar set weather_high_${i} ${report.maxtempC.padStart(2, "0")}`; + await $`ironbar set weather_low_${i} ${report.mintempC.padStart(2, "0")}`; +} +``` + +## Styling + +```css +.popup-weather #header { + font-size: 1.8em; + padding-bottom: 0.4em; + margin-bottom: 0.6em; + border-bottom: 1px solid @color-border; +} + +.popup-weather .weather-date { + font-size: 1.5em; + padding-right: 1em; +} + +.popup-weather .weather-avg { + margin-left: 0.5em; + margin-right: 0.5em; +} + +/* + this is a hack to align the different font sizes on left/right + you may need to adjust for different fonts +*/ +.popup-weather #temps label { + padding-top: 0.2em; + margin-bottom: 0.7em; +} +``` \ No newline at end of file