#include #include #include /* * Weather forecast via forecast.io. Get a key from * https://developer.forecast.io/register and stick it in * $home/lib/darksky * Relies on 9son: https://bitbucket.org/bedo/9son */ void parse(void); char *wday[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", }; char *mon[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", }; void main(int argc, char *argv[]) { char *apibase, *options, resp[32*1024], *mtpt, buf[128], key[64]; int i, j, n, index, ai, ci, di, hi, mi, datai; int aflag, currently, daily, hourly, minutely, summ, sumh, sumd; int conn, ctlfd, fd; char *keyfile, *herefile; float here[2], precip; Tm *tm; Jparser p; apibase = "https://api.forecast.io/forecast"; aflag = currently = daily = hourly = minutely = summ = sumh = sumd = 0; herefile = "/lib/sky/here"; keyfile = smprint("%s/lib/darksky", getenv("home")); // options = "exclude=minutely,hourly&units=auto"; options = "units=auto"; mtpt = "/mnt/web"; ARGBEGIN { case 'a': aflag = 1; break; case 'c': currently = 1; break; case 'm': minutely = 1; break; case 'h': hourly = 1; break; case 'd': daily = 1; break; case 'M': minutely = 1; summ = 1; break; case 'H': hourly = 1; sumh = 1; break; case 'D': daily = 1; sumd = 1; break; }ARGEND if (!aflag && !currently && !daily && !hourly && !minutely) currently = minutely = hourly = daily = sumh = sumd = 1; if((fd = open(keyfile, OREAD)) <= 0) sysfatal("couldn't get key: %r"); if((n = read(fd, key, 32)) <= 0) sysfatal("couldn't get key: %r"); if(n<32) sysfatal("bad key, len %d", n); close(fd); if((fd = open(herefile, OREAD)) <= 0) sysfatal("couldn't find our location: %r"); if(read(fd, buf, 128) <= 0) sysfatal("couldn't find our location: %r"); close(fd); here[0]=atof(strtok(buf, " ")); here[1]=atof(strtok(nil, " ")); snprint(buf, sizeof buf, "%s/clone", mtpt); if((ctlfd = open(buf, ORDWR)) < 0) sysfatal("couldn't open %s: %r", buf); if((n = read(ctlfd, buf, sizeof buf-1)) < 0) sysfatal("reading clone: %r"); if(n == 0) sysfatal("short read on clone"); buf[n] = '\0'; conn = atoi(buf); if(fprint(ctlfd, "url %s/%s/%2.4f,-%2.4f?%s", apibase, key, here[0], here[1], options) <= 0) sysfatal("get ctl write: %r"); snprint(buf, sizeof buf, "%s/%d/body", mtpt, conn); if((fd = open(buf, OREAD)) < 0) sysfatal("open %s: %r", buf); readn(fd, resp, sizeof resp); Jinit(&p); if(Jtokenise(&p, resp) < 0) sysfatal("JSON tokenization error: %r"); if(p.tokens[0].type != JObj) sysfatal("Darksky didn't return an object."); ai = Jfind(&p, 0, "alerts"); if(ai>1) { print("ALERT:\n"); for(i=0, j=ai+1 ; i < p.tokens[ai].nsub ; i++) { index = Jfind(&p, j, "title"); print(" %s\n",Jtokstr(&p.tokens[index])); index = Jfind(&p, j, "expires"); tm = localtime(atol(Jtokstr(&p.tokens[index]))); print(" Expires %s, %s %d %d:%02.2d.\n", wday[tm->wday], mon[tm->mon], tm->mday, tm->hour, tm->min); index = Jfind(&p, j, "uri"); print(" For more information, see %s\n", Jtokstr(&p.tokens[index])); j=Jnext(&p, j); } } else if(aflag) print("No alerts.\n"); if(currently) { ci = Jfind(&p, 0, "currently"); print("Conditions as of "); index = Jfind(&p, ci, "time"); print("%s", ctime(atol(Jtokstr(&p.tokens[index])))); index = Jfind(&p, ci, "summary"); print(" %s, ", Jtokstr(&p.tokens[index])); index = Jfind(&p, ci, "temperature"); print("%s°\n", Jtokstr(&p.tokens[index])); } if (minutely) { mi = Jfind(&p, 0, "minutely"); // if(!summ) // print("Forecast for the next hour:\n"); index = Jfind(&p, mi, "summary"); print(" %s\n", Jtokstr(&p.tokens[index])); if(!summ) { print(" "); datai = Jfind(&p, mi, "data"); for(i=0, j=datai+1 ; i < p.tokens[datai].nsub ; i++) { index = Jfind(&p, j, "precipProbability"); precip = atof(Jtokstr(&p.tokens[index]))*100; switch((int)precip/8) { case 0: print(" "); break; case 1: print("▁"); break; case 2: print("▂"); break; case 3: print("▃"); break; case 4: print("▄"); break; case 5: print("▅"); break; case 6: print("▆"); break; case 7: print("▇"); break; case 8: print("█"); break; } j=Jnext(&p, j); } print("\n"); } } if (hourly) { hi = Jfind(&p, 0, "hourly"); // if(!sumh) // print("Hourly forecast:\n"); index = Jfind(&p, hi, "summary"); print(" %s\n", Jtokstr(&p.tokens[index])); if(!sumh) { datai = Jfind(&p, hi, "data"); for(i=0, j=datai+1 ; i < p.tokens[datai].nsub ; i++) { index = Jfind(&p, j, "time"); tm=localtime(atol(Jtokstr(&p.tokens[index]))); print("→ %d:%02.2d:\n", tm->hour, tm->min); index = Jfind(&p, j, "temperature"); print(" %0s°, ", Jtokstr(&p.tokens[index])); index = Jfind(&p, j, "summary"); print(" %s\n", Jtokstr(&p.tokens[index])); index = Jfind(&p, j, "precipProbability"); precip = atof(Jtokstr(&p.tokens[index]))*100; if(precip != 0) { print(" %2.0f%% chance of ", precip); index = Jfind(&p, j, "precipType"); print("%s.\n", Jtokstr(&p.tokens[index])); } j=Jnext(&p, j); } } } if (daily) { di = Jfind(&p, 0, "daily"); // if(!sumd) // print("Extended forecast:\n"); index = Jfind(&p, di, "summary"); print(" %s\n", Jtokstr(&p.tokens[index])); if(!sumd) { datai = Jfind(&p, di, "data"); for(i=0, j=datai+1 ; i < p.tokens[datai].nsub ; i++) { index = Jfind(&p, j, "time"); tm=localtime(atol(Jtokstr(&p.tokens[index]))); print("→ %s, %s %d, %d:\n", wday[tm->wday], mon[tm->mon], tm->mday, tm->year+1900); index = Jfind(&p, j, "summary"); print(" %s\n", Jtokstr(&p.tokens[index])); index = Jfind(&p, j, "temperatureMax"); print(" High: %s°", Jtokstr(&p.tokens[index])); index = Jfind(&p, j, "temperatureMin"); print(" Low: %s°\n", Jtokstr(&p.tokens[index])); index = Jfind(&p, j, "precipProbability"); precip = atof(Jtokstr(&p.tokens[index]))*100; if(precip != 0) { print(" %2.0f%% chance of ", precip); index = Jfind(&p, j, "precipType"); print("%s.\n", Jtokstr(&p.tokens[index])); } j=Jnext(&p, j); } } } exits(0); }