Merge lp:~martin-borho/ubuntu-weather-app/refactored-weather-api into lp:ubuntu-weather-app/obsolete.trunk

Proposed by Martin Borho
Status: Merged
Approved by: Raúl Yeguas
Approved revision: 81
Merged at revision: 81
Proposed branch: lp:~martin-borho/ubuntu-weather-app/refactored-weather-api
Merge into: lp:ubuntu-weather-app/obsolete.trunk
Diff against target: 527 lines (+143/-204)
6 files modified
components/CurrentWeather.qml (+9/-6)
components/LocationTab.qml (+7/-6)
components/WeatherApi.js (+115/-183)
tests/autopilot/ubuntu_weather_app/tests/test_mainview.py (+2/-2)
tests/autopilot/ubuntu_weather_app/tests/test_settings.py (+4/-4)
tests/autopilot/ubuntu_weather_app/tests/weatherdata.py (+6/-3)
To merge this branch: bzr merge lp:~martin-borho/ubuntu-weather-app/refactored-weather-api
Reviewer Review Type Date Requested Status
Raúl Yeguas Approve
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve
Review via email: mp+177265@code.launchpad.net

Commit message

changed internal data format, refactored weather api.

Description of the change

* changed internal data format
* refactored weather api, data provider can now be easier added/replaced
* changed displayed data in location tab, removed doubled temperature
* updated test data with new data format

To post a comment you must log in.
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Raúl Yeguas (neokore) wrote :

