103
// Remove anything including and after APPID in the given term
103
// Remove just the API key
104
104
function trimAPIKey(data) {
105
var owm = data.indexOf("&APPID=");
106
var twc = data.indexOf("&key=");
105
var owm = data.indexOf("APPID=");
106
var twc = data.indexOf("apiKey=");
108
// Key length is 32 char for both APIs
109
data = data.substr(0, owm);
112
var replace = data.substr(owm+6, keySize);
113
data = data.replace(replace,"")
110
114
} else if (twc > -1) {
111
data = data.substr(0, twc);
115
var replace = data.substr(twc+7, keySize);
116
data = data.replace(replace,"")
459
464
function _buildDataPoint(date, dataObj) {
460
var data = dataObj["Observation"] || dataObj,
465
var partData = dataObj["metric"] || dataObj;
466
var data = dataObj["observation"] || dataObj,
462
timestamp: data.date || data.dateTime,
468
timestamp: data.fcst_valid,
466
tempFeels: data.feelsLike,
467
windSpeed: data.wSpeed
472
tempFeels: partData.feels_like,
473
windSpeed: partData.wspd
470
temp: calcFahrenheit(data.temp),
471
tempFeels: calcFahrenheit(data.feelsLike),
472
windSpeed: convertKphToMph(data.wSpeed)
476
temp: calcFahrenheit(partData.temp),
477
tempFeels: calcFahrenheit(partData.feels_like),
478
windSpeed: convertKphToMph(partData.wspd)
474
480
precipType: (data.precip_type !== undefined) ? data.precip_type : null,
475
481
propPrecip: (data.pop !== undefined) ? data.pop : null,
476
humidity: data.humid,
477
pressure: data.pressure,
479
windDir: data.wDirText,
480
icon: _iconMap[(data.wxIcon||data.icon)],
481
condition: data.text || data.wDesc,
482
humidity: partData.rh,
483
pressure: partData.mslp,
485
windDir: data.wdir_cardinal,
486
icon: _iconMap[data.icon_code],
487
condition: data.phrase_32char,
484
if(_iconMap[data.wxIcon||data.icon] === undefined) {
485
print("ICON MISSING POINT: "+(data.wxIcon||data.icon)+" "+result.condition)
491
if (_iconMap[data.icon_code] === undefined) {
492
print("ICON MISSING POINT: " + data.icon_code + " " + result.condition)
490
498
function _buildDayFormat(date, data, now) {
491
var partData = (now > data.validDate || data.day === undefined) ? data.night : data.day,
499
var partData = (now > data.fcst_valid || data.day === undefined) ? data.night : data.day,
494
timestamp: data.validDate,
502
timestamp: data.fcst_valid,
496
tempMin: data.minTemp,
497
tempMax: data.maxTemp,
498
windSpeed: partData.wSpeed
504
tempMin: data.min_temp,
505
tempMax: data.max_temp !== null ? data.max_temp : undefined,
506
windSpeed: partData.wspd
501
tempMin: calcFahrenheit(data.minTemp),
502
tempMax: calcFahrenheit(data.maxTemp !== undefined ? data.maxTemp : data.minTemp),
503
windSpeed: convertKphToMph(partData.wSpeed)
509
tempMin: calcFahrenheit(data.min_temp),
510
tempMax: data.max_temp !== null && data.max_temp !== undefined ? calcFahrenheit(data.max_temp) : undefined,
511
windSpeed: convertKphToMph(partData.wspd)
505
513
precipType: partData.precip_type,
506
514
propPrecip: partData.pop,
508
humidity: partData.humid,
509
icon: _iconMap[partData.icon],
510
condition: partData.phrase,
511
windDeg: partData.wDir,
512
windDir: partData.wDirText,
516
humidity: partData.rh,
517
icon: _iconMap[partData.icon_code],
518
condition: partData.phrase_32char,
519
windDeg: partData.wdir,
520
windDir: partData.wdir_cardinal,
521
uv: partData.uv_index,
516
if(_iconMap[partData.icon] === undefined) {
517
print("ICON MISSING DAY: "+partData.icon+" "+result.condition)
525
if (_iconMap[partData.icon_code] === undefined) {
526
print("ICON MISSING DAY: " + partData.icon_code + " " + result.condition)
527
537
nowMs = parseInt(now/1000),
528
538
localNow = getLocationTime(now+offset),
530
"location": combinedData[0]["Location"],
531
"daily": combinedData[0]["DailyForecasts"],
532
"forecast": combinedData[0]["HourlyForecasts"],
533
"current": combinedData[0]["StandardObservation"],
534
"sunRiseSet": combinedData[0]["SunRiseSet"],
540
"location": combinedData["current"]["metadata"],
541
"daily": combinedData["daily"]["forecasts"],
542
"forecast": combinedData["forecast"]["forecasts"],
543
"current": combinedData["current"]["observation"],
536
545
print("["+location.name+"] "+JSON.stringify(localNow));
537
546
// add openweathermap id for faster responses
538
547
if(location.services && !location.services[_serviceName] && data["location"].key) {
539
548
location.services[_serviceName] = data["location"].key
541
550
// only 5 days of forecast for TWC
542
for(var x=0;x<5;x++) {
551
for(var x=0; x<5; x++) {
543
552
var dayData = data["daily"][x],
544
date = getLocationTime(((dayData.validDate*1000)-1000)+offset); // minus 1 sec to handle +/-12 TZ
545
var sunRiseSet = data["sunRiseSet"][x];
553
date = getLocationTime(((dayData.fcst_valid * 1000) - 1000) + offset); // minus 1 sec to handle +/-12 TZ
555
// Sun{rise,set} is in ISOString format so use getTime() to convert
556
var sunrise = new Date(dayData.sunrise).getTime(),
557
sunset = new Date(dayData.sunset).getTime();
546
558
day = date.year+"-"+date.month+"-"+date.date;
548
if(localNow.year+"-"+localNow.month+"-"+localNow.date > day) {
561
if (localNow.year + "-" + localNow.month + "-" + localNow.date > day) {
549
562
// skip "yesterday"
552
566
todayDate = date;
554
569
tmpResult[day] = _buildDayFormat(date, dayData, nowMs);
555
571
var timezoneOffset = new Date().getTimezoneOffset();
556
572
var timesOffset = (location.timezone && location.timezone.dstOffset !== undefined) ? (location.timezone.dstOffset*60 + timezoneOffset)*60*1000: 0
557
var sunrise = new Date(sunRiseSet.rise*1000 + timesOffset);
558
var sunset = new Date(sunRiseSet.set*1000 + timesOffset);
574
sunrise = new Date(sunrise + timesOffset);
575
sunset = new Date(sunset + timesOffset);
559
577
var options = { timeZone: location.timezone.timeZoneId, timeZoneName: 'long' };
560
578
tmpResult[day].sunrise = sunrise.toLocaleTimeString(Qt.locale().name, options);
561
579
tmpResult[day].sunset = sunset.toLocaleTimeString(Qt.locale().name, options);
594
function _getUrl(params) {
597
key: params.twc_api_key,
598
units: (params.units === "metric") ? "m" : "e",
599
locale: Qt.locale().name,
603
"mobileaggregation": "mobile/mobagg/",
613
function _getUrls(params) {
615
units: (params.units === "metric") ? "m" : "e",
616
language: Qt.locale().name.replace("_","-"),
617
apiKey: params.twc_api_key,
620
"geocode": "v1/geocode/",
628
// FIXME: only use coords for now and not location codes (UKXX0085)
629
if (params.location.coord) {
631
lat: params.location.coord.lat,
632
lng: params.location.coord.lon
605
if(params.location.services && params.location.services[_serviceName]) {
606
serviceId = encodeURIComponent(params.location.services[_serviceName]);
607
url = _baseUrl+commands["mobileaggregation"]+serviceId+".js?"+parameterize(baseParams);
608
} else if (params.location.coord) {
609
var coord = {lat: params.location.coord.lat, lng: params.location.coord.lon};
610
url = _baseUrl+commands["mobileaggregation"]+"get.js?"+parameterize(baseParams)+"&"+
635
urls.current = _baseUrl + commands["geocode"] +
636
coord.lat + "/" + coord.lng +
637
"/observations/current.json?" +
638
parameterize(baseParams);
639
urls.daily = _baseUrl + commands["geocode"] +
640
coord.lat + "/" + coord.lng +
641
"/forecast/daily/5day.json?" +
642
parameterize(baseParams);
643
urls.hourly = _baseUrl + commands["geocode"] +
644
coord.lat + "/" + coord.lng +
645
"/forecast/hourly/48hour.json?" +
646
parameterize(baseParams);
617
653
getData: function(params, apiCaller, onSuccess, onError) {
618
var url = _getUrl(params),
654
var urls = _getUrls(params),
620
all: { type: "all", url: url}
623
location: params.location,
624
db: (params.db) ? params.db : null,
625
format: RESPONSE_DATA_VERSION
627
addDataToResponse = (function(request, data) {
629
response["data"] = formatResult(data, params.location);
670
location: params.location,
671
db: (params.db) ? params.db : null,
672
format: RESPONSE_DATA_VERSION
675
addDataToResponse = (function(request, data) {
677
respData[request.type] = data;
679
if (respData["current"] !== undefined &&
680
respData["forecast"] !== undefined &&
681
respData["daily"] !== undefined) {
683
response["data"] = formatResult(respData, params.location);
630
684
onSuccess(response);
632
onErrorHandler = (function(err) {
635
apiCaller(handlerMap.all, addDataToResponse, onErrorHandler);
687
onErrorHandler = (function(err) {
690
retryHandler = (function(err) {
691
console.log("retry of " + trimAPIKey(err.request.url));
692
var retryFunc = handlerMap[err.request.type];
694
apiCaller(retryFunc, addDataToResponse, onErrorHandler);
697
apiCaller(handlerMap.current, addDataToResponse, retryHandler);
698
apiCaller(handlerMap.forecast, addDataToResponse, retryHandler);
699
apiCaller(handlerMap.daily, addDataToResponse, retryHandler);