Last active
December 30, 2023 13:37
-
-
Save mountbatt/163c5d8f8bd7978e1f3c06b3dcccf00f to your computer and use it in GitHub Desktop.
Scriptable Widget to get Weather Data from a weewx driven Weather-Station via JSON by weewx-json (https://github.com/teeks99/weewx-json). With Shortcodes this Widget is fully Siri compatible!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Variables used by Scriptable. | |
// These must be at the very top of the file. Do not edit. | |
// icon-color: blue; icon-glyph: sun; | |
// Check weewx Weather | |
// Script Updates: https://gist.github.com/mountbatt/163c5d8f8bd7978e1f3c06b3dcccf00f | |
// Version: 0.7.4 | |
// edit: | |
let endpoint = "http://www.waldbadviertel-wetter.de/current_minimal.json" | |
let prefix = "im" // im | in | at ... defines "im Waldbadviertel" oder "in Cologne" (set to "in" or "at" for good english) | |
let widgetLang = Device.language() | |
// do not edit: | |
// language strings | |
let langWeather | |
let langHumidity | |
let langRain | |
let langWind | |
let langMessage | |
let langItsRainingMessage | |
let langRainIntensityLow | |
let langRainIntensityHigh | |
if(widgetLang == "de") { | |
langWeather = "Wetter" | |
langHumidity = "RL" | |
langRain = "R" | |
langWind = "W" | |
langMessage = "Aktuell beträgt die Temperatur" | |
langItsRainingMessage = "Es regnet zur Zeit" | |
langRainIntensityLow = "ein wenig" | |
langRainIntensityHigh = "stark" | |
} else { | |
langWeather = "Weather" | |
langHumidity = "RH" | |
langRain = "R" | |
langWind = "W" | |
langMessage = "Currently the temperature" | |
langItsRainingMessage = "It is currently raining" | |
langRainIntensityLow = "a bit" | |
langRainIntensityHigh = "heavily" | |
} | |
let req = new Request(endpoint) | |
let apiResult = await req.loadJSON() | |
let weatherData = await apiResult | |
let locationName = weatherData.station.location | |
// trunkate locationName after comma (Waldbadviertel, Köln => Waldbadviertel) | |
locationName = locationName.split(',')[0] | |
// moonEmoji | |
let moonEmoji = await getMoonPhase("emoji") | |
let currentRain = weatherData.current['rain rate'].value // with dot 0.2 | |
let sunriseTime = await isDay("sunrise") | |
let sunsetTime = await isDay("sunset") | |
let isDayNight = await isDay() | |
let nextRefresh = new Date(Date.now() + 60 * 2 * 1000); // 5 Min | |
console.log(nextRefresh) | |
if (config.runsWithSiri) { | |
if(weatherData){ | |
let message = langMessage + ' ' + prefix +' '+ locationName +' ' + replaceDot(weatherData.current.temperature.value, 1) + ' ' + weatherData.current.temperature.units + '.'; | |
if(currentRain > 0){ | |
let RainIntensity | |
if(currentRain > 5 ){ | |
RainIntensity = langRainIntensityHigh | |
} else { | |
RainIntensity = langRainIntensityLow | |
} | |
message = message + ' ' + langItsRainingMessage + ' ' + RainIntensity | |
} | |
Script.setShortcutOutput(message) | |
} | |
//Script.complete() | |
} else if (config.runsInWidget) { | |
let widget = createWidget(weatherData, moonEmoji, sunriseTime, sunsetTime, isDayNight, currentRain) | |
widget.refreshAfterDate = nextRefresh; | |
Script.setWidget(widget) | |
Script.complete() | |
} else { | |
let widget = createWidget(weatherData, moonEmoji, sunriseTime, sunsetTime, isDayNight, currentRain) | |
widget.refreshAfterDate = nextRefresh; | |
Script.setWidget(widget) | |
widget.presentSmall() | |
Script.complete() | |
} | |
function createWidget(weatherData, moonEmoji, sunriseTime, sunsetTime, isDayNight, currentRain) { | |
let w = new ListWidget() | |
w.useDefaultPadding() | |
// add url to open to widget | |
let widgetLink = weatherData.station.link | |
if(!widgetLink){ | |
// extract url from endpoint url | |
var pathArray = endpoint.split( '/' ); | |
var protocol = pathArray[0]; | |
var host = pathArray[2]; | |
var url = protocol + '//' + host; | |
widgetLink = url | |
} | |
if(widgetLink){ | |
w.url = widgetLink | |
} | |
// Set gradient background | |
let daytime | |
let startColor | |
let endColor | |
if(isDayNight == true){ | |
if(currentRain > 0){ | |
// day color during rain | |
startColor = new Color("#4e6b7d") | |
endColor = new Color("#5b707d") | |
} else { | |
// day color | |
startColor = new Color("#2e86be") | |
endColor = new Color("#65a8cb") | |
} | |
} else { | |
// night color | |
startColor = new Color("#010722") | |
endColor = new Color("#313b59") | |
} | |
let gradient = new LinearGradient() | |
gradient.colors = [startColor, endColor] | |
gradient.locations = [0.0, 1] | |
w.backgroundGradient = gradient | |
let wHeaderStack = w.addStack() | |
let wNameStack = wHeaderStack.addStack() | |
let wEmojiStack = wHeaderStack.addStack() | |
let wName = wNameStack.addText(langWeather) | |
wName.font = Font.lightSystemFont(13) | |
wName.textColor = Color.white() | |
wEmojiStack.addSpacer() | |
let wEmoji | |
if(isDayNight == true){ | |
if(currentRain > 0 && currentRain < 5){ | |
wEmoji = wEmojiStack.addText('🌦️') | |
} | |
if(currentRain >= 5){ | |
wEmoji = wEmojiStack.addText('🌧️') | |
} | |
if(currentRain == 0){ | |
wEmoji = wEmojiStack.addText('🌤️') | |
} | |
} else { | |
wEmoji = wEmojiStack.addText(moonEmoji) | |
} | |
wEmoji.font = Font.regularSystemFont(13) | |
let wTitle = w.addText(locationName) | |
wTitle.textColor = Color.white() | |
wTitle.font = Font.boldSystemFont(13) | |
w.addSpacer(5) | |
let wTemp = w.addText(replaceDot(weatherData.current.temperature.value, 1) + '' + weatherData.current.temperature.units) | |
wTemp.textColor = Color.white() | |
wTemp.font = Font.lightSystemFont(36) | |
w.addSpacer(5) | |
/* | |
let wHumidity = w.addText(langHumidity + ': ' + replaceDot(weatherData.current.humidity.value) + '' + weatherData.current.humidity.units) | |
wHumidity.textColor = Color.white() | |
wHumidity.font = Font.regularSystemFont(12) | |
let wRain = w.addText(langRain + ': ' + replaceDot(weatherData.current["rain rate"].value, 1) + ' ' + weatherData.current["rain rate"].units) | |
wRain.textColor = Color.white() | |
wRain.font = Font.regularSystemFont(12) | |
*/ | |
let textHumidity = langHumidity + ': ' + replaceDot(weatherData.current.humidity.value) + '' + weatherData.current.humidity.units | |
let textRain = langRain + ': ' + replaceDot(weatherData.current["rain rate"].value, 2) + ' ' + weatherData.current["rain rate"].units | |
let wHumidityAndRain = w.addText(textHumidity + " " + textRain) | |
wHumidityAndRain.textColor = Color.white() | |
wHumidityAndRain.font = Font.regularSystemFont(11) | |
w.addSpacer(2) | |
function getWindDirName(i){ | |
if(i >= 348.75 || i < 11.25){ | |
return "N"; | |
} else if (i >= 11.25 && i < 33.75) { | |
return "NNO"; | |
} else if (i >= 33.75 && i < 56.25) { | |
return "NO"; | |
} else if (i >= 56.25 && i < 78.75) { | |
return "ONO"; | |
} else if (i >= 78.25 && i < 101.25) { | |
return "O"; | |
} else if (i >= 101.25 && i < 123.75) { | |
return "OSO"; | |
} else if (i >= 123.75 && i < 146.25) { | |
return "SO"; | |
} else if (i >= 146.25 && i < 168.75) { | |
return "SSO"; | |
} else if (i >= 168.75 && i < 191.25) { | |
return "S"; | |
} else if (i >= 191.25 && i < 213.75) { | |
return "SSW"; | |
} else if (i >= 213.75 && i < 236.25) { | |
return "SW"; | |
} else if (i >= 236.25 && i < 258.75) { | |
return "WSW"; | |
} else if (i >= 258.75 && i < 281.25) { | |
return "W"; | |
} else if (i >= 281.25 && i < 303.75) { | |
return "WNW"; | |
} else if (i >= 303.75 && i < 326.25) { | |
return "NW"; | |
} else if (i >= 326.25 && i < 348.75) { | |
return "NNW"; | |
} else { | |
return ""; | |
} | |
} | |
let windDirectionText = " " | |
if(typeof(weatherData.current["wind direction"]) != 'undefined'){ | |
windDirectionText = getWindDirName(weatherData.current["wind direction"].value) | |
} | |
let wWind = w.addText(langWind + ': ' + replaceDot(weatherData.current["wind speed"].value, 1) + ' ' + weatherData.current["wind speed"].units + " " + windDirectionText) | |
wWind.textColor = Color.white() | |
wWind.font = Font.regularSystemFont(11) | |
w.addSpacer(2) | |
let textSunriseTime = new Date(sunriseTime).getHours()+':'+(new Date(sunriseTime).getMinutes()<10?'0':'') + new Date(sunriseTime).getMinutes() | |
let textSunsetTime = new Date(sunsetTime).getHours()+':'+(new Date(sunsetTime).getMinutes()<10?'0':'') + new Date(sunsetTime).getMinutes() | |
let wSun = w.addText("☀↑ " + textSunriseTime + " ↓ " + textSunsetTime) | |
wSun.textColor = Color.white() | |
wSun.font = Font.regularSystemFont(11) | |
//w.addSpacer() // push to top | |
return w | |
} | |
function replaceDot(value, decimal = 0){ | |
value = value.toFixed(decimal) | |
if(widgetLang == "de"){ | |
// if "de" we replace a dot with a comma for decimal numbers | |
value = value.toString().replace(/\./g, ',') | |
} | |
return value | |
} | |
async function isDay(response) { | |
let stationLat = weatherData.station.latitude | |
let stationLon = weatherData.station.longitude | |
// get sunrise sunset via https://sunrise-sunset.org/api - thanks!!! <3 | |
let dayEndpoint = "https://api.sunrise-sunset.org/json?lat="+stationLat+"&lng="+stationLon+"&date=today&formatted=0" | |
let dRequest = new Request(dayEndpoint); | |
let dApiResult = await dRequest.loadJSON() | |
if(response && dApiResult.status == "OK"){ | |
if(response == "sunrise") { | |
return dApiResult.results.sunrise | |
} | |
if(response == "sunset") { | |
return dApiResult.results.sunset | |
} | |
} else { | |
if(dApiResult.status == "OK") { | |
let sunrise = dApiResult.results.sunrise | |
sunrise = Math.round(Date.parse(sunrise)/1000) | |
let sunset = dApiResult.results.sunset | |
sunset = Math.round(Date.parse(sunset)/1000) | |
let now = Math.round(Date.now()/1000) | |
if(now > sunrise && now < sunset){ | |
// day | |
return true | |
} else { | |
// night | |
return false | |
} | |
} else { | |
const hours = new Date().getHours() | |
const isDayTime = hours > 6 && hours < 19 | |
return isDayTime // returns true if its daytime | |
} | |
} | |
} | |
async function getMoonPhase(type = "index"){ | |
let currTime = Math.floor(Date.now() / 1000) | |
let mEndpoint = "https://api.farmsense.net/v1/moonphases/?d=" + currTime | |
let mImagePath = "https://www.farmsense.net/demos/images/moonphases/" | |
let mRequest = new Request(mEndpoint); | |
let mApiResult = await mRequest.loadJSON() | |
let moonIndex = mApiResult[0].Index; | |
let moonPhase = mApiResult[0].Phase; | |
let moonPhaseSanitized = moonPhase.replace(/\s+/g, '_').toLowerCase(); | |
let moonPhaseEmoji = await getMoonEmoji(mApiResult[0].Age) | |
mImagePath = mImagePath+moonIndex+'.png' | |
if(type == "image"){ | |
return mImagePath | |
} | |
if(type == "index"){ | |
return moonIndex | |
} | |
if(type == "phase"){ | |
return moonPhaseSanitized | |
} | |
if(type == "emoji"){ | |
return moonPhaseEmoji | |
} | |
} | |
async function getMoonEmoji(phase){ | |
if( phase < 1.84566 ){ return "🌑" } // new | |
else if ( phase < 5.53699 ) { return "🌒" } // waxing crescent | |
else if ( phase < 9.22831 ) { return "🌓" } // first quarter | |
else if ( phase < 12.91963 ) { return "🌔" } // waxing gibbous | |
else if ( phase < 16.61096 ) { return "🌕" } // full | |
else if ( phase < 20.30228 ) { return "🌖" } // waning gibbous | |
else if ( phase < 23.99361 ) { return "🌗" } // last quarter | |
else if ( phase < 27.68493 ) { return "🌘" } // waning crescent | |
else { return "🌑" } // new | |
} | |
// end of file | |
// |
Hello, i was looking at this code and noticied that the isDay function gets called three times, making a new web request each time. i wrote a patch to fix this.
diff --git "a/.\\theirs.js" "b/.\\mine.js"
index f15e0f1..df1c333 100644
--- "a/.\\theirs.js"
+++ "b/.\\mine.js"
@@ -51,9 +51,8 @@ locationName = locationName.split(',')[0]
// moonEmoji
let moonEmoji = await getMoonPhase("emoji")
let currentRain = weatherData.current['rain rate'].value // with dot 0.2
-let sunriseTime = await isDay("sunrise")
-let sunsetTime = await isDay("sunset")
-let isDayNight = await isDay()
+let [ sunriseTime, sunsetTime, isDayNight ] = await isDay()
+
let nextRefresh = new Date(Date.now() + 60 * 2 * 1000); // 5 Min
console.log(nextRefresh)
@@ -256,44 +255,30 @@ function replaceDot(value, decimal = 0) {
return value
}
-async function isDay(response) {
+async function isDay() {
let stationLat = weatherData.station.latitude
let stationLon = weatherData.station.longitude
// get sunrise sunset via https://sunrise-sunset.org/api - thanks!!! <3
let dayEndpoint = "https://api.sunrise-sunset.org/json?lat=" + stationLat + "&lng=" + stationLon + "&date=today&formatted=0"
let dRequest = new Request(dayEndpoint);
let dApiResult = await dRequest.loadJSON()
- if (response && dApiResult.status == "OK") {
- if (response == "sunrise") {
- return dApiResult.results.sunrise
- }
- if (response == "sunset") {
- return dApiResult.results.sunset
- }
- } else {
- if (dApiResult.status == "OK") {
- let sunrise = dApiResult.results.sunrise
- sunrise = Math.round(Date.parse(sunrise) / 1000)
- let sunset = dApiResult.results.sunset
- sunset = Math.round(Date.parse(sunset) / 1000)
- let now = Math.round(Date.now() / 1000)
- if (now > sunrise && now < sunset) {
- // day
- return true
-
- } else {
- // night
- return false
+ if (dApiResult.status == "OK") {
+ let sunrise = dApiResult.results.sunrise
+ sunrise = Math.round(Date.parse(sunrise) / 1000)
+ let sunset = dApiResult.results.sunset
+ sunset = Math.round(Date.parse(sunset) / 1000)
+ let now = Math.round(Date.now() / 1000)
+ let isSunUp = now > sunrise && now < sunset
+ return [sunrise, sunset, isSunUp];
- }
- } else {
- const hours = new Date().getHours()
- const isDayTime = hours > 6 && hours < 19
- return isDayTime // returns true if its daytime
- }
+ } else {
+ const hours = new Date().getHours()
+ const isDayTime = hours > 6 && hours < 19
+ return [undefined, undefined, isDayTime] // returns true if its daytime
}
}
+
async function getMoonPhase(type = "index") {
let currTime = Math.floor(Date.now() / 1000)
let mEndpoint = "https://api.farmsense.net/v1/moonphases/?d=" + currTime
i used javascript's destructuring to return multiple variables from a single call. this will reduct the number of API hits to the sunrise sunset API from 3 to 1 per call of the script.
@mralext20 Hi Alex, thanks! Good point! Could you be so kind and post the full code here or link to a gist? Thanks! (Or otherwise: how can i mix your changes with mine? I am not that deep into git …)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Intro
Mit diesem iOS Widget können aktuelle Wetterdaten von einer weewx Website geladen werden.
Beispiel: http://www.waldbadviertel-wetter.de
Die Daten werden per JSON übermittelt. Dafür muss die Wetterstation die Daten mit dem Plugin weewx-json bereitstellen. Das Plugin findet man hier: https://github.com/teeks99/weewx-json
Anforderungen
Installation
Wähle unter "Script" das oben erstellte aus (Wetter)
Siri Shortcut einrichten
Updates
04.03.2021
03.03.2021
03.03.2021
03.03.2021
03.03.2021
02.03.2021
02.03.2021
02.03.2021