Good work, Martin!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'components/CurrentWeather.qml'
2--- components/CurrentWeather.qml 2013-07-20 16:52:37 +0000
3+++ components/CurrentWeather.qml 2013-07-27 16:53:26 +0000
4@@ -12,6 +12,7 @@
5 property int currentTemp
6 property int minTemp
7 property int maxTemp
8+ property bool showMaxTemp
9 property string scale: (mainView.settings["units"] === "imperial") ? "F" : "C"
10
11 width: parent.width
12@@ -51,14 +52,15 @@
13 id: column1
14 width: units.gu(5)
15 height: units.gu(5)
16- anchors.rightMargin: 0
17+ anchors.rightMargin: units.gu(2)
18 anchors.verticalCenter: parent.verticalCenter
19 anchors.right: tempCurrent.left
20+ visible: showMaxTemp
21
22 Label {
23 text: i18n.tr("Max.")
24 anchors.horizontalCenter: parent.horizontalCenter
25- font.pixelSize: FontUtils.sizeToPixels("x-small")
26+ font.pixelSize: FontUtils.sizeToPixels("small")
27 horizontalAlignment: Text.AlignHCenter
28 }
29
30@@ -66,7 +68,7 @@
31 id: tempMax
32 text: maxTemp+"°"+currentWeather.scale
33 anchors.horizontalCenter: parent.horizontalCenter
34- font.pixelSize: FontUtils.sizeToPixels("medium")
35+ font.pixelSize: FontUtils.sizeToPixels("large")
36 horizontalAlignment: Text.AlignHCenter
37 color: Theme.palette.normal.baseText
38 }
39@@ -83,6 +85,7 @@
40 font.family: "Ubuntu"
41 verticalAlignment: Text.AlignVCenter
42 anchors.horizontalCenter: parent.horizontalCenter
43+ anchors.horizontalCenterOffset: (showMaxTemp) ? 0 : -units.gu(4)
44 anchors.verticalCenter: parent.verticalCenter
45 font.pointSize: 52
46 horizontalAlignment: Text.AlignHCenter
47@@ -93,7 +96,7 @@
48 id: column2
49 width: units.gu(5)
50 height: units.gu(5)
51- anchors.leftMargin: 0
52+ anchors.leftMargin: (showMaxTemp) ? units.gu(2) : units.gu(4)
53 anchors.verticalCenter: parent.verticalCenter
54 anchors.left: tempCurrent.right
55
56@@ -101,7 +104,7 @@
57 text: i18n.tr("Min.")
58 horizontalAlignment: Text.AlignHCenter
59 anchors.horizontalCenter: parent.horizontalCenter
60- font.pixelSize: FontUtils.sizeToPixels("x-small")
61+ font.pixelSize: FontUtils.sizeToPixels("small")
62 color: Theme.palette.normal.baseText
63 }
64
65@@ -110,7 +113,7 @@
66 text: minTemp+"°"+currentWeather.scale
67 horizontalAlignment: Text.AlignHCenter
68 anchors.horizontalCenter: parent.horizontalCenter
69- font.pixelSize: FontUtils.sizeToPixels("medium")
70+ font.pixelSize: FontUtils.sizeToPixels("large")
71 color: Theme.palette.normal.baseText
72 }
73 }
74
75=== modified file 'components/LocationTab.qml'
76--- components/LocationTab.qml 2013-07-22 21:41:32 +0000
77+++ components/LocationTab.qml 2013-07-27 16:53:26 +0000
78@@ -41,9 +41,8 @@
79
80 Component.onCompleted: {
81 var locData = mainView.locationsList[locationIndex],
82- currentData = locData.current.results,
83 units = (mainView.settings.units === 'imperial') ? 'imperial' : 'metric',
84- dailyForecasts = locData.daily.results,
85+ dailyForecasts = locData.data,
86 dailyLength = dailyForecasts.length,
87 todayForeCast = dailyForecasts[0];
88
89@@ -55,9 +54,11 @@
90 dayForecastModel.append({
91 dateRel: "",//Tomorrow",
92 date: formatTimestamp(dailyForecasts[x].timestamp, 'dddd, dd MMMM yyyy'),
93- temp: dailyForecasts[x][units].max,
94- tempMin: dailyForecasts[x][units].min,
95- tempMax: dailyForecasts[x][units].max,
96+ temp: (dailyForecasts[x]["current"] === undefined) ? dailyForecasts[x][units].tempMax :
97+ dailyForecasts[x]["current"][units].temp,
98+ tempMin: dailyForecasts[x][units].tempMin,
99+ tempMax: (dailyForecasts[x]["current"] !== undefined) ? dailyForecasts[x][units].tempMax :
100+ null,
101 cond: dailyForecasts[x].condition.id,
102 condIcon: dailyForecasts[x].condition.icon
103 });
104@@ -84,7 +85,6 @@
105 snapMode: ListView.SnapOneItem
106 verticalLayoutDirection: ListView.TopToBottom
107 flickableDirection: Flickable.VerticalFlick
108-
109 clip: true
110
111 delegate: Item {
112@@ -112,6 +112,7 @@
113 icon: condIcon
114 condition: cond
115 anchors.top: dateComponent.bottom
116+ showMaxTemp: (index === 0)
117 }
118 }
119 }
120
121=== modified file 'components/WeatherApi.js'
122--- components/WeatherApi.js 2013-07-10 19:53:11 +0000
123+++ components/WeatherApi.js 2013-07-27 16:53:26 +0000
124@@ -3,7 +3,7 @@
125 * Version of the response data format.
126 * Increase this number to force a refresh.
127 */
128-var RESPONSE_DATA_VERSION = 1;
129+var RESPONSE_DATA_VERSION = 20130727;
130
131 /**
132 * Helper functions
133@@ -22,10 +22,7 @@
134 var _baseUrl = "http://api.openweathermap.org/data/2.5/";
135 //
136 function _buildSearchResult(request, data) {
137- var searchResult = {
138- locations: [],
139- request: request
140- }
141+ var searchResult = { locations: [], request: request };
142 if(data.cod === "200" && data.list) {
143 data.list.forEach(function(r) {
144 searchResult.locations.push({
145@@ -44,17 +41,9 @@
146 // TODO add snow or rain data
147 var result = {
148 timestamp: data.dt,
149- date: (data.date !== undefined) ? data.date : ((data.dt_txt !== undefined) ? data.dt_txt: null),
150- metric: {
151- temp:data.main.temp,
152- temp_min: data.main.temp_min,
153- temp_max: data.main.temp_max
154- },
155- imperial: {
156- temp: calcFahrenheit(data.main.temp),
157- temp_min: calcFahrenheit(data.main.temp_min),
158- temp_max: calcFahrenheit(data.main.temp_max)
159- },
160+ date: Qt.formatDateTime(new Date(data.dt*1000), "yyyy-MM-dd hh:mm"),
161+ metric: { temp:data.main.temp },
162+ imperial: { temp: calcFahrenheit(data.main.temp) },
163 humidity: data.main.humidity,
164 pressure: data.main.pressure,
165 wind_speed_kmh: data.wind.speed,
166@@ -65,113 +54,113 @@
167 if(data.id !== undefined) {
168 result["service"] = "openweathermap";
169 result["service_id"] = data.id;
170-
171- }
172- return result;
173- }
174- //
175- function _buildCurrentCondition(request, data) {
176- var currentResult = {
177- results: _buildDataPoint(data),
178- request: request
179- }
180- return currentResult;
181- }
182- //
183- function _buildForecast(request, data) {
184- var forecastResult = {
185- results: [],
186- request: request
187- }
188- data.list.forEach(function(f) {
189- forecastResult.results.push(_buildDataPoint(f));
190- });
191- return forecastResult;
192- }
193- //
194- function _buildDailyForecast(request, data) {
195- var forecastResult = {
196- results: [],
197- request: request
198- }
199- data.list.forEach(function(f) {
200- // TODO date_txt
201- forecastResult.results.push({
202- timestamp: f.dt,
203- metric: {
204- day: f.temp.day,
205- min: f.temp.min,
206- max: f.temp.max,
207- night: f.temp.night,
208- eve: f.temp.eve,
209- morn: f.temp.morn
210- },
211- imperial: {
212- day: calcFahrenheit(f.temp.day),
213- min: calcFahrenheit(f.temp.min),
214- max: calcFahrenheit(f.temp.max),
215- night: calcFahrenheit(f.temp.night),
216- eve: calcFahrenheit(f.temp.eve),
217- morn: calcFahrenheit(f.temp.morn)
218- },
219- pressure: f.pressure,
220- humidity: f.humidity,
221- condition: f.weather[0],
222- wind_speed: f.speed,
223- wind_deg: f.deg
224- });
225- });
226- return forecastResult;
227+ }
228+ return result;
229+ }
230+ //
231+ function _buildDayFormat(date, data) {
232+ var result = {
233+ date: date,
234+ timestamp: data.dt,
235+ metric: {
236+ tempMin: data.temp.min,
237+ tempMax: data.temp.max
238+ },
239+ imperial: {
240+ tempMin: calcFahrenheit(data.temp.min),
241+ tempMax: calcFahrenheit(data.temp.max)
242+ },
243+ pressure: data.pressure,
244+ humidity: data.humidity,
245+ condition: data.weather[0],
246+ wind_speed: data.speed,
247+ wind_deg: data.deg,
248+ hourly: []
249+ }
250+ return result;
251+ }
252+ //
253+ function formatResult(data) {
254+ var tmpResult = {},
255+ result = [],
256+ day=null,
257+ today = Qt.formatDateTime(new Date(), "yyyy-MM-dd");
258+ data["daily"]["list"].forEach(function(dayData) {
259+ day = Qt.formatDateTime(new Date(dayData.dt*1000), "yyyy-MM-dd")
260+ tmpResult[day] = _buildDayFormat(day, dayData);
261+ })
262+ tmpResult[today]["current"] = _buildDataPoint(data["current"]);
263+ if(data["forecast"] !== undefined) {
264+ data["forecast"]["list"].forEach(function(hourData) {
265+ var date = new Date(hourData.dt*1000)
266+ day = Qt.formatDateTime(date, "yyyy-MM-dd");
267+ tmpResult[day]["hourly"].push(_buildDataPoint(hourData));
268+ })
269+ }
270+ for(var d in tmpResult) {
271+ result.push(tmpResult[d]);
272+ }
273+ return result;
274 }
275 //
276 return {
277 //
278- getSearchByNameRequest: function(params) {
279- var request = {
280- type: "search",
281- url: _baseUrl+"find?q="+encodeURIComponent(params.name)+"&units="+params.units,
282- formatter: _buildSearchResult
283- }
284- return request;
285- },
286- //
287- getSearchByPointRequest: function(params) {
288- var url = _baseUrl+"find?lat="+encodeURIComponent(params.coords.lat)
289- +"&lon="+encodeURIComponent(params.coords.lon)+"&units="+params.units,
290- request = {
291- type: "search",
292- url: url,
293- formatter: _buildSearchResult
294+ search: function(mode, params, apiCaller, onSuccess, onError) {
295+ var request,
296+ retryHandler = (function(err) {
297+ console.log("search retry of "+err.request.url);
298+ apiCaller(request, searchResponseHandler, onError);
299+ }),
300+ searchResponseHandler = function(request, data) {
301+ onSuccess(_buildSearchResult(request, data));
302 };
303- return request;
304- },
305- //
306- getCurrentConditionRequest: function(params) {
307- var request = {
308- type: "current",
309- url: _baseUrl + "weather?id="+params.location.service_id+"&units="+params.units,
310- formatter: _buildCurrentCondition
311- }
312- return request;
313- },
314- //
315- getForecastRequest: function(params) {
316- var request = {
317- type: "forecast",
318- url: _baseUrl + "forecast?id="+params.location.service_id+"&units="+params.units,
319- formatter: _buildForecast
320- }
321- return request;
322- },
323- //
324- getDailyForecastRequest: function(params) {
325- var request = {
326- type: "daily",
327- url: _baseUrl + "forecast/daily?id="+params.location.service_id
328- +"&cnt=10&units="+params.units,
329- formatter: _buildDailyForecast
330- }
331- return request;
332+ if(mode === "point") {
333+ request = { type: "search",
334+ url: _baseUrl+"find?lat="+encodeURIComponent(params.coords.lat)
335+ +"&lon="+encodeURIComponent(params.coords.lon)+"&units="+params.units}
336+ } else {
337+ request = { type: "search",
338+ url: _baseUrl+"find?q="+encodeURIComponent(params.name)+"&units="+params.units}
339+ }
340+ apiCaller(request, searchResponseHandler, retryHandler);
341+ },
342+ //
343+ getData: function(params, apiCaller, onSuccess, onError) {
344+ var handlerMap = {
345+ current: { type: "current",
346+ url: _baseUrl + "weather?id="+params.location.service_id+"&units="+params.units},
347+ daily: { type: "daily",
348+ url: _baseUrl + "forecast/daily?id="+params.location.service_id
349+ +"&cnt=10&units="+params.units},
350+ forecast: { type: "forecast",
351+ url: _baseUrl + "forecast?id="+params.location.service_id+"&units="+params.units}},
352+ response = {
353+ location: params.location,
354+ db: (params.db) ? params.db : null,
355+ format: RESPONSE_DATA_VERSION
356+ },
357+ respData = {},
358+ addDataToResponse = (function(request, data) {
359+ var formattedResult;
360+ respData[request.type] = data;
361+ if(respData["current"] !== undefined
362+ //&& respData["forecast"] !== undefined
363+ && respData["daily"] !== undefined) {
364+ response["data"] = formatResult(respData)
365+ onSuccess(response);
366+ }
367+ }),
368+ onErrorHandler = (function(err) {
369+ onError(err);
370+ }),
371+ retryHandler = (function(err) {
372+ console.log("retry of "+err.request.url);
373+ var retryFunc = handlerMap[err.request.type];
374+ apiCaller(retryFunc, addDataToResponse, onErrorHandler);
375+ })
376+ apiCaller(handlerMap.current, addDataToResponse, retryHandler);
377+ //apiCaller(handlerMap.forecast, addDataToResponse, retryHandler);
378+ apiCaller(handlerMap.daily, addDataToResponse, retryHandler);
379 }
380 }
381
382@@ -200,8 +189,7 @@
383 //console.log(xmlHttp.responseText);
384 var json = JSON.parse(xmlHttp.responseText);
385 if(xmlHttp.status === 200) {
386- var result = request.formatter(request,json);
387- onSuccess(result);
388+ onSuccess(request,json);
389 } else {
390 onError({
391 msg: "wrong response http code, got "+xmlHttp.status,
392@@ -218,72 +206,16 @@
393 }
394 //
395 return {
396- getForecast: function(params, onSuccess, onError) {
397- var request = _getService().getForecastRequest(params);
398- _sendRequest(request, onSuccess, onError);
399- },
400- //
401- getDailyForecast: function(params, onSuccess, onError) {
402- var request = _getService().getDailyForecastRequest(params);
403- _sendRequest(request, onSuccess, onError);
404- },
405- //
406- getCurrentCondition: function(params, onSuccess, onError) {
407- var request = _getService().getCurrentConditionRequest(params);
408- _sendRequest(request, onSuccess, onError);
409- },
410- //
411- searchLocationByName: function(params, onSuccess, onError) {
412- var request = _getService().getSearchByNameRequest(params);
413- _sendRequest(request, onSuccess, onError);
414- },
415- //
416- searchLocationByPoint: function(params, onSuccess, onError) {
417- var request = _getService().getSearchByPointRequest(params);
418- _sendRequest(request, onSuccess, onError);
419- },
420- //
421- search: function(mode, params, onSuccess, onError) {
422- var searchFunc = (mode === "point") ? this.searchLocationByPoint: this.searchLocationByName,
423- retryHandler = (function(err) {
424- console.log("search retry of "+err.request.url);
425- searchFunc(params, onSuccess, onError);
426- });
427- searchFunc(params, onSuccess, retryHandler);
428+ //
429+ search: function(mode, params, onSuccess, onError) {
430+ var service = _getService();
431+ service.search(mode, params, _sendRequest, onSuccess, onError);
432 },
433 //
434 getLocationData: function(params, onSuccess, onError) {
435- var retryMap = {
436- current:this.getCurrentCondition,
437- daily:this.getDailyForecast,
438- forecast:this.getForecast
439- },
440- response = {
441- location: params.location,
442- db: (params.db) ? params.db : null,
443- format: RESPONSE_DATA_VERSION
444- },
445- addDataToResponse = (function(data) {
446- response[data.request.type] = data;
447- if(response["current"] !== undefined
448- //&& response["forecast"] !== undefined
449- && response["daily"] !== undefined) {
450- onSuccess(response);
451- }
452- }),
453- onErrorHandler = (function(err) {
454- onError(err);
455- }),
456- retryHandler = (function(err) {
457- console.log("retry of "+err.request.url);
458- var retryFunc = retryMap[err.request.type];
459- retryFunc(params, addDataToResponse, onErrorHandler);
460- })
461-
462- this.getCurrentCondition(params, addDataToResponse, retryHandler);
463- //this.getForecast(params, addDataToResponse, retryHandler);
464- this.getDailyForecast(params, addDataToResponse, retryHandler);
465- }
466+ var service = _getService();
467+ service.getData(params, _sendRequest, onSuccess, onError);
468+ },
469 }
470 })({
471 "openweathermap": OpenWeatherMapApi
472
473=== modified file 'tests/autopilot/ubuntu_weather_app/tests/test_mainview.py'
474--- tests/autopilot/ubuntu_weather_app/tests/test_mainview.py 2013-07-03 19:41:03 +0000
475+++ tests/autopilot/ubuntu_weather_app/tests/test_mainview.py 2013-07-27 16:53:26 +0000
476@@ -52,7 +52,7 @@
477 # get the dates from the test data
478 curr_dates = self.main_window.get_objects('Label','DayDateLabel')
479 tab1_curr_date = curr_dates[0].text
480- tab2_curr_date = curr_dates[1].text
481+ tab2_curr_date = curr_dates[2].text
482
483 # refresh and wait till loading has finished
484 self.main_window.click_toolbar_button("RefreshButton")
485@@ -62,4 +62,4 @@
486 # get the data from the refreshed tabs, have to be new
487 refreshed_dates = self.main_window.get_objects('Label','DayDateLabel')
488 self.assertNotEqual(tab1_curr_date, refreshed_dates[0].text)
489- self.assertNotEqual(tab2_curr_date, refreshed_dates[1].text)
490+ self.assertNotEqual(tab2_curr_date, refreshed_dates[2].text)
491
492=== modified file 'tests/autopilot/ubuntu_weather_app/tests/test_settings.py'
493--- tests/autopilot/ubuntu_weather_app/tests/test_settings.py 2013-07-20 11:39:51 +0000
494+++ tests/autopilot/ubuntu_weather_app/tests/test_settings.py 2013-07-27 16:53:26 +0000
495@@ -39,11 +39,11 @@
496 """Checks selected units by values from the first location tab"""
497 current_temps = self.main_window.get_objects('QQuickText', 'CurrentTempText')
498 if units == "imperial":
499- self.assertThat(current_temps[0].text, Eventually(Equals(u'69°F')))
500- self.assertThat(current_temps[1].text, Eventually(Equals(u'78°F')))
501+ self.assertThat(current_temps[0].text, Eventually(Equals(u'76°F')))
502+ self.assertThat(current_temps[2].text, Eventually(Equals(u'78°F')))
503 else:
504- self.assertThat(current_temps[0].text, Eventually(Equals(u'21°C')))
505- self.assertThat(current_temps[1].text, Eventually(Equals(u'26°C')))
506+ self.assertThat(current_temps[0].text, Eventually(Equals(u'25°C')))
507+ self.assertThat(current_temps[2].text, Eventually(Equals(u'25°C')))
508
509 def test_switch_scale(self):
510 """Tests switching the scale in the settings"""
511
512=== modified file 'tests/autopilot/ubuntu_weather_app/tests/weatherdata.py'
513--- tests/autopilot/ubuntu_weather_app/tests/weatherdata.py 2013-06-18 16:13:13 +0000
514+++ tests/autopilot/ubuntu_weather_app/tests/weatherdata.py 2013-07-27 16:53:26 +0000
515@@ -5,6 +5,9 @@
516 # under the terms of the GNU General Public License version 3, as published
517 # by the Free Software Foundation.
518 locations_data = []
519-locations_data.append( """{"daily":{"request":{"type":"daily","url":"http://api.openweathermap.org/data/2.5/forecast/daily?id=2643743&cnt=10&units=metric"},"results":[{"timestamp":1371556800,"pressure":1018.07,"metric":{"eve":18.45,"morn":20.61,"night":12.92,"max":20.61,"day":20.61,"min":12.92},"wind_speed":1.77,"condition":{"icon":"10d","description":"light rain","id":500,"main":"Rain"},"wind_deg":99,"humidity":77,"imperial":{"eve":65.21000000000001,"morn":69.098,"night":55.256,"max":69.098,"day":69.098,"min":55.256}},{"timestamp":1371643200,"pressure":1018.59,"metric":{"eve":19.63,"morn":14.05,"night":15.99,"max":20.92,"day":18.54,"min":14.05},"wind_speed":1.63,"condition":{"icon":"10d","description":"moderate rain","id":501,"main":"Rain"},"wind_deg":31,"humidity":97,"imperial":{"eve":67.334,"morn":57.290000000000006,"night":60.782,"max":69.656,"day":65.372,"min":57.290000000000006}},{"timestamp":1371729600,"pressure":1016.49,"metric":{"eve":18.31,"morn":16.07,"night":14.48,"max":19.64,"day":16.82,"min":14.48},"wind_speed":1.76,"condition":{"icon":"10d","description":"light rain","id":500,"main":"Rain"},"wind_deg":211,"humidity":92,"imperial":{"eve":64.958,"morn":60.926,"night":58.064,"max":67.352,"day":62.275999999999996,"min":58.064}},{"timestamp":1371816000,"pressure":1015.82,"metric":{"eve":18.09,"morn":13.73,"night":14.89,"max":18.65,"day":17.55,"min":13.73},"wind_speed":3.27,"condition":{"icon":"03d","description":"scattered clouds","id":802,"main":"Clouds"},"wind_deg":257,"humidity":78,"imperial":{"eve":64.562,"morn":56.714,"night":58.80200000000001,"max":65.57,"day":63.59,"min":56.714}},{"timestamp":1371902400,"pressure":1003.45,"metric":{"eve":13.5,"morn":12.02,"night":13.04,"max":13.98,"day":13.98,"min":12.02},"wind_speed":6.11,"condition":{"icon":"10d","description":"moderate rain","id":501,"main":"Rain"},"wind_deg":215,"humidity":84,"imperial":{"eve":56.3,"morn":53.635999999999996,"night":55.471999999999994,"max":57.164,"day":57.164,"min":53.635999999999996}},{"timestamp":1371988800,"pressure":1011.26,"metric":{"eve":13.66,"morn":12.54,"night":12.4,"max":15.18,"day":15.18,"min":12.4},"wind_speed":4.46,"condition":{"icon":"10d","description":"light rain","id":500,"main":"Rain"},"wind_deg":290,"humidity":82,"imperial":{"eve":56.588,"morn":54.572,"night":54.32,"max":59.324,"day":59.324,"min":54.32}},{"timestamp":1372075200,"pressure":1018.06,"metric":{"eve":14.96,"morn":11.73,"night":12.42,"max":14.96,"day":14.62,"min":11.73},"wind_speed":6.44,"condition":{"icon":"10d","description":"moderate rain","id":501,"main":"Rain"},"wind_deg":292,"humidity":0,"imperial":{"eve":58.928,"morn":53.114000000000004,"night":54.356,"max":58.928,"day":58.316,"min":53.114000000000004}},{"timestamp":1372161600,"pressure":1023.37,"metric":{"eve":15.08,"morn":12.04,"night":11.13,"max":15.8,"day":15.8,"min":11.13},"wind_speed":5.25,"condition":{"icon":"10d","description":"moderate rain","id":501,"main":"Rain"},"wind_deg":294,"humidity":0,"imperial":{"eve":59.144000000000005,"morn":53.672,"night":52.034000000000006,"max":60.44,"day":60.44,"min":52.034000000000006}},{"timestamp":1372248000,"pressure":1023.86,"metric":{"eve":14.99,"morn":11.59,"night":11.29,"max":15.91,"day":15.91,"min":11.29},"wind_speed":4.64,"condition":{"icon":"10d","description":"moderate rain","id":501,"main":"Rain"},"wind_deg":247,"humidity":0,"imperial":{"eve":58.982,"morn":52.862,"night":52.322,"max":60.638000000000005,"day":60.638000000000005,"min":52.322}},{"timestamp":1372334400,"pressure":1022.68,"metric":{"eve":14.6,"morn":11.33,"night":10.22,"max":15.73,"day":15.73,"min":10.22},"wind_speed":4.34,"condition":{"icon":"10d","description":"light rain","id":500,"main":"Rain"},"wind_deg":294,"humidity":0,"imperial":{"eve":58.28,"morn":52.394000000000005,"night":50.396,"max":60.314,"day":60.314,"min":50.396}}]},"format":1,"current":{"request":{"type":"current","url":"http://api.openweathermap.org/data/2.5/weather?id=2643743&units=metric"},"results":{"timestamp":1371568737,"pressure":1013,"service_id":2643743,"metric":{"temp_min":19,"temp":20.61,"temp_max":22.22},"date":null,"condition":{"icon":"03d","description":"scattered clouds","id":802,"main":"Clouds"},"wind_deg":98.5007,"humidity":80,"wind_speed_mph":1.0998249,"imperial":{"temp_min":66.2,"temp":69.098,"temp_max":71.99600000000001},"service":"openweathermap","wind_speed_kmh":1.77}},"location":{"service_id":2643743,"name":"London","country":"GB","service":"openweathermap"}}""")
520-
521-locations_data.append("""{"daily":{"request":{"type":"daily","url":"http://api.openweathermap.org/data/2.5/forecast/daily?id=2911298&cnt=10&units=metric"},"results":[{"timestamp":1371553200,"pressure":1026.02,"metric":{"eve":24.71,"morn":25.5,"night":18.12,"max":25.5,"day":25.5,"min":18.12},"wind_speed":2.52,"condition":{"icon":"01d","description":"sky is clear","id":800,"main":"Clear"},"wind_deg":89,"humidity":70,"imperial":{"eve":76.47800000000001,"morn":77.9,"night":64.616,"max":77.9,"day":77.9,"min":64.616}},{"timestamp":1371639600,"pressure":1023.37,"metric":{"eve":29.17,"morn":20.41,"night":22.73,"max":30.39,"day":29.24,"min":20.41},"wind_speed":5.28,"condition":{"icon":"02d","description":"few clouds","id":801,"main":"Clouds"},"wind_deg":147,"humidity":69,"imperial":{"eve":84.506,"morn":68.738,"night":72.914,"max":86.702,"day":84.632,"min":68.738}},{"timestamp":1371726000,"pressure":1015.84,"metric":{"eve":25.49,"morn":24.61,"night":19.26,"max":29.68,"day":26.55,"min":19.26},"wind_speed":4.91,"condition":{"icon":"10d","description":"light rain","id":500,"main":"Rain"},"wind_deg":197,"humidity":84,"imperial":{"eve":77.882,"morn":76.298,"night":66.668,"max":85.424,"day":79.78999999999999,"min":66.668}},{"timestamp":1371812400,"pressure":1016.63,"metric":{"eve":17.09,"morn":16.63,"night":14.89,"max":19.75,"day":19.75,"min":14.89},"wind_speed":6.37,"condition":{"icon":"10d","description":"moderate rain","id":501,"main":"Rain"},"wind_deg":217,"humidity":91,"imperial":{"eve":62.762,"morn":61.934,"night":58.80200000000001,"max":67.55000000000001,"day":67.55000000000001,"min":58.80200000000001}},{"timestamp":1371898800,"pressure":1017.64,"metric":{"eve":18.15,"morn":16.27,"night":14.89,"max":19.34,"day":18.23,"min":14.89},"wind_speed":5.96,"condition":{"icon":"10d","description":"light rain","id":500,"main":"Rain"},"wind_deg":197,"humidity":83,"imperial":{"eve":64.67,"morn":61.286,"night":58.80200000000001,"max":66.812,"day":64.814,"min":58.80200000000001}},{"timestamp":1371985200,"pressure":1011.58,"metric":{"eve":15.16,"morn":14.29,"night":14.3,"max":15.93,"day":15.43,"min":14.29},"wind_speed":7.46,"condition":{"icon":"10d","description":"light rain","id":500,"main":"Rain"},"wind_deg":211,"humidity":86,"imperial":{"eve":59.288,"morn":57.721999999999994,"night":57.74,"max":60.674,"day":59.774,"min":57.721999999999994}},{"timestamp":1372071600,"pressure":1021.31,"metric":{"eve":17.86,"morn":14.88,"night":13.72,"max":17.97,"day":17.97,"min":13.72},"wind_speed":4.75,"condition":{"icon":"10d","description":"light rain","id":500,"main":"Rain"},"wind_deg":205,"humidity":0,"imperial":{"eve":64.148,"morn":58.784000000000006,"night":56.696,"max":64.346,"day":64.346,"min":56.696}},{"timestamp":1372158000,"pressure":1026.21,"metric":{"eve":16.23,"morn":13.89,"night":12.53,"max":16.75,"day":16.75,"min":12.53},"wind_speed":3.7,"condition":{"icon":"10d","description":"moderate rain","id":501,"main":"Rain"},"wind_deg":277,"humidity":0,"imperial":{"eve":61.214,"morn":57.002,"night":54.554,"max":62.150000000000006,"day":62.150000000000006,"min":54.554}},{"timestamp":1372244400,"pressure":1028.72,"metric":{"eve":16.24,"morn":13.84,"night":12.09,"max":16.71,"day":16.71,"min":12.09},"wind_speed":5.86,"condition":{"icon":"10d","description":"moderate rain","id":501,"main":"Rain"},"wind_deg":249,"humidity":0,"imperial":{"eve":61.232,"morn":56.912,"night":53.762,"max":62.078,"day":62.078,"min":53.762}},{"timestamp":1372330800,"pressure":1024.91,"metric":{"eve":16.15,"morn":12.93,"night":10.44,"max":16.33,"day":16.33,"min":10.44},"wind_speed":3.21,"condition":{"icon":"10d","description":"light rain","id":500,"main":"Rain"},"wind_deg":271,"humidity":0,"imperial":{"eve":61.06999999999999,"morn":55.274,"night":50.792,"max":61.394,"day":61.394,"min":50.792}}]},"db":{"updated":"2013-06-18T16:03:34.203Z","id":2},"format":1,"current":{"request":{"type":"current","url":"http://api.openweathermap.org/data/2.5/weather?id=2911298&units=metric"},"results":{"timestamp":1371568800,"pressure":1016,"service_id":2911298,"metric":{"temp_min":25,"temp":25.5,"temp_max":26},"date":null,"condition":{"icon":"01d","description":"Sky is Clear","id":800,"main":"Clear"},"wind_deg":100,"humidity":53,"wind_speed_mph":2.8583019999999997,"imperial":{"temp_min":77,"temp":77.9,"temp_max":78.80000000000001},"service":"openweathermap","wind_speed_kmh":4.6}},"location":{"service_id":2911298,"name":"Hamburg","country":"DE","service":"openweathermap"}}""")
522+
523+locations_data.append("""{"location":{"service_id":2643743,"name":"London","country":"GB","service":"openweathermap"},"db":{"updated":"2013-07-27T16:06:14.606Z","id":1},"format":20130727,"data":[{"date":"2013-07-27","timestamp":1374926400,"metric":{"tempMin":15.55,"tempMax":24.5},"imperial":{"tempMin":59.99,"tempMax":76.1},"pressure":1009.81,"humidity":63,"condition":{"id":502,"main":"Rain","description":"heavy intensity rain","icon":"10d"},"wind_speed":3.3,"wind_deg":101,"hourly":[],"current":{"timestamp":1374940874,"date":"2013-07-27 18:01","metric":{"temp":24.5},"imperial":{"temp":76.1},"humidity":64,"pressure":1004,"wind_speed_kmh":6.2,"wind_speed_mph":3.852494,"wind_deg":110,"condition":{"id":520,"main":"Rain","description":"light intensity shower rain","icon":"09d"},"service":"openweathermap","service_id":2643743}},{"date":"2013-07-28","timestamp":1375012800,"metric":{"tempMin":14.7,"tempMax":19.86},"imperial":{"tempMin":58.46,"tempMax":67.74799999999999},"pressure":1013.76,"humidity":91,"condition":{"id":501,"main":"Rain","description":"moderate rain","icon":"10d"},"wind_speed":4.46,"wind_deg":213,"hourly":[]},{"date":"2013-07-29","timestamp":1375099200,"metric":{"tempMin":14.67,"tempMax":17.63},"imperial":{"tempMin":58.406,"tempMax":63.733999999999995},"pressure":1016.16,"humidity":95,"condition":{"id":500,"main":"Rain","description":"light rain","icon":"10d"},"wind_speed":4.73,"wind_deg":213,"hourly":[]},{"date":"2013-07-30","timestamp":1375185600,"metric":{"tempMin":14.29,"tempMax":19.79},"imperial":{"tempMin":57.721999999999994,"tempMax":67.622},"pressure":1023.8,"humidity":70,"condition":{"id":500,"main":"Rain","description":"light rain","icon":"10d"},"wind_speed":3.98,"wind_deg":252,"hourly":[]},{"date":"2013-07-31","timestamp":1375272000,"metric":{"tempMin":15.19,"tempMax":24.08},"imperial":{"tempMin":59.342,"tempMax":75.344},"pressure":1021.26,"humidity":69,"condition":{"id":800,"main":"Clear","description":"sky is clear","icon":"01d"},"wind_speed":4.3,"wind_deg":217,"hourly":[]},{"date":"2013-08-01","timestamp":1375358400,"metric":{"tempMin":19.05,"tempMax":28.47},"imperial":{"tempMin":66.28999999999999,"tempMax":83.24600000000001},"pressure":1018.91,"humidity":59,"condition":{"id":800,"main":"Clear","description":"sky is clear","icon":"01d"},"wind_speed":3.45,"wind_deg":176,"hourly":[]},{"date":"2013-08-02","timestamp":1375444800,"metric":{"tempMin":14.26,"tempMax":18.83},"imperial":{"tempMin":57.668,"tempMax":65.894},"pressure":1016.86,"humidity":0,"condition":{"id":501,"main":"Rain","description":"moderate rain","icon":"10d"},"wind_speed":7.11,"wind_deg":207,"hourly":[]},{"date":"2013-08-03","timestamp":1375531200,"metric":{"tempMin":13.28,"tempMax":20.37},"imperial":{"tempMin":55.903999999999996,"tempMax":68.666},"pressure":1024.05,"humidity":0,"condition":{"id":500,"main":"Rain","description":"light rain","icon":"10d"},"wind_speed":3.05,"wind_deg":249,"hourly":[]},{"date":"2013-08-04","timestamp":1375617600,"metric":{"tempMin":14.07,"tempMax":21.59},"imperial":{"tempMin":57.326,"tempMax":70.862},"pressure":1020.85,"humidity":0,"condition":{"id":500,"main":"Rain","description":"light rain","icon":"10d"},"wind_speed":3.55,"wind_deg":165,"hourly":[]},{"date":"2013-08-05","timestamp":1375704000,"metric":{"tempMin":13.76,"tempMax":19.47},"imperial":{"tempMin":56.768,"tempMax":67.04599999999999},"pressure":1014.62,"humidity":0,"condition":{"id":501,"main":"Rain","description":"moderate rain","icon":"10d"},"wind_speed":5.38,"wind_deg":196,"hourly":[]}],"save":true}""")
524+
525+locations_data.append( """{"location":{"coord":{"lon":10,"lat":53.549999},"service_id":2911298,"name":"Hamburg","country":"DE","service":"openweathermap"},"db":{"updated":"2013-07-27T16:06:14.628Z","id":2},"format":20130727,"data":[{"date":"2013-07-27","timestamp":1374922800,"metric":{"tempMin":16.77,"tempMax":25.3},"imperial":{"tempMin":62.186,"tempMax":77.53999999999999},"pressure":1018.72,"humidity":66,"condition":{"id":501,"main":"Rain","description":"moderate rain","icon":"10d"},"wind_speed":2.15,"wind_deg":102,"hourly":[],"current":{"timestamp":1374940200,"date":"2013-07-27 17:50","metric":{"temp":25.3},"imperial":{"temp":77.53999999999999},"humidity":94,"pressure":1009,"wind_speed_kmh":6.2,"wind_speed_mph":3.852494,"wind_deg":240,"condition":{"id":200,"main":"Thunderstorm","description":"thunderstorm with light rain","icon":"11d"},"service":"openweathermap","service_id":2911298}},{"date":"2013-07-28","timestamp":1375009200,"metric":{"tempMin":17.73,"tempMax":22.74},"imperial":{"tempMin":63.914,"tempMax":72.93199999999999},"pressure":1020.48,"humidity":87,"condition":{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"},"wind_speed":6.21,"wind_deg":249,"hourly":[]},{"date":"2013-07-29","timestamp":1375095600,"metric":{"tempMin":15.53,"tempMax":23.35},"imperial":{"tempMin":59.954,"tempMax":74.03},"pressure":1024.02,"humidity":82,"condition":{"id":500,"main":"Rain","description":"light rain","icon":"10d"},"wind_speed":2.05,"wind_deg":172,"hourly":[]},{"date":"2013-07-30","timestamp":1375182000,"metric":{"tempMin":15.57,"tempMax":18.14},"imperial":{"tempMin":60.025999999999996,"tempMax":64.652},"pressure":1022.58,"humidity":95,"condition":{"id":501,"main":"Rain","description":"moderate rain","icon":"10d"},"wind_speed":7.5,"wind_deg":267,"hourly":[]},{"date":"2013-07-31","timestamp":1375268400,"metric":{"tempMin":15.09,"tempMax":23.08},"imperial":{"tempMin":59.162,"tempMax":73.544},"pressure":1028.48,"humidity":78,"condition":{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"},"wind_speed":5,"wind_deg":258,"hourly":[]},{"date":"2013-08-01","timestamp":1375354800,"metric":{"tempMin":19.15,"tempMax":27.67},"imperial":{"tempMin":66.47,"tempMax":81.80600000000001},"pressure":1030.67,"humidity":73,"condition":{"id":800,"main":"Clear","description":"sky is clear","icon":"01d"},"wind_speed":0.85,"wind_deg":99,"hourly":[]},{"date":"2013-08-02","timestamp":1375441200,"metric":{"tempMin":13.19,"tempMax":18.78},"imperial":{"tempMin":55.742000000000004,"tempMax":65.804},"pressure":1022.53,"humidity":0,"condition":{"id":502,"main":"Rain","description":"heavy intensity rain","icon":"10d"},"wind_speed":6.02,"wind_deg":253,"hourly":[]},{"date":"2013-08-03","timestamp":1375527600,"metric":{"tempMin":14.58,"tempMax":21.82},"imperial":{"tempMin":58.244,"tempMax":71.27600000000001},"pressure":1027.5,"humidity":0,"condition":{"id":500,"main":"Rain","description":"light rain","icon":"10d"},"wind_speed":3.21,"wind_deg":261,"hourly":[]},{"date":"2013-08-04","timestamp":1375614000,"metric":{"tempMin":12.47,"tempMax":19.72},"imperial":{"tempMin":54.446,"tempMax":67.49600000000001},"pressure":1027.54,"humidity":0,"condition":{"id":500,"main":"Rain","description":"light rain","icon":"10d"},"wind_speed":2.71,"wind_deg":1,"hourly":[]},{"date":"2013-08-05","timestamp":1375700400,"metric":{"tempMin":13.23,"tempMax":21.94},"imperial":{"tempMin":55.814,"tempMax":71.492},"pressure":1023.33,"humidity":0,"condition":{"id":800,"main":"Clear","description":"sky is clear","icon":"01d"},"wind_speed":2.09,"wind_deg":94,"hourly":[]}],"save":true}""")
526+
527+

Subscribers

People subscribed via source and target branches