Private Weather App, powered by Dark Sky, with Google Apps Script backend
V
Viktor Z
started a topic
over 8 years ago
I was unhappy with stock weather app, because it refreshes infrequently (three hours old "current" temperature? Seriously?). So I quickly put together my own.
It's a "push" Indicator App, and the push data is provided by Google Apps Script set to run every 15 min. Those scripts are hosted by Google (for free). The script retrieves data from The Dark Sky Forecast API (https://developer.forecast.io/). It's free up to 1000 request per day, but you have to register and get API key you need to put into the script:
function getDarkSkyWeather() {
var result = UrlFetchApp.fetch("https://api.forecast.io/forecast/<PUT YOUR FORECAST API KEY HERE>/35.00,-120.00?units=si&exclude=flags,hourly,daily,alerts");
//Logger.log(result);
var json = JSON.parse(result);
//Logger.log(json.currently);
return json;
}
function convertDarkSkyToLaMetric(darkSkyJson) {
var temp = darkSkyJson.currently.temperature;
var icon = darkSkyJson.currently.icon;
var minutelySummary = darkSkyJson.minutely.summary;
var minutelyIcon = darkSkyJson.minutely.icon;
return {
"frames": [
{
"index": 0,
"text": Math.round(temp) + "°",
"icon": pickIcon(icon)
},
{
"index": 1,
"text": minutelySummary,
"icon": pickIcon(minutelyIcon)
},
]
}
}
function pickIcon(icon) { // clear-day, clear-night, rain, snow, sleet, wind, fog, cloudy, partly-cloudy-day, or partly-cloudy-night
switch (icon) {
case "clear-day": return "a2282";
case "cloudy": return "a2283";
case "rain": return "a2284";
case "sleet": return "a160";
case "partly-cloudy-day": return "a2286";
case "snow": return "a2289";
case "clear-night": return "i2314";
case "wind": return "a2440";
case "fog": return "i2158";
case "partly-cloudy-night": return "i2152";
default: return "i73";
}
}
function executePost() {
var payload = convertDarkSkyToLaMetric(getDarkSkyWeather());
var options = {
"method" : "post",
"payload" : JSON.stringify(payload),
"contentType": "application/json",
"headers" : {
"X-Access-Token" : "<PUT YOUR LAMETRIC ACCESS TOKEN HERE>"
}
};
var result = UrlFetchApp.fetch("https://developer.lametric.com/api/V1/dev/widget/update/com.lametric.<PUT YOUR APP ID HERE>/1", options);
Logger.log(result);
}
var minutelySummary = darkSkyJson.currently.summary;
var minutelyIcon = darkSkyJson.currently.icon;
var currentlywindSpeed = darkSkyJson.currently.windSpeed + " m/s";
var currentlywindIcon = "a3363";
var currentlywindRikt = darkSkyJson.currently.windBearing;
var vindriktIcon = "a12194";
var currentlyTrycket = darkSkyJson.currently.pressure + " hPa";
var TrycketIcon = "a2272";
var kommande = darkSkyJson.daily.summary;
return {
"frames": [
{
"index": 0,
"text": Math.round(temp) + "°",
"icon": pickIcon(icon)
},
{
"index": 1,
"text": minutelySummary,
"icon": pickIcon(minutelyIcon)
},
{
"index": 2,
"text": currentlywindSpeed,
"icon": currentlywindIcon
},
{
"index": 3,
"text": degToCompass(currentlywindRikt),
"icon": vindriktIcon
},
{
"index": 4,
"text": currentlyTrycket,
"icon": TrycketIcon
},
{
"index": 5,
"text": kommande,
"icon": TrycketIcon
}
]
}
}
function pickIcon(icon) { // clear-day, clear-night, rain, snow, sleet, wind, fog, cloudy, partly-cloudy-day, or partly-cloudy-night
switch (icon) {
case "clear-day": return "a2282";
case "cloudy": return "a2283";
case "rain": return "a2284";
case "sleet": return "a160";
case "partly-cloudy-day": return "a2286";
case "snow": return "a2289";
case "clear-night": return "i2314";
case "wind": return "a2440";
case "fog": return "i2158";
case "partly-cloudy-night": return "i2152";
default: return "i73";
}
}
function executePost() {
var payload = convertDarkSkyToLaMetric(getDarkSkyWeather());
var options = {
"method" : "post",
"payload" : JSON.stringify(payload),
"contentType": "application/json",
"headers" : {
"X-Access-Token" : "xx"
}
};
var result = UrlFetchApp.fetch("xx", options);
Logger.log(result);
}
V
Viktor Z
said
almost 7 years ago
Here is response I've got for your coordinates:
{"latitude":56.03129,"longitude":14.15242,"timezone":"Europe/Stockholm","currently":{"time":1510873140,"summary":"Drizzle and Breezy","icon":"rain","precipIntensity":0.3124,"precipProbability":0.42,"precipType":"rain","temperature":8.69,"apparentTemperature":4.89,"dewPoint":8.19,"humidity":0.97,"pressure":1014.26,"windSpeed":8.27,"windGust":12.5,"windBearing":330,"cloudCover":0.83,"uvIndex":0,"visibility":8,"ozone":303.94},"offset":1}
For comparison, this is what I've got for a random address in San Francisco:
{"latitude":37.7806108,"longitude":-122.4332017,"timezone":"America/Los_Angeles","currently":{"time":1510873468,"summary":"Drizzle","icon":"rain","nearestStormDistance":0,"precipIntensity":0.0762,"precipIntensityError":0,"precipProbability":0.97,"precipType":"rain","temperature":13.66,"apparentTemperature":13.66,"dewPoint":12.28,"humidity":0.91,"pressure":1012.21,"windSpeed":1.19,"windGust":1.69,"windBearing":238,"cloudCover":0.54,"uvIndex":1,"visibility":12.42,"ozone":256.25},"minutely":{"summary":"Drizzle stopping in 25 min.","icon":"rain","data":[{"time":1510873440,"precipIntensity":0.0762,"precipIntensityError":0,"precipProbability":0.98,"precipType":"rain"},{"time":1510873500,"precipIntensity":0.0762,"precipIntensityError":0,"precipProbability":0.96,"precipType":"rain"},{"time":1510873560,"precipIntensity":0.0762,"precipIntensityError":0,"precipProbability":0.97,"precipType":"rain"},{"time":1510873620,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.98,"precipType":"rain"},{"time":1510873680,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.97,"precipType":"rain"},{"time":1510873740,"precipIntensity":0.1016,"precipIntensityError":0.0254,"precipProbability":0.92,"precipType":"rain"},{"time":1510873800,"precipIntensity":0.1016,"precipIntensityError":0.0254,"precipProbability":0.93,"precipType":"rain"},{"time":1510873860,"precipIntensity":0.1016,"precipIntensityError":0.0254,"precipProbability":0.97,"precipType":"rain"},{"time":1510873920,"precipIntensity":0.1016,"precipIntensityError":0.0254,"precipProbability":0.99,"precipType":"rain"},{"time":1510873980,"precipIntensity":0.127,"precipIntensityError":0.0254,"precipProbability":0.99,"precipType":"rain"},{"time":1510874040,"precipIntensity":0.127,"precipIntensityError":0.0254,"precipProbability":0.99,"precipType":"rain"},{"time":1510874100,"precipIntensity":0.127,"precipIntensityError":0.0254,"precipProbability":0.99,"precipType":"rain"},{"time":1510874160,"precipIntensity":0.127,"precipIntensityError":0.0508,"precipProbability":1,"precipType":"rain"},{"time":1510874220,"precipIntensity":0.127,"precipIntensityError":0.0508,"precipProbability":0.99,"precipType":"rain"},{"time":1510874280,"precipIntensity":0.127,"precipIntensityError":0.0508,"precipProbability":0.99,"precipType":"rain"},{"time":1510874340,"precipIntensity":0.1016,"precipIntensityError":0.0508,"precipProbability":0.99,"precipType":"rain"},{"time":1510874400,"precipIntensity":0.1016,"precipIntensityError":0.0508,"precipProbability":0.98,"precipType":"rain"},{"time":1510874460,"precipIntensity":0.1016,"precipIntensityError":0.0508,"precipProbability":0.97,"precipType":"rain"},{"time":1510874520,"precipIntensity":0.1016,"precipIntensityError":0.0254,"precipProbability":0.95,"precipType":"rain"},{"time":1510874580,"precipIntensity":0.1016,"precipIntensityError":0.0254,"precipProbability":0.94,"precipType":"rain"},{"time":1510874640,"precipIntensity":0.1016,"precipIntensityError":0.0254,"precipProbability":0.91,"precipType":"rain"},{"time":1510874700,"precipIntensity":0.1016,"precipIntensityError":0.0254,"precipProbability":0.88,"precipType":"rain"},{"time":1510874760,"precipIntensity":0.1016,"precipIntensityError":0.0254,"precipProbability":0.83,"precipType":"rain"},{"time":1510874820,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.76,"precipType":"rain"},{"time":1510874880,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.71,"precipType":"rain"},{"time":1510874940,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.65,"precipType":"rain"},{"time":1510875000,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.6,"precipType":"rain"},{"time":1510875060,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.55,"precipType":"rain"},{"time":1510875120,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.49,"precipType":"rain"},{"time":1510875180,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.47,"precipType":"rain"},{"time":1510875240,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.44,"precipType":"rain"},{"time":1510875300,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.41,"precipType":"rain"},{"time":1510875360,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.4,"precipType":"rain"},{"time":1510875420,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.37,"precipType":"rain"},{"time":1510875480,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.38,"precipType":"rain"},{"time":1510875540,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.37,"precipType":"rain"},{"time":1510875600,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.37,"precipType":"rain"},{"time":1510875660,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.39,"precipType":"rain"},{"time":1510875720,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.4,"precipType":"rain"},{"time":1510875780,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.41,"precipType":"rain"},{"time":1510875840,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.43,"precipType":"rain"},{"time":1510875900,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.43,"precipType":"rain"},{"time":1510875960,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.44,"precipType":"rain"},{"time":1510876020,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.45,"precipType":"rain"},{"time":1510876080,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.45,"precipType":"rain"},{"time":1510876140,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.45,"precipType":"rain"},{"time":1510876200,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.43,"precipType":"rain"},{"time":1510876260,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.42,"precipType":"rain"},{"time":1510876320,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.41,"precipType":"rain"},{"time":1510876380,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.39,"precipType":"rain"},{"time":1510876440,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.38,"precipType":"rain"},{"time":1510876500,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.37,"precipType":"rain"},{"time":1510876560,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.34,"precipType":"rain"},{"time":1510876620,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.34,"precipType":"rain"},{"time":1510876680,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.34,"precipType":"rain"},{"time":1510876740,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.32,"precipType":"rain"},{"time":1510876800,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.32,"precipType":"rain"},{"time":1510876860,"precipIntensity":0.0762,"precipIntensityError":0.0254,"precipProbability":0.31,"precipType":"rain"},{"time":1510876920,"precipIntensity":0.1016,"precipIntensityError":0.0254,"precipProbability":0.31,"precipType":"rain"},{"time":1510876980,"precipIntensity":0.1016,"precipIntensityError":0.0508,"precipProbability":0.32,"precipType":"rain"},{"time":1510877040,"precipIntensity":0.1016,"precipIntensityError":0.0508,"precipProbability":0.32,"precipType":"rain"}]},"offset":-8}
Stefan Rydberg
said
almost 7 years ago
Ok, i have to try other locations and so on. I ve got resspnse in my pythonscript on daily.summary but for wrong day. I am trying to get that right also. Can you i fyou have time try to get data from daily.summary for Kristianstad Sweden lat 56.03129 long 14.15242? I would like to get a short forecast for the tomorrow.
kind regards Stefan
V
Viktor Z
said
almost 7 years ago
Also, maybe the provider simply have no data for your location. Documentation says:
Never make any assumptions about the presence of data or lengths of arrays. For example, a lack of data in our data sources may cause data to be missing
V
Viktor Z
said
almost 7 years ago
Stefan,
No, I am not paying anything and "minutely" info is there in the response. It is spelled "minutely" though, not "minutly". Make sure you are not misspelling it in you code too. And make sure you do not "exclude" it from the request.
Stefan Rydberg
said
almost 7 years ago
Viktor Z
I am hooked on this :D
But i am stuck a little again. I can only use currently data, but in your gs there in minutly also. That re guest do not work. Do I need paid key for that?
Kind regards
Stefan
Stefan Rydberg
said
almost 7 years ago
Thanks!
I have got it to work and start to understand the basics.
Viktor Z
I was unhappy with stock weather app, because it refreshes infrequently (three hours old "current" temperature? Seriously?). So I quickly put together my own.
It's a "push" Indicator App, and the push data is provided by Google Apps Script set to run every 15 min. Those scripts are hosted by Google (for free). The script retrieves data from The Dark Sky Forecast API (https://developer.forecast.io/). It's free up to 1000 request per day, but you have to register and get API key you need to put into the script:
1. Here you can find information on updating apps. We've added instructions.
2. Currently it is not possible to use icons from LaMetric Weather App, but you can create your own.
Please follow instructions in User Guide (7.6. Searching and creating icons).
And some great news: in the next LaMetric firmware the weather data on LaMetric Weather App will be refreshed once in 1 and half hour.
- Oldest First
- Popular
- Newest First
Sorted by Newest FirstAnimesh Mukherjee
Animesh Mukherjee
Tristan
Hi. Would anybody be kind enough to provide step by step instructions on how to make this work?
Stefan Rydberg
It was the exclude that i have not seen....
Hourly works now, daily give wrong day.
Kind regards
Stefan
Stefan Rydberg
Great!
Viktor Z
You can use those Logger.log functions to see results. You can uncomment them, run your code and then click "View / Log" menu
Stefan Rydberg
Ok.
Looks like i have to better lat long or something. Thanks.
I have to learn how to see the result i gs also....
Getting there...
Kind regards
Stefan
Stefan Rydberg
This is what i done
function getDarkSkyWeather() {
var result = UrlFetchApp.fetch("https://api.forecast.io/forecast/xxxx/56.03129,14.15242?lang=sv&units=auto&exclude=flags,hourly,daily,alerts");
//Logger.log(result);
var json = JSON.parse(result);
//Logger.log(json.currently);
return json;
}
function degToCompass(num) {
var val = Math.floor((num / 22.5) + 0.5);
var arr = ["N", "NNÖ", "NÖ", "ÖNÖ", "Ö", "ÖSÖ", "SÖ", "SSÖ", "S", "SSV", "SV", "VSV", "W", "VNV", "NV", "NNV"];
return arr[(val % 16)];
}
function convertDarkSkyToLaMetric(darkSkyJson) {
var temp = darkSkyJson.currently.temperature;
var icon = darkSkyJson.currently.icon;
var minutelySummary = darkSkyJson.currently.summary;
var minutelyIcon = darkSkyJson.currently.icon;
var currentlywindSpeed = darkSkyJson.currently.windSpeed + " m/s";
var currentlywindIcon = "a3363";
var currentlywindRikt = darkSkyJson.currently.windBearing;
var vindriktIcon = "a12194";
var currentlyTrycket = darkSkyJson.currently.pressure + " hPa";
var TrycketIcon = "a2272";
var kommande = darkSkyJson.daily.summary;
return {
"frames": [
{
"index": 0,
"text": Math.round(temp) + "°",
"icon": pickIcon(icon)
},
{
"index": 1,
"text": minutelySummary,
"icon": pickIcon(minutelyIcon)
},
{
"index": 2,
"text": currentlywindSpeed,
"icon": currentlywindIcon
},
{
"index": 3,
"text": degToCompass(currentlywindRikt),
"icon": vindriktIcon
},
{
"index": 4,
"text": currentlyTrycket,
"icon": TrycketIcon
},
{
"index": 5,
"text": kommande,
"icon": TrycketIcon
}
]
}
}
function pickIcon(icon) { // clear-day, clear-night, rain, snow, sleet, wind, fog, cloudy, partly-cloudy-day, or partly-cloudy-night
switch (icon) {
case "clear-day": return "a2282";
case "cloudy": return "a2283";
case "rain": return "a2284";
case "sleet": return "a160";
case "partly-cloudy-day": return "a2286";
case "snow": return "a2289";
case "clear-night": return "i2314";
case "wind": return "a2440";
case "fog": return "i2158";
case "partly-cloudy-night": return "i2152";
default: return "i73";
}
}
function executePost() {
var payload = convertDarkSkyToLaMetric(getDarkSkyWeather());
var options = {
"method" : "post",
"payload" : JSON.stringify(payload),
"contentType": "application/json",
"headers" : {
"X-Access-Token" : "xx"
}
};
var result = UrlFetchApp.fetch("xx", options);
Logger.log(result);
}
Viktor Z
Here is response I've got for your coordinates:
For comparison, this is what I've got for a random address in San Francisco:
Stefan Rydberg
Ok, i have to try other locations and so on. I ve got resspnse in my pythonscript on daily.summary but for wrong day. I am trying to get that right also. Can you i fyou have time try to get data from daily.summary for Kristianstad Sweden lat 56.03129 long 14.15242? I would like to get a short forecast for the tomorrow.
kind regards Stefan
Viktor Z
Also, maybe the provider simply have no data for your location. Documentation says:
Viktor Z
Stefan,
No, I am not paying anything and "minutely" info is there in the response. It is spelled "minutely" though, not "minutly". Make sure you are not misspelling it in you code too. And make sure you do not "exclude" it from the request.
Stefan Rydberg
Viktor Z
I am hooked on this :D
But i am stuck a little again. I can only use currently data, but in your gs there in minutly also. That re guest do not work. Do I need paid key for that?
Kind regards
Stefan
Stefan Rydberg
Thanks!
I have got it to work and start to understand the basics.
Stefan
Viktor Z
Just in case, this maybe helpful: http://lametric-documentation.readthedocs.io/en/latest/guides/first-steps/first-lametric-indicator-app.html
-
How to pull data from external site to display?
-
nodejs request "gets acces denied"
-
curl to python for eventghost
-
Push text from Eventghost to LaMetric via python
-
Basic API pull and json parse example....
-
A guide for starting an app?
-
A small wrapper to push your just created JIRA issues to your LaMetric.
-
Simple project to push home consumption data to be shown on a Lametric device
-
Interface to have Slack send messages to a LaMetric Time
-
Very simple module to push frames to LaMetric
See all 149 topics