diff --git a/front/src/assets/integrations/cover/openweather.jpg b/front/src/assets/integrations/cover/openweather.jpg new file mode 100644 index 0000000000..532ba72fd0 Binary files /dev/null and b/front/src/assets/integrations/cover/openweather.jpg differ diff --git a/front/src/components/app.jsx b/front/src/components/app.jsx index 66dc0bbc8a..bef17e4445 100644 --- a/front/src/components/app.jsx +++ b/front/src/components/app.jsx @@ -56,7 +56,7 @@ import SettingsGatewayOpenApi from '../routes/settings/settings-gateway-open-api // Integrations import TelegramPage from '../routes/integration/all/telegram'; import CaldavPage from '../routes/integration/all/caldav'; -import DarkSkyPage from '../routes/integration/all/darksky'; +import OpenWeatherPage from '../routes/integration/all/openweather'; import PhilipsHueSetupPage from '../routes/integration/all/philips-hue/setup-page'; import PhilipsHueDevicePage from '../routes/integration/all/philips-hue/device-page'; import ZwaveNodePage from '../routes/integration/all/zwave/node-page'; @@ -153,7 +153,7 @@ const AppRouter = connect( - + ( {' '} - + @@ -119,7 +119,7 @@ const WeatherBox = ({ children, ...props }) => ( fontSize: '30px' }} > - {props.units === 'si' ? 'C' : 'F'} + {props.units === 'metric' ? 'C' : 'F'} diff --git a/front/src/config/demo.json b/front/src/config/demo.json index fb036fb165..42fb82beb7 100644 --- a/front/src/config/demo.json +++ b/front/src/config/demo.json @@ -169,7 +169,7 @@ "humidity": 0.99, "pressure": 1005.09, "datetime": "2019-05-09T04:27:57.000Z", - "units": "si", + "units": "metric", "wind_speed": 1.96, "weather": "rain", "house": { diff --git a/front/src/config/i18n/en.json b/front/src/config/i18n/en.json index 0bbdab4344..8499d2ef8d 100644 --- a/front/src/config/i18n/en.json +++ b/front/src/config/i18n/en.json @@ -183,9 +183,9 @@ "weather": { "editHouseLabel": "Select a house. I will use its latitude/longitude to get the weather.", "houseHasNoCoordinates": "Your house has no coordinates defined. Go to Gladys parameters to define the position of your house.", - "serviceNotConfigured": "The DarkSky service is not configured. Please go to the 'Integrations' tab, and configure the DarkSky service.", - "requestToThirdPartyFailed": "The request to DarkSKy API failed. Is your Gladys instance connected to the internet? Please go to the DarkSky configuration panel to troubleshoot this problem.", - "clickHere": "Click here to access the DarkSky configuration panel.", + "serviceNotConfigured": "The OpenWeather service is not configured. Please go to the 'Integrations' tab, and configure the OpenWeather service.", + "requestToThirdPartyFailed": "The request to OpenWeather API failed. Is your Gladys instance connected to the internet? Please go to the OpenWeather configuration panel to troubleshoot this problem.", + "clickHere": "Click here to access the OpenWeather configuration panel.", "unknownError": "We are unable to get the weather for this house. Did you define a house for this box?" }, "devicesInRoom": { @@ -398,13 +398,13 @@ "nodeAddedDescription": "Wait a few seconds while we get all of the information from this node..." } }, - "darkSky": { - "title": "DarkSky", + "openWeather": { + "title": "OpenWeather API", "description": "Get the weather in Gladys.", - "introduction": "This integration helps you integrate with the DarkSky API to get the weather in Gladys.", - "instructions": "You first need to create an account on the DarkSky API website: https://darksky.net/dev.", + "introduction": "This integration helps you integrate with OpenWeather API to get the weather in Gladys.", + "instructions": "You first need to create an account on OpenWeather API website: https://openweathermap.org/api.", "apiKeyLabel": "Then, enter your API key here:", - "apiKeyPlaceholder": "Enter DarkSky API key", + "apiKeyPlaceholder": "Enter OpenWeather API key", "saveButton": "Save", "instructionsToUse": "To use this integration, go to the dashboard and create a weather box." }, diff --git a/front/src/config/i18n/fr.json b/front/src/config/i18n/fr.json index 5859705e2b..cae91739a9 100644 --- a/front/src/config/i18n/fr.json +++ b/front/src/config/i18n/fr.json @@ -183,9 +183,9 @@ "weather": { "editHouseLabel": "Sélectionnez une maison. J'utiliserais les latitude/longitude pour obtenir la météo.", "houseHasNoCoordinates": "Les coordonnées de votre maison ne sont pas définies. Accédez aux paramètres Gladys pour définir la position de votre maison.", - "serviceNotConfigured": "Le service DarkSky n'est pas configuré. Veuillez accéder à l'onglet «Intégrations» et configurer le service DarkSky.", - "requestToThirdPartyFailed": "La requête à l'API DarkSKy a échouée. Votre instance Gladys est-elle connectée à Internet? Veuillez vous rendre dans le panneau de configuration de DarkSky pour résoudre ce problème.", - "clickHere": "Cliquez ici pour accéder au panneau de configuration de DarkSky.", + "serviceNotConfigured": "Le service OpenWeather n'est pas configuré. Veuillez accéder à l'onglet «Intégrations» et configurer le service OpenWeather.", + "requestToThirdPartyFailed": "La requête à l'API OpenWeather a échouée. Votre instance Gladys est-elle connectée à Internet? Veuillez vous rendre dans le panneau de configuration de OpenWeather pour résoudre ce problème.", + "clickHere": "Cliquez ici pour accéder au panneau de configuration de OpenWeather.", "unknownError": "Nous ne pouvons pas obtenir la météo pour cette maison. Avez-vous défini une maison pour cette box ?" }, "devicesInRoom": { @@ -442,13 +442,13 @@ "nodeAddedDescription": "Attendez quelques secondes pendant que nous obtenons toutes les informations de ce nœud..." } }, - "darkSky": { - "title": "DarkSky", + "openWeather": { + "title": "API OpenWeather", "description": "Récupérer la météo dans Gladys.", - "introduction": "Cette intégration vous aide à intégrer l'API DarkSky pour obtenir la météo dans Gladys.", - "instructions": "Vous devez d'abord créer un compte sur le site Web de l'API DarkSky : https://darksky.net/dev.", + "introduction": "Cette intégration vous aide à intégrer l'API OpenWeather pour obtenir la météo dans Gladys.", + "instructions": "Vous devez d'abord créer un compte sur le site Web de l'API d'OpenWeather : https://openweathermap.org/api.", "apiKeyLabel": "Saisissez ensuite votre clé API ici :", - "apiKeyPlaceholder": "Entrer la clé API DarkSky", + "apiKeyPlaceholder": "Entrer la clé API OpenWeather", "saveButton": "Sauvegarder", "instructionsToUse": "Pour utiliser cette intégration, accédez au tableau de bord et créez une box météo." }, diff --git a/front/src/config/integrations/weathers.json b/front/src/config/integrations/weathers.json index 71ba2daef0..3f515ba90a 100644 --- a/front/src/config/integrations/weathers.json +++ b/front/src/config/integrations/weathers.json @@ -1,6 +1,6 @@ [ { - "key": "darkSky", - "img": "/assets/integrations/cover/darksky.jpg" + "key": "openWeather", + "img": "/assets/integrations/cover/openweather.jpg" } ] diff --git a/front/src/routes/integration/all/darksky/actions.js b/front/src/routes/integration/all/darksky/actions.js deleted file mode 100644 index a192b87cb5..0000000000 --- a/front/src/routes/integration/all/darksky/actions.js +++ /dev/null @@ -1,51 +0,0 @@ -import { RequestStatus } from '../../../../utils/consts'; - -const actions = store => ({ - updateApiKey(state, e) { - store.setState({ - darkSkyApiKey: e.target.value - }); - }, - async getApiKey(state) { - store.setState({ - darkskyGetApiKeyStatus: RequestStatus.Getting - }); - try { - const variable = await state.httpClient.get('/api/v1/service/darksky/variable/DARKSKY_API_KEY'); - store.setState({ - darkSkyApiKey: variable.value, - darkskyGetApiKeyStatus: RequestStatus.Success - }); - } catch (e) { - store.setState({ - darkskyGetApiKeyStatus: RequestStatus.Error - }); - } - }, - async saveApiKey(state, e) { - e.preventDefault(); - store.setState({ - darkskySaveApiKeyStatus: RequestStatus.Getting - }); - try { - store.setState({ - darkSkyApiKey: state.darkSkyApiKey.trim() - }); - // save api key - await state.httpClient.post('/api/v1/service/darksky/variable/DARKSKY_API_KEY', { - value: state.darkSkyApiKey.trim() - }); - // start service - await state.httpClient.post('/api/v1/service/darksky/start'); - store.setState({ - darkskySaveApiKeyStatus: RequestStatus.Success - }); - } catch (e) { - store.setState({ - darkskySaveApiKeyStatus: RequestStatus.Error - }); - } - } -}); - -export default actions; diff --git a/front/src/routes/integration/all/darksky/index.js b/front/src/routes/integration/all/darksky/index.js deleted file mode 100644 index e7f34e4355..0000000000 --- a/front/src/routes/integration/all/darksky/index.js +++ /dev/null @@ -1,20 +0,0 @@ -import { Component } from 'preact'; -import { connect } from 'unistore/preact'; -import actions from './actions'; -import DarkSkyPage from './DarkSky'; -import { RequestStatus } from '../../../../utils/consts'; - -@connect('user,darkSkyApiKey,darkskySaveApiKeyStatus,darkskyGetApiKeyStatus', actions) -class TelegramIntegration extends Component { - componentWillMount() { - this.props.getApiKey(); - } - - render(props, {}) { - const loading = - props.darkskySaveApiKeyStatus === RequestStatus.Getting || props.darkskyGetApiKeyStatus === RequestStatus.Getting; - return ; - } -} - -export default TelegramIntegration; diff --git a/front/src/routes/integration/all/darksky/DarkSky.jsx b/front/src/routes/integration/all/openweather/OpenWeather.jsx similarity index 77% rename from front/src/routes/integration/all/darksky/DarkSky.jsx rename to front/src/routes/integration/all/openweather/OpenWeather.jsx index 82dcb4e9a9..388ad513f8 100644 --- a/front/src/routes/integration/all/darksky/DarkSky.jsx +++ b/front/src/routes/integration/all/openweather/OpenWeather.jsx @@ -1,7 +1,7 @@ import { Text, MarkupText, Localizer } from 'preact-i18n'; import cx from 'classnames'; -const DarkSkyPage = ({ children, ...props }) => ( +const OpenWeatherPage = ({ children, ...props }) => (
@@ -18,27 +18,27 @@ const DarkSkyPage = ({ children, ...props }) => (

- +

- +

- +

- +
} + placeholder={} onInput={props.updateApiKey} - value={props.darkSkyApiKey} + value={props.openWeatherApiKey} /> @@ -48,7 +48,7 @@ const DarkSkyPage = ({ children, ...props }) => ( })} type="submit" > - +
@@ -56,7 +56,7 @@ const DarkSkyPage = ({ children, ...props }) => (
@@ -72,4 +72,4 @@ const DarkSkyPage = ({ children, ...props }) => (
); -export default DarkSkyPage; +export default OpenWeatherPage; diff --git a/front/src/routes/integration/all/openweather/actions.js b/front/src/routes/integration/all/openweather/actions.js new file mode 100644 index 0000000000..64abcef05b --- /dev/null +++ b/front/src/routes/integration/all/openweather/actions.js @@ -0,0 +1,51 @@ +import { RequestStatus } from '../../../../utils/consts'; + +const actions = store => ({ + updateApiKey(state, e) { + store.setState({ + openWeatherApiKey: e.target.value + }); + }, + async getApiKey(state) { + store.setState({ + openWeatherGetApiKeyStatus: RequestStatus.Getting + }); + try { + const variable = await state.httpClient.get('/api/v1/service/openweather/variable/OPENWEATHER_API_KEY'); + store.setState({ + openWeatherApiKey: variable.value, + openWeatherGetApiKeyStatus: RequestStatus.Success + }); + } catch (e) { + store.setState({ + openWeatherGetApiKeyStatus: RequestStatus.Error + }); + } + }, + async saveApiKey(state, e) { + e.preventDefault(); + store.setState({ + openWeatherSaveApiKeyStatus: RequestStatus.Getting + }); + try { + store.setState({ + openWeatheryApiKey: state.openWeatherApiKey.trim() + }); + // save api key + await state.httpClient.post('/api/v1/service/openweather/variable/OPENWEATHER_API_KEY', { + value: state.openWeatherApiKey.trim() + }); + // start service + await state.httpClient.post('/api/v1/service/openweather/start'); + store.setState({ + openWeatherSaveApiKeyStatus: RequestStatus.Success + }); + } catch (e) { + store.setState({ + openWeatherSaveApiKeyStatus: RequestStatus.Error + }); + } + } +}); + +export default actions; diff --git a/front/src/routes/integration/all/openweather/index.js b/front/src/routes/integration/all/openweather/index.js new file mode 100644 index 0000000000..73bfaa5d76 --- /dev/null +++ b/front/src/routes/integration/all/openweather/index.js @@ -0,0 +1,21 @@ +import { Component } from 'preact'; +import { connect } from 'unistore/preact'; +import actions from './actions'; +import OpenWeatherPage from './OpenWeather'; +import { RequestStatus } from '../../../../utils/consts'; + +@connect('user,openWeatherApiKey,openWeatherSaveApiKeyStatus,openWeatherGetApiKeyStatus', actions) +class OpenWeatherIntegration extends Component { + componentWillMount() { + this.props.getApiKey(); + } + + render(props, {}) { + const loading = + props.openWeatherSaveApiKeyStatus === RequestStatus.Getting || + props.openWeatherGetApiKeyStatus === RequestStatus.Getting; + return ; + } +} + +export default OpenWeatherIntegration; diff --git a/server/api/controllers/weather.controller.js b/server/api/controllers/weather.controller.js index b545f9a1c0..755ba1e3ff 100644 --- a/server/api/controllers/weather.controller.js +++ b/server/api/controllers/weather.controller.js @@ -13,7 +13,7 @@ module.exports = function WeatherController(gladys) { * "humidity": 0.58, * "pressure": 1005.98, * "datetime": "2019-05-09T04:26:42.000Z", - * "units": "si", + * "units": "metric", * "wind_speed": 5.06, * "weather": "cloud" * } @@ -39,7 +39,7 @@ module.exports = function WeatherController(gladys) { * "humidity": 0.58, * "pressure": 1005.98, * "datetime": "2019-05-09T04:26:42.000Z", - * "units": "si", + * "units": "metric", * "wind_speed": 5.06, * "weather": "cloud" * } diff --git a/server/config/brain/weather/answers.en.json b/server/config/brain/weather/answers.en.json index 6645796edc..0af4cdf5e9 100644 --- a/server/config/brain/weather/answers.en.json +++ b/server/config/brain/weather/answers.en.json @@ -37,7 +37,7 @@ }, { "label": "weather.get.fail.not-configured", - "answers": ["You need to configure DarkSky API in the Integration tab before using this feature."] + "answers": ["You need to configure OpenWeather API in the Integration tab before using this feature."] }, { "label": "weather.get.fail.no-house", diff --git a/server/lib/weather/weather.command.js b/server/lib/weather/weather.command.js index c20932ae43..f0aea4ce8a 100644 --- a/server/lib/weather/weather.command.js +++ b/server/lib/weather/weather.command.js @@ -21,7 +21,7 @@ async function command(message, classification, context) { case 'weather.get': weather = await this.get(house); context.temperature = weather.temperature; - context.units = weather.units === 'si' ? '°C' : '°F'; + context.units = weather.units === 'metric' ? '°C' : '°F'; await this.messageManager.replyByIntent(message, `weather.get.success.${weather.weather}`, context); break; default: diff --git a/server/lib/weather/weather.get.js b/server/lib/weather/weather.get.js index a433b47f48..f1d8ffc999 100644 --- a/server/lib/weather/weather.get.js +++ b/server/lib/weather/weather.get.js @@ -14,15 +14,15 @@ const { ServiceNotConfiguredError } = require('../../utils/coreErrors'); * longitude: -2, * offset: 0, * language: 'fr', - * units: 'si' + * units: 'metric' * }); */ function get(options) { - const darkSkyService = this.service.getService('darksky'); - if (darkSkyService === null) { - throw new ServiceNotConfiguredError(`Service darksky is not found or not configured.`); + const openweatherService = this.service.getService('openweather'); + if (openweatherService === null) { + throw new ServiceNotConfiguredError(`Service openweather is not found or not configured.`); } - return darkSkyService.weather.get(options); + return openweatherService.weather.get(options); } module.exports = { diff --git a/server/services/darksky/lib/formatResults.js b/server/services/darksky/lib/formatResults.js deleted file mode 100644 index ffa9da9653..0000000000 --- a/server/services/darksky/lib/formatResults.js +++ /dev/null @@ -1,67 +0,0 @@ -/** - * @description Transform DarkSky JSON to Gladys data. - * @param {Object} options - The weather call options. - * @param {Object} result - The result of the API call to DarkSky. - * @returns {Object} Return a formatted weather object. - * @example - * const formatted = formatResults(options, result); - */ -function formatResults(options, result) { - const dataToReturn = {}; - let dataPoint = null; - - // if options.offset == 0, it means it's now - if (options.offset === 0) { - dataPoint = result.currently; - - // if options.offset < 24, we take in the hour response - } else if (options.offset < 24) { - if (result.hourly.data.length > options.offset) { - dataPoint = result.hourly.data[options.offset]; - } else { - dataPoint = result.currently; - } - - // else if options.offset > 24, we take in the daily response - } else { - // we transform options.offset in day count - options.offset = Math.round(options.offset / 24); - - if (result.daily.data.length > options.offset) { - dataPoint = result.daily.data[options.offset]; - } else { - dataPoint = result.daily.data[result.daily.data.length - 1]; - } - } - - dataToReturn.temperature = dataPoint.temperature; - dataToReturn.humidity = dataPoint.humidity; - dataToReturn.pressure = dataPoint.pressure; - dataToReturn.datetime = new Date(dataPoint.time * 1000); - dataToReturn.units = options.units; - dataToReturn.wind_speed = dataPoint.windSpeed; - - if (dataPoint.icon.search('snow') !== -1) { - dataToReturn.weather = 'snow'; - } else if (dataPoint.icon.search('rain') !== -1) { - dataToReturn.weather = 'rain'; - } else if (dataPoint.icon.search('clear') !== -1) { - dataToReturn.weather = 'clear'; - } else if (dataPoint.icon.search('cloud') !== -1) { - dataToReturn.weather = 'cloud'; - } else if (dataPoint.icon.search('fog') !== -1) { - dataToReturn.weather = 'fog'; - } else if (dataPoint.icon.search('sleet') !== -1) { - dataToReturn.weather = 'sleet'; - } else if (dataPoint.icon.search('wind') !== -1) { - dataToReturn.weather = 'wind'; - } else { - dataToReturn.weather = 'unknown'; - } - - return dataToReturn; -} - -module.exports = { - formatResults, -}; diff --git a/server/services/index.js b/server/services/index.js index f1eaf06a9c..c7457cfcb2 100644 --- a/server/services/index.js +++ b/server/services/index.js @@ -1,6 +1,6 @@ module.exports.example = require('./example'); module.exports.caldav = require('./caldav'); -module.exports.darksky = require('./darksky'); +module.exports.openweather = require('./openweather'); module.exports.mqtt = require('./mqtt'); module.exports['philips-hue'] = require('./philips-hue'); module.exports['rtsp-camera'] = require('./rtsp-camera'); diff --git a/server/services/darksky/index.js b/server/services/openweather/index.js similarity index 64% rename from server/services/darksky/index.js rename to server/services/openweather/index.js index 4d8324911c..fba0c2920f 100644 --- a/server/services/darksky/index.js +++ b/server/services/openweather/index.js @@ -4,23 +4,23 @@ const { formatResults } = require('./lib/formatResults'); const { Error400 } = require('../../utils/httpErrors'); const { ERROR_MESSAGES } = require('../../utils/constants'); -const DARKSKY_API_KEY = 'DARKSKY_API_KEY'; +const OPENWEATHER_API_KEY = 'OPENWEATHER_API_KEY'; -module.exports = function DarkSkyService(gladys, serviceId) { +module.exports = function OpenWeatherService(gladys, serviceId) { const { default: axios } = require('axios'); - let darkSkyApiKey; + let openWeatherApiKey; /** * @public * @description This function starts the service * @example - * gladys.services.darksky.start(); + * gladys.services.openWeather.start(); */ async function start() { - logger.info('Starting Dark Sky service'); - darkSkyApiKey = await gladys.variable.getValue(DARKSKY_API_KEY, serviceId); - if (!darkSkyApiKey) { - throw new ServiceNotConfiguredError('Dark Sky Service not configured'); + logger.info('Starting Open Weather service'); + openWeatherApiKey = await gladys.variable.getValue(OPENWEATHER_API_KEY, serviceId); + if (!openWeatherApiKey) { + throw new ServiceNotConfiguredError('Open Weather Service not configured'); } } @@ -28,10 +28,10 @@ module.exports = function DarkSkyService(gladys, serviceId) { * @public * @description This function stops the service * @example - * gladys.services.darksky.stop(); + * gladys.services.openWeather.stop(); */ async function stop() { - logger.log('stopping Dark Sky service'); + logger.log('stopping Open Weather service'); } /** @@ -43,32 +43,34 @@ module.exports = function DarkSkyService(gladys, serviceId) { * @param {string} [options.language] - The language of the report. * @param {string} [options.units] - Unit of the weather [auto, si, us]. * @example - * gladys.services.darksky.weather.get({ + * gladys.services.openWeather.weather.get({ * latitude: 112, * longitude: -2, * offset: 0, * language: 'fr', - * units: 'si' + * units: 'metric' * }); */ async function get(options) { const DEFAULT = { language: 'en', - units: 'si', + units: 'metric', offset: 0, }; const optionsMerged = Object.assign({}, DEFAULT, options); const { latitude, longitude, language, units } = optionsMerged; - if (!darkSkyApiKey) { - throw new ServiceNotConfiguredError('Dark Sky API Key not found'); + if (!openWeatherApiKey) { + throw new ServiceNotConfiguredError('Open Weather API Key not found'); } - const url = `https://api.darksky.net/forecast/${darkSkyApiKey}/${latitude},${longitude}?language=${language}&units=${units}`; + const url = `http://api.openweathermap.org/data/2.5/weather?lat=${latitude}&lon=${longitude}&lang=${language}&units=${units}&cnt=1&appid=${openWeatherApiKey}`; try { + logger.log(`OpenWeather URL : ${url}`); const { data } = await axios.get(url); const weatherFormatted = formatResults(optionsMerged, data); return weatherFormatted; } catch (e) { + logger.error(e); throw new Error400(ERROR_MESSAGES.REQUEST_TO_THIRD_PARTY_FAILED); } } diff --git a/server/services/openweather/lib/formatResults.js b/server/services/openweather/lib/formatResults.js new file mode 100644 index 0000000000..c60d8a6c74 --- /dev/null +++ b/server/services/openweather/lib/formatResults.js @@ -0,0 +1,47 @@ +/** + * @description Transform OpenWeather JSON to Gladys data. + * @param {Object} options - The weather call options. + * @param {Object} result - The result of the API call to OpenWeather. + * @returns {Object} Return a formatted weather object. + * @example + * const formatted = formatResults(options, result); + */ +function formatResults(options, result) { + const dataToReturn = {}; + + // no offset management for now + const dataPoint = result; + + dataToReturn.name = dataPoint.name; + dataToReturn.temperature = dataPoint.main.temp; + dataToReturn.humidity = dataPoint.main.humidity; + dataToReturn.pressure = dataPoint.main.pressure; + dataToReturn.datetime = new Date(dataPoint.dt * 1000); + dataToReturn.units = options.units; + dataToReturn.wind_speed = dataPoint.wind.speed; + dataToReturn.wind_direction = dataPoint.wind.deg; + + if (dataPoint.weather[0].main.search('Snow') !== -1) { + dataToReturn.weather = 'snow'; + } else if (dataPoint.weather[0].main.search('Rain') !== -1) { + dataToReturn.weather = 'rain'; + } else if (dataPoint.weather[0].main.search('Clear') !== -1) { + dataToReturn.weather = 'clear'; + } else if (dataPoint.weather[0].main.search('Clouds') !== -1) { + dataToReturn.weather = 'cloud'; + } else if (dataPoint.weather[0].main.search('Mist') !== -1) { + dataToReturn.weather = 'fog'; + } else if (dataPoint.weather[0].main.search('Thunderstorm') !== -1) { + dataToReturn.weather = 'thunderstorm'; + } else if (dataPoint.weather[0].main.search('Drizzle') !== -1) { + dataToReturn.weather = 'drizzle'; + } else { + dataToReturn.weather = 'unknown'; + } + + return dataToReturn; +} + +module.exports = { + formatResults, +}; diff --git a/server/services/darksky/package-lock.json b/server/services/openweather/package-lock.json similarity index 97% rename from server/services/darksky/package-lock.json rename to server/services/openweather/package-lock.json index c833a3856a..faf0b633df 100644 --- a/server/services/darksky/package-lock.json +++ b/server/services/openweather/package-lock.json @@ -1,5 +1,5 @@ { - "name": "gladys-darksky", + "name": "gladys-openweather", "requires": true, "lockfileVersion": 1, "dependencies": { diff --git a/server/services/darksky/package.json b/server/services/openweather/package.json similarity index 85% rename from server/services/darksky/package.json rename to server/services/openweather/package.json index e0f331b8ef..dbef59e6f2 100644 --- a/server/services/darksky/package.json +++ b/server/services/openweather/package.json @@ -1,5 +1,5 @@ { - "name": "gladys-darksky", + "name": "gladys-openweather", "main": "index.js", "os": [ "darwin", diff --git a/server/test/bootstrap.test.js b/server/test/bootstrap.test.js index 4861aebedd..6b6b3ece8f 100644 --- a/server/test/bootstrap.test.js +++ b/server/test/bootstrap.test.js @@ -6,7 +6,7 @@ const Gladys = require('../lib'); const db = require('../models'); const logger = require('../utils/logger'); const { seedDb, cleanDb } = require('./helpers/db.test'); -const fakeDarkSkyService = require('./services/darksky/fakeDarkSkyService'); +const fakeOpenWeatherService = require('./services/openweather/fakeOpenWeatherService'); chai.use(chaiAsPromised); @@ -36,7 +36,7 @@ before(async function before() { throw e; } await gladys.start(); - gladys.stateManager.setState('service', 'darksky', fakeDarkSkyService); + gladys.stateManager.setState('service', 'openweather', fakeOpenWeatherService); gladys.gateway.gladysGatewayClient.accessToken = 'access-token'; gladys.gateway.gladysGatewayClient.refreshToken = 'refresh-token'; // @ts-ignore diff --git a/server/test/controllers/weather/weather.test.js b/server/test/controllers/weather/weather.test.js index eaa03e28dd..f7e69a5c0e 100644 --- a/server/test/controllers/weather/weather.test.js +++ b/server/test/controllers/weather/weather.test.js @@ -13,7 +13,7 @@ describe('GET /api/v1/user/:selector/weather', () => { humidity: 0.76, pressure: 1019.4, datetime: '2019-03-28T07:50:18.000Z', - units: 'si', + units: 'metric', wind_speed: 5.25, weather: 'cloud', }); @@ -45,7 +45,7 @@ describe('GET /api/v1/house/:selector/weather', () => { humidity: 0.76, pressure: 1019.4, datetime: '2019-03-28T07:50:18.000Z', - units: 'si', + units: 'metric', wind_speed: 5.25, weather: 'cloud', house: { diff --git a/server/test/lib/weather/weather.get.test.js b/server/test/lib/weather/weather.get.test.js index 3fe08d18d1..adda638544 100644 --- a/server/test/lib/weather/weather.get.test.js +++ b/server/test/lib/weather/weather.get.test.js @@ -13,7 +13,7 @@ const fakeWeather = { humidity: 0.76, pressure: 1019.4, datetime: new Date('2019-03-28T07:50:18.000Z'), - units: 'si', + units: 'metric', windSpeed: 5.25, weather: 'cloud', }; @@ -21,17 +21,17 @@ const fakeWeather = { const Weather = require('../../../lib/weather'); const { ServiceNotConfiguredError } = require('../../../utils/coreErrors'); -const darkSky = { +const openWeather = { weather: { get: fake.resolves(fakeWeather), }, }; const service = { - getService: () => darkSky, + getService: () => openWeather, }; -const serviceWithoutDarkSky = { +const serviceWithoutOpenWeather = { getService: () => null, }; @@ -43,7 +43,7 @@ describe('weather.get', () => { longitude: -2, offset: 0, language: 'fr', - units: 'si', + units: 'metric', }; const result = await weather.get(options); expect(result).to.deep.equal({ @@ -51,23 +51,23 @@ describe('weather.get', () => { humidity: 0.76, pressure: 1019.4, datetime: new Date('2019-03-28T07:50:18.000Z'), - units: 'si', + units: 'metric', windSpeed: 5.25, weather: 'cloud', }); - assert.calledWith(darkSky.weather.get, options); + assert.calledWith(openWeather.weather.get, options); }); it('should throw an error, service not configured', async () => { - const weather = new Weather(serviceWithoutDarkSky, event); + const weather = new Weather(serviceWithoutOpenWeather, event); const options = { latitude: 112, longitude: -2, offset: 0, language: 'fr', - units: 'si', + units: 'metric', }; expect(() => { weather.get(options); - }).to.throw(ServiceNotConfiguredError, 'Service darksky is not found or not configured'); + }).to.throw(ServiceNotConfiguredError, 'Service openweather is not found or not configured'); }); }); diff --git a/server/test/services/darksky/darsky.test.js b/server/test/services/darksky/darsky.test.js deleted file mode 100644 index b94ba7ff25..0000000000 --- a/server/test/services/darksky/darsky.test.js +++ /dev/null @@ -1,66 +0,0 @@ -const { expect, assert } = require('chai'); -const proxyquire = require('proxyquire').noCallThru(); -const weatherExample = require('./weather.json'); - -const workingAxios = { - axios: { - default: { - get: () => ({ data: weatherExample }), - }, - }, -}; - -const brokenAxios = { - axios: { - default: { - get: () => Promise.reject(new Error('broken')), - }, - }, -}; - -const gladys = { - variable: { - getValue: () => Promise.resolve('DARK_SKY_API_KEY'), - }, -}; - -describe('DarkSkyService', () => { - it('should start service', async () => { - const DarkSkyService = proxyquire('../../../services/darksky/index', workingAxios); - const darkSkyService = DarkSkyService(gladys, '35deac79-f295-4adf-8512-f2f48e1ea0f8'); - await darkSkyService.start(); - }); - it('should stop service', async () => { - const DarkSkyService = proxyquire('../../../services/darksky/index', workingAxios); - const darkSkyService = DarkSkyService(gladys, '35deac79-f295-4adf-8512-f2f48e1ea0f8'); - await darkSkyService.stop(); - }); - it('should return weather formatted', async () => { - const DarkSkyService = proxyquire('../../../services/darksky/index', workingAxios); - const darkSkyService = DarkSkyService(gladys, '35deac79-f295-4adf-8512-f2f48e1ea0f8'); - await darkSkyService.start(); - const weather = await darkSkyService.weather.get({ - latitude: 12, - longitude: 10, - }); - expect(weather).to.deep.equal({ - temperature: 54.87, - humidity: 0.76, - pressure: 1019.4, - datetime: new Date('2019-03-28T07:50:18.000Z'), - units: 'si', - wind_speed: 5.25, - weather: 'cloud', - }); - }); - it('should return error, unable to contact third party provider', async () => { - const DarkSkyService = proxyquire('../../../services/darksky/index', brokenAxios); - const darkSkyService = DarkSkyService(gladys, '35deac79-f295-4adf-8512-f2f48e1ea0f8'); - await darkSkyService.start(); - const promise = darkSkyService.weather.get({ - latitude: 12, - longitude: 10, - }); - return assert.isRejected(promise, 'REQUEST_TO_THIRD_PARTY_FAILED'); - }); -}); diff --git a/server/test/services/darksky/weather.json b/server/test/services/darksky/weather.json deleted file mode 100644 index 07d806c3ac..0000000000 --- a/server/test/services/darksky/weather.json +++ /dev/null @@ -1,1755 +0,0 @@ -{ - "latitude": 37.8267, - "longitude": -122.4233, - "timezone": "America/Los_Angeles", - "currently": { - "time": 1553759418, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-night", - "nearestStormDistance": 10, - "nearestStormBearing": 158, - "precipIntensity": 0, - "precipProbability": 0, - "temperature": 54.87, - "apparentTemperature": 54.87, - "dewPoint": 47.38, - "humidity": 0.76, - "pressure": 1019.4, - "windSpeed": 5.25, - "windGust": 9.43, - "windBearing": 200, - "cloudCover": 0.35, - "uvIndex": 0, - "visibility": 8.29, - "ozone": 332.54 - }, - "minutely": { - "summary": "Partly cloudy for the hour.", - "icon": "partly-cloudy-night", - "data": [ - { - "time": 1553759400, - "precipIntensity": 0, - "precipProbability": 0 - }, - { - "time": 1553759460, - "precipIntensity": 0, - "precipProbability": 0 - }, - { - "time": 1553759520, - "precipIntensity": 0, - "precipProbability": 0 - }, - { - "time": 1553759580, - "precipIntensity": 0, - "precipProbability": 0 - }, - { - "time": 1553759640, - "precipIntensity": 0, - "precipProbability": 0 - }, - { - "time": 1553759700, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.01, - "precipType": "rain" - }, - { - "time": 1553759760, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.02, - "precipType": "rain" - }, - { - "time": 1553759820, - "precipIntensity": 0.002, - "precipIntensityError": 0.001, - "precipProbability": 0.03, - "precipType": "rain" - }, - { - "time": 1553759880, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.05, - "precipType": "rain" - }, - { - "time": 1553759940, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.06, - "precipType": "rain" - }, - { - "time": 1553760000, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.08, - "precipType": "rain" - }, - { - "time": 1553760060, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.09, - "precipType": "rain" - }, - { - "time": 1553760120, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.1, - "precipType": "rain" - }, - { - "time": 1553760180, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.1, - "precipType": "rain" - }, - { - "time": 1553760240, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.1, - "precipType": "rain" - }, - { - "time": 1553760300, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.1, - "precipType": "rain" - }, - { - "time": 1553760360, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.09, - "precipType": "rain" - }, - { - "time": 1553760420, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.09, - "precipType": "rain" - }, - { - "time": 1553760480, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.08, - "precipType": "rain" - }, - { - "time": 1553760540, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.07, - "precipType": "rain" - }, - { - "time": 1553760600, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.07, - "precipType": "rain" - }, - { - "time": 1553760660, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.07, - "precipType": "rain" - }, - { - "time": 1553760720, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.06, - "precipType": "rain" - }, - { - "time": 1553760780, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.06, - "precipType": "rain" - }, - { - "time": 1553760840, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.05, - "precipType": "rain" - }, - { - "time": 1553760900, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.05, - "precipType": "rain" - }, - { - "time": 1553760960, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.05, - "precipType": "rain" - }, - { - "time": 1553761020, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.05, - "precipType": "rain" - }, - { - "time": 1553761080, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.04, - "precipType": "rain" - }, - { - "time": 1553761140, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.04, - "precipType": "rain" - }, - { - "time": 1553761200, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.04, - "precipType": "rain" - }, - { - "time": 1553761260, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.03, - "precipType": "rain" - }, - { - "time": 1553761320, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.03, - "precipType": "rain" - }, - { - "time": 1553761380, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.04, - "precipType": "rain" - }, - { - "time": 1553761440, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.03, - "precipType": "rain" - }, - { - "time": 1553761500, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.03, - "precipType": "rain" - }, - { - "time": 1553761560, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.03, - "precipType": "rain" - }, - { - "time": 1553761620, - "precipIntensity": 0, - "precipProbability": 0 - }, - { - "time": 1553761680, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.03, - "precipType": "rain" - }, - { - "time": 1553761740, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.03, - "precipType": "rain" - }, - { - "time": 1553761800, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.03, - "precipType": "rain" - }, - { - "time": 1553761860, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.02, - "precipType": "rain" - }, - { - "time": 1553761920, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.03, - "precipType": "rain" - }, - { - "time": 1553761980, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.02, - "precipType": "rain" - }, - { - "time": 1553762040, - "precipIntensity": 0, - "precipProbability": 0 - }, - { - "time": 1553762100, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.02, - "precipType": "rain" - }, - { - "time": 1553762160, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.02, - "precipType": "rain" - }, - { - "time": 1553762220, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.02, - "precipType": "rain" - }, - { - "time": 1553762280, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.02, - "precipType": "rain" - }, - { - "time": 1553762340, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.02, - "precipType": "rain" - }, - { - "time": 1553762400, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.02, - "precipType": "rain" - }, - { - "time": 1553762460, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.02, - "precipType": "rain" - }, - { - "time": 1553762520, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.02, - "precipType": "rain" - }, - { - "time": 1553762580, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.02, - "precipType": "rain" - }, - { - "time": 1553762640, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.02, - "precipType": "rain" - }, - { - "time": 1553762700, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.02, - "precipType": "rain" - }, - { - "time": 1553762760, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.02, - "precipType": "rain" - }, - { - "time": 1553762820, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.02, - "precipType": "rain" - }, - { - "time": 1553762880, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.02, - "precipType": "rain" - }, - { - "time": 1553762940, - "precipIntensity": 0, - "precipProbability": 0 - }, - { - "time": 1553763000, - "precipIntensity": 0.003, - "precipIntensityError": 0.001, - "precipProbability": 0.02, - "precipType": "rain" - } - ] - }, - "hourly": { - "summary": "Partly cloudy throughout the day.", - "icon": "partly-cloudy-day", - "data": [ - { - "time": 1553756400, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-night", - "precipIntensity": 0, - "precipProbability": 0, - "temperature": 55.4, - "apparentTemperature": 55.4, - "dewPoint": 47.59, - "humidity": 0.75, - "pressure": 1019.37, - "windSpeed": 5.84, - "windGust": 10.15, - "windBearing": 209, - "cloudCover": 0.29, - "uvIndex": 0, - "visibility": 8.27, - "ozone": 330.36 - }, - { - "time": 1553760000, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-night", - "precipIntensity": 0.0024, - "precipProbability": 0.11, - "precipType": "rain", - "temperature": 54.77, - "apparentTemperature": 54.77, - "dewPoint": 47.34, - "humidity": 0.76, - "pressure": 1019.41, - "windSpeed": 5.16, - "windGust": 9.29, - "windBearing": 198, - "cloudCover": 0.36, - "uvIndex": 0, - "visibility": 8.29, - "ozone": 332.96 - }, - { - "time": 1553763600, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-night", - "precipIntensity": 0.0016, - "precipProbability": 0.07, - "precipType": "rain", - "temperature": 54.15, - "apparentTemperature": 54.15, - "dewPoint": 47.22, - "humidity": 0.77, - "pressure": 1019.78, - "windSpeed": 5.11, - "windGust": 9.15, - "windBearing": 190, - "cloudCover": 0.45, - "uvIndex": 0, - "visibility": 8.51, - "ozone": 335.28 - }, - { - "time": 1553767200, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-night", - "precipIntensity": 0.0013, - "precipProbability": 0.09, - "precipType": "rain", - "temperature": 52.73, - "apparentTemperature": 52.73, - "dewPoint": 47.37, - "humidity": 0.82, - "pressure": 1020.67, - "windSpeed": 6.49, - "windGust": 10.8, - "windBearing": 192, - "cloudCover": 0.47, - "uvIndex": 0, - "visibility": 9.59, - "ozone": 336.95 - }, - { - "time": 1553770800, - "summary": "Possible Light Rain", - "icon": "rain", - "precipIntensity": 0.0355, - "precipProbability": 0.25, - "precipType": "rain", - "temperature": 51.9, - "apparentTemperature": 51.9, - "dewPoint": 47.57, - "humidity": 0.85, - "pressure": 1021.56, - "windSpeed": 7.45, - "windGust": 12.02, - "windBearing": 193, - "cloudCover": 0.54, - "uvIndex": 0, - "visibility": 9.25, - "ozone": 338.38 - }, - { - "time": 1553774400, - "summary": "Mostly Cloudy", - "icon": "partly-cloudy-night", - "precipIntensity": 0.0059, - "precipProbability": 0.23, - "precipType": "rain", - "temperature": 51.99, - "apparentTemperature": 51.99, - "dewPoint": 47.48, - "humidity": 0.85, - "pressure": 1021.73, - "windSpeed": 7.44, - "windGust": 12.25, - "windBearing": 191, - "cloudCover": 0.75, - "uvIndex": 0, - "visibility": 9.34, - "ozone": 340.57 - }, - { - "time": 1553778000, - "summary": "Mostly Cloudy", - "icon": "partly-cloudy-night", - "precipIntensity": 0.004, - "precipProbability": 0.19, - "precipType": "rain", - "temperature": 52.03, - "apparentTemperature": 52.03, - "dewPoint": 47.12, - "humidity": 0.83, - "pressure": 1022.11, - "windSpeed": 7.48, - "windGust": 12.94, - "windBearing": 188, - "cloudCover": 0.87, - "uvIndex": 0, - "visibility": 9.11, - "ozone": 344.25 - }, - { - "time": 1553781600, - "summary": "Overcast", - "icon": "cloudy", - "precipIntensity": 0.004, - "precipProbability": 0.18, - "precipType": "rain", - "temperature": 52, - "apparentTemperature": 52, - "dewPoint": 46.76, - "humidity": 0.82, - "pressure": 1022.36, - "windSpeed": 7.61, - "windGust": 13.74, - "windBearing": 186, - "cloudCover": 0.94, - "uvIndex": 0, - "visibility": 8.89, - "ozone": 348.6 - }, - { - "time": 1553785200, - "summary": "Mostly Cloudy", - "icon": "partly-cloudy-day", - "precipIntensity": 0.0047, - "precipProbability": 0.19, - "precipType": "rain", - "temperature": 52.46, - "apparentTemperature": 52.46, - "dewPoint": 46.55, - "humidity": 0.8, - "pressure": 1022.85, - "windSpeed": 7.82, - "windGust": 14.19, - "windBearing": 187, - "cloudCover": 0.86, - "uvIndex": 0, - "visibility": 8.84, - "ozone": 352.19 - }, - { - "time": 1553788800, - "summary": "Mostly Cloudy", - "icon": "partly-cloudy-day", - "precipIntensity": 0.0045, - "precipProbability": 0.19, - "precipType": "rain", - "temperature": 53.43, - "apparentTemperature": 53.43, - "dewPoint": 46.48, - "humidity": 0.77, - "pressure": 1023.24, - "windSpeed": 8.6, - "windGust": 14.92, - "windBearing": 189, - "cloudCover": 0.84, - "uvIndex": 1, - "visibility": 8.77, - "ozone": 354.99 - }, - { - "time": 1553792400, - "summary": "Mostly Cloudy", - "icon": "partly-cloudy-day", - "precipIntensity": 0.016, - "precipProbability": 0.27, - "precipType": "rain", - "temperature": 54.4, - "apparentTemperature": 54.4, - "dewPoint": 46.51, - "humidity": 0.75, - "pressure": 1023.88, - "windSpeed": 9.59, - "windGust": 16.17, - "windBearing": 198, - "cloudCover": 0.78, - "uvIndex": 2, - "visibility": 7.89, - "ozone": 357.05 - }, - { - "time": 1553796000, - "summary": "Mostly Cloudy", - "icon": "partly-cloudy-day", - "precipIntensity": 0.0106, - "precipProbability": 0.25, - "precipType": "rain", - "temperature": 55.12, - "apparentTemperature": 55.12, - "dewPoint": 46.58, - "humidity": 0.73, - "pressure": 1024.28, - "windSpeed": 10.93, - "windGust": 16.9, - "windBearing": 201, - "cloudCover": 0.74, - "uvIndex": 3, - "visibility": 8.64, - "ozone": 356.98 - }, - { - "time": 1553799600, - "summary": "Mostly Cloudy", - "icon": "partly-cloudy-day", - "precipIntensity": 0.0061, - "precipProbability": 0.21, - "precipType": "rain", - "temperature": 55.68, - "apparentTemperature": 55.68, - "dewPoint": 46.67, - "humidity": 0.72, - "pressure": 1024.29, - "windSpeed": 11.9, - "windGust": 16.85, - "windBearing": 207, - "cloudCover": 0.65, - "uvIndex": 4, - "visibility": 10, - "ozone": 353.68 - }, - { - "time": 1553803200, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-day", - "precipIntensity": 0.0067, - "precipProbability": 0.22, - "precipType": "rain", - "temperature": 55.88, - "apparentTemperature": 55.88, - "dewPoint": 46.46, - "humidity": 0.71, - "pressure": 1024.19, - "windSpeed": 12.59, - "windGust": 16.96, - "windBearing": 215, - "cloudCover": 0.53, - "uvIndex": 5, - "visibility": 10, - "ozone": 348.29 - }, - { - "time": 1553806800, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-day", - "precipIntensity": 0.0084, - "precipProbability": 0.24, - "precipType": "rain", - "temperature": 56.32, - "apparentTemperature": 56.32, - "dewPoint": 46.74, - "humidity": 0.7, - "pressure": 1024.19, - "windSpeed": 13.88, - "windGust": 17.57, - "windBearing": 221, - "cloudCover": 0.43, - "uvIndex": 5, - "visibility": 10, - "ozone": 342.62 - }, - { - "time": 1553810400, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-day", - "precipIntensity": 0.0085, - "precipProbability": 0.2, - "precipType": "rain", - "temperature": 57.83, - "apparentTemperature": 57.83, - "dewPoint": 46.47, - "humidity": 0.66, - "pressure": 1024.01, - "windSpeed": 14.3, - "windGust": 17.39, - "windBearing": 229, - "cloudCover": 0.47, - "uvIndex": 4, - "visibility": 10, - "ozone": 336.49 - }, - { - "time": 1553814000, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-day", - "precipIntensity": 0.005, - "precipProbability": 0.15, - "precipType": "rain", - "temperature": 57.16, - "apparentTemperature": 57.16, - "dewPoint": 46.64, - "humidity": 0.68, - "pressure": 1023.92, - "windSpeed": 13.91, - "windGust": 17.21, - "windBearing": 235, - "cloudCover": 0.45, - "uvIndex": 3, - "visibility": 10, - "ozone": 330.11 - }, - { - "time": 1553817600, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-day", - "precipIntensity": 0.0042, - "precipProbability": 0.14, - "precipType": "rain", - "temperature": 56.27, - "apparentTemperature": 56.27, - "dewPoint": 46.82, - "humidity": 0.71, - "pressure": 1023.97, - "windSpeed": 13.23, - "windGust": 16.64, - "windBearing": 241, - "cloudCover": 0.42, - "uvIndex": 2, - "visibility": 10, - "ozone": 325.8 - }, - { - "time": 1553821200, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-day", - "precipIntensity": 0.005, - "precipProbability": 0.17, - "precipType": "rain", - "temperature": 55.57, - "apparentTemperature": 55.57, - "dewPoint": 47.03, - "humidity": 0.73, - "pressure": 1024.15, - "windSpeed": 12.16, - "windGust": 15.41, - "windBearing": 245, - "cloudCover": 0.4, - "uvIndex": 1, - "visibility": 10, - "ozone": 325.23 - }, - { - "time": 1553824800, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-day", - "precipIntensity": 0.0077, - "precipProbability": 0.2, - "precipType": "rain", - "temperature": 54.67, - "apparentTemperature": 54.67, - "dewPoint": 47.26, - "humidity": 0.76, - "pressure": 1024.45, - "windSpeed": 10.74, - "windGust": 13.76, - "windBearing": 248, - "cloudCover": 0.39, - "uvIndex": 0, - "visibility": 10, - "ozone": 326.69 - }, - { - "time": 1553828400, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-night", - "precipIntensity": 0.0103, - "precipProbability": 0.23, - "precipType": "rain", - "temperature": 53.9, - "apparentTemperature": 53.9, - "dewPoint": 47.41, - "humidity": 0.79, - "pressure": 1024.89, - "windSpeed": 9.38, - "windGust": 12.07, - "windBearing": 250, - "cloudCover": 0.38, - "uvIndex": 0, - "visibility": 10, - "ozone": 328.05 - }, - { - "time": 1553832000, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-night", - "precipIntensity": 0.0096, - "precipProbability": 0.26, - "precipType": "rain", - "temperature": 53.4, - "apparentTemperature": 53.4, - "dewPoint": 47.39, - "humidity": 0.8, - "pressure": 1025.53, - "windSpeed": 8.09, - "windGust": 10.32, - "windBearing": 253, - "cloudCover": 0.37, - "uvIndex": 0, - "visibility": 10, - "ozone": 328.41 - }, - { - "time": 1553835600, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-night", - "precipIntensity": 0.0082, - "precipProbability": 0.29, - "precipType": "rain", - "temperature": 52.98, - "apparentTemperature": 52.98, - "dewPoint": 47.31, - "humidity": 0.81, - "pressure": 1026.31, - "windSpeed": 6.84, - "windGust": 8.56, - "windBearing": 251, - "cloudCover": 0.36, - "uvIndex": 0, - "visibility": 10, - "ozone": 328.54 - }, - { - "time": 1553839200, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-night", - "precipIntensity": 0.0075, - "precipProbability": 0.3, - "precipType": "rain", - "temperature": 52.59, - "apparentTemperature": 52.59, - "dewPoint": 47.2, - "humidity": 0.82, - "pressure": 1026.91, - "windSpeed": 5.84, - "windGust": 7.21, - "windBearing": 245, - "cloudCover": 0.34, - "uvIndex": 0, - "visibility": 10, - "ozone": 328.84 - }, - { - "time": 1553842800, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-night", - "precipIntensity": 0.0067, - "precipProbability": 0.26, - "precipType": "rain", - "temperature": 52.2, - "apparentTemperature": 52.2, - "dewPoint": 47.11, - "humidity": 0.83, - "pressure": 1027.16, - "windSpeed": 5.14, - "windGust": 6.51, - "windBearing": 221, - "cloudCover": 0.43, - "uvIndex": 0, - "visibility": 10, - "ozone": 329.26 - }, - { - "time": 1553846400, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-night", - "precipIntensity": 0.0058, - "precipProbability": 0.23, - "precipType": "rain", - "temperature": 51.92, - "apparentTemperature": 51.92, - "dewPoint": 46.99, - "humidity": 0.83, - "pressure": 1027.21, - "windSpeed": 4.54, - "windGust": 6.16, - "windBearing": 263, - "cloudCover": 0.54, - "uvIndex": 0, - "visibility": 10, - "ozone": 329.74 - }, - { - "time": 1553850000, - "summary": "Mostly Cloudy", - "icon": "partly-cloudy-night", - "precipIntensity": 0.0052, - "precipProbability": 0.2, - "precipType": "rain", - "temperature": 51.75, - "apparentTemperature": 51.75, - "dewPoint": 46.85, - "humidity": 0.83, - "pressure": 1027.23, - "windSpeed": 4.36, - "windGust": 5.84, - "windBearing": 247, - "cloudCover": 0.61, - "uvIndex": 0, - "visibility": 10, - "ozone": 330.35 - }, - { - "time": 1553853600, - "summary": "Mostly Cloudy", - "icon": "partly-cloudy-night", - "precipIntensity": 0.0052, - "precipProbability": 0.19, - "precipType": "rain", - "temperature": 51.48, - "apparentTemperature": 51.48, - "dewPoint": 46.73, - "humidity": 0.84, - "pressure": 1027.23, - "windSpeed": 3.8, - "windGust": 5.39, - "windBearing": 211, - "cloudCover": 0.6, - "uvIndex": 0, - "visibility": 10, - "ozone": 331.24 - }, - { - "time": 1553857200, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-night", - "precipIntensity": 0.0061, - "precipProbability": 0.22, - "precipType": "rain", - "temperature": 51.14, - "apparentTemperature": 51.14, - "dewPoint": 46.59, - "humidity": 0.84, - "pressure": 1027.18, - "windSpeed": 3.65, - "windGust": 4.95, - "windBearing": 307, - "cloudCover": 0.55, - "uvIndex": 0, - "visibility": 10, - "ozone": 332.33 - }, - { - "time": 1553860800, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-night", - "precipIntensity": 0.0063, - "precipProbability": 0.24, - "precipType": "rain", - "temperature": 50.85, - "apparentTemperature": 50.85, - "dewPoint": 46.43, - "humidity": 0.85, - "pressure": 1027.24, - "windSpeed": 4.1, - "windGust": 4.6, - "windBearing": 274, - "cloudCover": 0.5, - "uvIndex": 0, - "visibility": 10, - "ozone": 333.37 - }, - { - "time": 1553864400, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-night", - "precipIntensity": 0.0044, - "precipProbability": 0.2, - "precipType": "rain", - "temperature": 50.37, - "apparentTemperature": 50.37, - "dewPoint": 46.31, - "humidity": 0.86, - "pressure": 1027.56, - "windSpeed": 3.2, - "windGust": 4.37, - "windBearing": 255, - "cloudCover": 0.47, - "uvIndex": 0, - "visibility": 10, - "ozone": 334.35 - }, - { - "time": 1553868000, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-night", - "precipIntensity": 0.0021, - "precipProbability": 0.11, - "precipType": "rain", - "temperature": 49.86, - "apparentTemperature": 49.13, - "dewPoint": 46.17, - "humidity": 0.87, - "pressure": 1028.01, - "windSpeed": 3.45, - "windGust": 4.26, - "windBearing": 346, - "cloudCover": 0.45, - "uvIndex": 0, - "visibility": 10, - "ozone": 335.35 - }, - { - "time": 1553871600, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-day", - "precipIntensity": 0.0011, - "precipProbability": 0.06, - "precipType": "rain", - "temperature": 49.83, - "apparentTemperature": 48.81, - "dewPoint": 45.97, - "humidity": 0.87, - "pressure": 1028.37, - "windSpeed": 3.82, - "windGust": 4.37, - "windBearing": 334, - "cloudCover": 0.44, - "uvIndex": 0, - "visibility": 10, - "ozone": 336.17 - }, - { - "time": 1553875200, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-day", - "precipIntensity": 0.0007, - "precipProbability": 0.03, - "precipType": "rain", - "temperature": 50.8, - "apparentTemperature": 50.8, - "dewPoint": 45.62, - "humidity": 0.82, - "pressure": 1028.57, - "windSpeed": 3.99, - "windGust": 4.94, - "windBearing": 334, - "cloudCover": 0.46, - "uvIndex": 1, - "visibility": 10, - "ozone": 336.92 - }, - { - "time": 1553878800, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-day", - "precipIntensity": 0.0004, - "precipProbability": 0.02, - "precipType": "rain", - "temperature": 52.38, - "apparentTemperature": 52.38, - "dewPoint": 45.25, - "humidity": 0.77, - "pressure": 1028.69, - "windSpeed": 4.29, - "windGust": 5.92, - "windBearing": 340, - "cloudCover": 0.49, - "uvIndex": 2, - "visibility": 10, - "ozone": 337.47 - }, - { - "time": 1553882400, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-day", - "precipIntensity": 0.0002, - "precipProbability": 0.02, - "precipType": "rain", - "temperature": 53.85, - "apparentTemperature": 53.85, - "dewPoint": 44.91, - "humidity": 0.72, - "pressure": 1028.7, - "windSpeed": 4.71, - "windGust": 6.7, - "windBearing": 338, - "cloudCover": 0.5, - "uvIndex": 4, - "visibility": 10, - "ozone": 337.45 - }, - { - "time": 1553886000, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-day", - "precipIntensity": 0, - "precipProbability": 0, - "temperature": 55.28, - "apparentTemperature": 55.28, - "dewPoint": 44.54, - "humidity": 0.67, - "pressure": 1028.61, - "windSpeed": 5.02, - "windGust": 6.91, - "windBearing": 327, - "cloudCover": 0.43, - "uvIndex": 5, - "visibility": 10, - "ozone": 336.45 - }, - { - "time": 1553889600, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-day", - "precipIntensity": 0, - "precipProbability": 0, - "temperature": 57.18, - "apparentTemperature": 57.18, - "dewPoint": 44.22, - "humidity": 0.62, - "pressure": 1028.4, - "windSpeed": 5.42, - "windGust": 6.92, - "windBearing": 309, - "cloudCover": 0.34, - "uvIndex": 6, - "visibility": 10, - "ozone": 334.91 - }, - { - "time": 1553893200, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-day", - "precipIntensity": 0, - "precipProbability": 0, - "temperature": 58.68, - "apparentTemperature": 58.68, - "dewPoint": 44.16, - "humidity": 0.58, - "pressure": 1028.14, - "windSpeed": 6.17, - "windGust": 7.41, - "windBearing": 296, - "cloudCover": 0.27, - "uvIndex": 6, - "visibility": 10, - "ozone": 333.74 - }, - { - "time": 1553896800, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-day", - "precipIntensity": 0, - "precipProbability": 0, - "temperature": 59.3, - "apparentTemperature": 59.3, - "dewPoint": 44.51, - "humidity": 0.58, - "pressure": 1027.7, - "windSpeed": 7.73, - "windGust": 8.86, - "windBearing": 294, - "cloudCover": 0.27, - "uvIndex": 5, - "visibility": 10, - "ozone": 333.2 - }, - { - "time": 1553900400, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-day", - "precipIntensity": 0, - "precipProbability": 0, - "temperature": 59.14, - "apparentTemperature": 59.14, - "dewPoint": 45.09, - "humidity": 0.6, - "pressure": 1027.2, - "windSpeed": 9.7, - "windGust": 10.81, - "windBearing": 292, - "cloudCover": 0.28, - "uvIndex": 3, - "visibility": 10, - "ozone": 333.04 - }, - { - "time": 1553904000, - "summary": "Partly Cloudy", - "icon": "partly-cloudy-day", - "precipIntensity": 0, - "precipProbability": 0, - "temperature": 58.61, - "apparentTemperature": 58.61, - "dewPoint": 45.49, - "humidity": 0.62, - "pressure": 1026.86, - "windSpeed": 11.07, - "windGust": 12.56, - "windBearing": 291, - "cloudCover": 0.27, - "uvIndex": 2, - "visibility": 10, - "ozone": 333.21 - }, - { - "time": 1553907600, - "summary": "Clear", - "icon": "clear-day", - "precipIntensity": 0, - "precipProbability": 0, - "temperature": 57.63, - "apparentTemperature": 57.63, - "dewPoint": 45.57, - "humidity": 0.64, - "pressure": 1026.87, - "windSpeed": 11.34, - "windGust": 14.18, - "windBearing": 294, - "cloudCover": 0.2, - "uvIndex": 1, - "visibility": 10, - "ozone": 333.82 - }, - { - "time": 1553911200, - "summary": "Clear", - "icon": "clear-day", - "precipIntensity": 0, - "precipProbability": 0, - "temperature": 56.32, - "apparentTemperature": 56.32, - "dewPoint": 45.53, - "humidity": 0.67, - "pressure": 1027.05, - "windSpeed": 11.13, - "windGust": 15.61, - "windBearing": 301, - "cloudCover": 0.11, - "uvIndex": 0, - "visibility": 10, - "ozone": 334.7 - }, - { - "time": 1553914800, - "summary": "Clear", - "icon": "clear-night", - "precipIntensity": 0, - "precipProbability": 0, - "temperature": 54.97, - "apparentTemperature": 54.97, - "dewPoint": 45.52, - "humidity": 0.7, - "pressure": 1027.26, - "windSpeed": 10.64, - "windGust": 15.96, - "windBearing": 304, - "cloudCover": 0.04, - "uvIndex": 0, - "visibility": 10, - "ozone": 335.64 - }, - { - "time": 1553918400, - "summary": "Clear", - "icon": "clear-night", - "precipIntensity": 0, - "precipProbability": 0, - "temperature": 54.01, - "apparentTemperature": 54.01, - "dewPoint": 45.58, - "humidity": 0.73, - "pressure": 1027.47, - "windSpeed": 9.96, - "windGust": 14.47, - "windBearing": 306, - "cloudCover": 0.04, - "uvIndex": 0, - "visibility": 10, - "ozone": 336.62 - }, - { - "time": 1553922000, - "summary": "Clear", - "icon": "clear-night", - "precipIntensity": 0, - "precipProbability": 0, - "temperature": 53.25, - "apparentTemperature": 53.25, - "dewPoint": 45.67, - "humidity": 0.75, - "pressure": 1027.73, - "windSpeed": 9.11, - "windGust": 11.91, - "windBearing": 310, - "cloudCover": 0.05, - "uvIndex": 0, - "visibility": 10, - "ozone": 337.7 - }, - { - "time": 1553925600, - "summary": "Clear", - "icon": "clear-night", - "precipIntensity": 0, - "precipProbability": 0, - "temperature": 52.56, - "apparentTemperature": 52.56, - "dewPoint": 45.65, - "humidity": 0.77, - "pressure": 1027.78, - "windSpeed": 8.29, - "windGust": 9.7, - "windBearing": 312, - "cloudCover": 0.08, - "uvIndex": 0, - "visibility": 10, - "ozone": 338.17 - }, - { - "time": 1553929200, - "summary": "Clear", - "icon": "clear-night", - "precipIntensity": 0, - "precipProbability": 0, - "temperature": 51.95, - "apparentTemperature": 51.95, - "dewPoint": 45.47, - "humidity": 0.78, - "pressure": 1027.57, - "windSpeed": 7.61, - "windGust": 8.44, - "windBearing": 313, - "cloudCover": 0.13, - "uvIndex": 0, - "visibility": 10, - "ozone": 338.05 - } - ] - }, - "daily": { - "summary": "Light rain today, with high temperatures peaking at 67°F on Sunday.", - "icon": "rain", - "data": [ - { - "time": 1553756400, - "summary": "Partly cloudy throughout the day.", - "icon": "partly-cloudy-day", - "sunriseTime": 1553781720, - "sunsetTime": 1553826583, - "moonPhase": 0.77, - "precipIntensity": 0.0074, - "precipIntensityMax": 0.0355, - "precipIntensityMaxTime": 1553770800, - "precipProbability": 0.7, - "precipType": "rain", - "temperatureHigh": 57.83, - "temperatureHighTime": 1553810400, - "temperatureLow": 49.83, - "temperatureLowTime": 1553871600, - "apparentTemperatureHigh": 57.83, - "apparentTemperatureHighTime": 1553810400, - "apparentTemperatureLow": 48.81, - "apparentTemperatureLowTime": 1553871600, - "dewPoint": 47, - "humidity": 0.77, - "pressure": 1023.25, - "windSpeed": 8.51, - "windGust": 17.57, - "windGustTime": 1553806800, - "windBearing": 218, - "cloudCover": 0.54, - "uvIndex": 5, - "uvIndexTime": 1553803200, - "visibility": 9.39, - "ozone": 338.8, - "temperatureMin": 51.9, - "temperatureMinTime": 1553770800, - "temperatureMax": 57.83, - "temperatureMaxTime": 1553810400, - "apparentTemperatureMin": 51.9, - "apparentTemperatureMinTime": 1553770800, - "apparentTemperatureMax": 57.83, - "apparentTemperatureMaxTime": 1553810400 - }, - { - "time": 1553842800, - "summary": "Partly cloudy until evening.", - "icon": "partly-cloudy-day", - "sunriseTime": 1553868028, - "sunsetTime": 1553913038, - "moonPhase": 0.8, - "precipIntensity": 0.0019, - "precipIntensityMax": 0.0067, - "precipIntensityMaxTime": 1553842800, - "precipProbability": 0.44, - "precipType": "rain", - "temperatureHigh": 59.3, - "temperatureHighTime": 1553896800, - "temperatureLow": 49.52, - "temperatureLowTime": 1553954400, - "apparentTemperatureHigh": 59.3, - "apparentTemperatureHighTime": 1553896800, - "apparentTemperatureLow": 48.16, - "apparentTemperatureLowTime": 1553954400, - "dewPoint": 45.69, - "humidity": 0.74, - "pressure": 1027.68, - "windSpeed": 5.71, - "windGust": 15.96, - "windGustTime": 1553914800, - "windBearing": 299, - "cloudCover": 0.35, - "uvIndex": 6, - "uvIndexTime": 1553889600, - "visibility": 10, - "ozone": 334.38, - "temperatureMin": 49.83, - "temperatureMinTime": 1553871600, - "temperatureMax": 59.3, - "temperatureMaxTime": 1553896800, - "apparentTemperatureMin": 48.81, - "apparentTemperatureMinTime": 1553871600, - "apparentTemperatureMax": 59.3, - "apparentTemperatureMaxTime": 1553896800 - }, - { - "time": 1553929200, - "summary": "Partly cloudy throughout the day.", - "icon": "partly-cloudy-day", - "sunriseTime": 1553954336, - "sunsetTime": 1553999492, - "moonPhase": 0.83, - "precipIntensity": 0.0002, - "precipIntensityMax": 0.0007, - "precipIntensityMaxTime": 1554012000, - "precipProbability": 0.05, - "precipType": "rain", - "temperatureHigh": 61.82, - "temperatureHighTime": 1553986800, - "temperatureLow": 52.84, - "temperatureLowTime": 1554040800, - "apparentTemperatureHigh": 61.82, - "apparentTemperatureHighTime": 1553986800, - "apparentTemperatureLow": 52.84, - "apparentTemperatureLowTime": 1554040800, - "dewPoint": 45.76, - "humidity": 0.71, - "pressure": 1025.41, - "windSpeed": 5.47, - "windGust": 11.7, - "windGustTime": 1553997600, - "windBearing": 297, - "cloudCover": 0.35, - "uvIndex": 5, - "uvIndexTime": 1553972400, - "visibility": 10, - "ozone": 331.16, - "temperatureMin": 49.52, - "temperatureMinTime": 1553954400, - "temperatureMax": 61.82, - "temperatureMaxTime": 1553986800, - "apparentTemperatureMin": 48.16, - "apparentTemperatureMinTime": 1553954400, - "apparentTemperatureMax": 61.82, - "apparentTemperatureMaxTime": 1553986800 - }, - { - "time": 1554015600, - "summary": "Mostly cloudy throughout the day.", - "icon": "partly-cloudy-day", - "sunriseTime": 1554040645, - "sunsetTime": 1554085946, - "moonPhase": 0.86, - "precipIntensity": 0.0002, - "precipIntensityMax": 0.0007, - "precipIntensityMaxTime": 1554033600, - "precipProbability": 0.07, - "precipType": "rain", - "temperatureHigh": 67.01, - "temperatureHighTime": 1554069600, - "temperatureLow": 55.16, - "temperatureLowTime": 1554127200, - "apparentTemperatureHigh": 67.01, - "apparentTemperatureHighTime": 1554069600, - "apparentTemperatureLow": 55.16, - "apparentTemperatureLowTime": 1554127200, - "dewPoint": 48.14, - "humidity": 0.69, - "pressure": 1022.24, - "windSpeed": 4.77, - "windGust": 12.24, - "windGustTime": 1554080400, - "windBearing": 291, - "cloudCover": 0.71, - "uvIndex": 5, - "uvIndexTime": 1554058800, - "visibility": 10, - "ozone": 316.32, - "temperatureMin": 52.84, - "temperatureMinTime": 1554040800, - "temperatureMax": 67.01, - "temperatureMaxTime": 1554069600, - "apparentTemperatureMin": 52.84, - "apparentTemperatureMinTime": 1554040800, - "apparentTemperatureMax": 67.01, - "apparentTemperatureMaxTime": 1554069600 - }, - { - "time": 1554102000, - "summary": "Mostly cloudy throughout the day.", - "icon": "partly-cloudy-day", - "sunriseTime": 1554126953, - "sunsetTime": 1554172401, - "moonPhase": 0.89, - "precipIntensity": 0.0009, - "precipIntensityMax": 0.0111, - "precipIntensityMaxTime": 1554184800, - "precipProbability": 0.44, - "precipType": "rain", - "temperatureHigh": 64.89, - "temperatureHighTime": 1554156000, - "temperatureLow": 54.96, - "temperatureLowTime": 1554217200, - "apparentTemperatureHigh": 64.89, - "apparentTemperatureHighTime": 1554156000, - "apparentTemperatureLow": 54.96, - "apparentTemperatureLowTime": 1554217200, - "dewPoint": 52.37, - "humidity": 0.79, - "pressure": 1016, - "windSpeed": 4.52, - "windGust": 15.98, - "windGustTime": 1554163200, - "windBearing": 275, - "cloudCover": 0.79, - "uvIndex": 5, - "uvIndexTime": 1554148800, - "visibility": 9.72, - "ozone": 322.16, - "temperatureMin": 55.16, - "temperatureMinTime": 1554127200, - "temperatureMax": 64.89, - "temperatureMaxTime": 1554156000, - "apparentTemperatureMin": 55.16, - "apparentTemperatureMinTime": 1554127200, - "apparentTemperatureMax": 64.89, - "apparentTemperatureMaxTime": 1554156000 - }, - { - "time": 1554188400, - "summary": "Overcast throughout the day.", - "icon": "cloudy", - "sunriseTime": 1554213263, - "sunsetTime": 1554258855, - "moonPhase": 0.92, - "precipIntensity": 0.0045, - "precipIntensityMax": 0.0155, - "precipIntensityMaxTime": 1554192000, - "precipProbability": 0.84, - "precipType": "rain", - "temperatureHigh": 57.38, - "temperatureHighTime": 1554249600, - "temperatureLow": 53.81, - "temperatureLowTime": 1554300000, - "apparentTemperatureHigh": 57.38, - "apparentTemperatureHighTime": 1554249600, - "apparentTemperatureLow": 53.81, - "apparentTemperatureLowTime": 1554300000, - "dewPoint": 50.25, - "humidity": 0.83, - "pressure": 1013.86, - "windSpeed": 9.9, - "windGust": 19.15, - "windGustTime": 1554206400, - "windBearing": 246, - "cloudCover": 0.96, - "uvIndex": 4, - "uvIndexTime": 1554231600, - "visibility": 8.2, - "ozone": 328.42, - "temperatureMin": 54.65, - "temperatureMinTime": 1554235200, - "temperatureMax": 57.38, - "temperatureMaxTime": 1554249600, - "apparentTemperatureMin": 54.65, - "apparentTemperatureMinTime": 1554235200, - "apparentTemperatureMax": 57.38, - "apparentTemperatureMaxTime": 1554249600 - }, - { - "time": 1554274800, - "summary": "Overcast throughout the day.", - "icon": "cloudy", - "sunriseTime": 1554299572, - "sunsetTime": 1554345309, - "moonPhase": 0.95, - "precipIntensity": 0.0015, - "precipIntensityMax": 0.0057, - "precipIntensityMaxTime": 1554346800, - "precipProbability": 0.51, - "precipType": "rain", - "temperatureHigh": 59.91, - "temperatureHighTime": 1554325200, - "temperatureLow": 52.9, - "temperatureLowTime": 1554368400, - "apparentTemperatureHigh": 59.91, - "apparentTemperatureHighTime": 1554325200, - "apparentTemperatureLow": 52.9, - "apparentTemperatureLowTime": 1554368400, - "dewPoint": 45.81, - "humidity": 0.69, - "pressure": 1016.66, - "windSpeed": 6.89, - "windGust": 23.56, - "windGustTime": 1554357600, - "windBearing": 247, - "cloudCover": 0.98, - "uvIndex": 4, - "uvIndexTime": 1554318000, - "visibility": 9.31, - "ozone": 312.83, - "temperatureMin": 53.81, - "temperatureMinTime": 1554300000, - "temperatureMax": 59.91, - "temperatureMaxTime": 1554325200, - "apparentTemperatureMin": 53.81, - "apparentTemperatureMinTime": 1554300000, - "apparentTemperatureMax": 59.91, - "apparentTemperatureMaxTime": 1554325200 - }, - { - "time": 1554361200, - "summary": "Mostly cloudy throughout the day.", - "icon": "partly-cloudy-day", - "sunriseTime": 1554385882, - "sunsetTime": 1554431764, - "moonPhase": 0.98, - "precipIntensity": 0.0076, - "precipIntensityMax": 0.0162, - "precipIntensityMaxTime": 1554368400, - "precipProbability": 0.95, - "precipType": "rain", - "temperatureHigh": 59.58, - "temperatureHighTime": 1554422400, - "temperatureLow": 56.25, - "temperatureLowTime": 1554444000, - "apparentTemperatureHigh": 59.58, - "apparentTemperatureHighTime": 1554422400, - "apparentTemperatureLow": 56.25, - "apparentTemperatureLowTime": 1554444000, - "dewPoint": 47.68, - "humidity": 0.75, - "pressure": 1017.04, - "windSpeed": 8.96, - "windGust": 28.98, - "windGustTime": 1554390000, - "windBearing": 203, - "cloudCover": 0.94, - "uvIndex": 4, - "uvIndexTime": 1554404400, - "visibility": 5.92, - "ozone": 328.21, - "temperatureMin": 52.9, - "temperatureMinTime": 1554368400, - "temperatureMax": 59.58, - "temperatureMaxTime": 1554422400, - "apparentTemperatureMin": 52.9, - "apparentTemperatureMinTime": 1554368400, - "apparentTemperatureMax": 59.58, - "apparentTemperatureMaxTime": 1554422400 - } - ] - }, - "flags": { - "sources": ["nearest-precip", "nwspa", "cmc", "gfs", "hrrr", "icon", "isd", "madis", "nam", "sref", "darksky"], - "nearest-station": 1.839, - "units": "us" - }, - "offset": -7 -} diff --git a/server/test/services/darksky/fakeDarkSkyService.js b/server/test/services/openweather/fakeOpenWeatherService.js similarity index 92% rename from server/test/services/darksky/fakeDarkSkyService.js rename to server/test/services/openweather/fakeOpenWeatherService.js index 414c1a2e5f..61e6ef04ad 100644 --- a/server/test/services/darksky/fakeDarkSkyService.js +++ b/server/test/services/openweather/fakeOpenWeatherService.js @@ -6,7 +6,7 @@ const service = { humidity: 0.76, pressure: 1019.4, datetime: new Date('2019-03-28T07:50:18.000Z'), - units: 'si', + units: 'metric', wind_speed: 5.25, weather: 'cloud', }), diff --git a/server/test/services/openweather/openweather.test.js b/server/test/services/openweather/openweather.test.js new file mode 100644 index 0000000000..79a04754d7 --- /dev/null +++ b/server/test/services/openweather/openweather.test.js @@ -0,0 +1,271 @@ +const { expect, assert } = require('chai'); +const proxyquire = require('proxyquire').noCallThru(); +const weatherExampleClear = require('./weather-clear.json'); +const weatherExampleClouds = require('./weather-clouds.json'); +const weatherExampleRain = require('./weather-rain.json'); +const weatherExampleSnow = require('./weather-snow.json'); +const weatherExampleDrizzle = require('./weather-drizzle.json'); +const weatherExampleFog = require('./weather-fog.json'); +const weatherExampleThunderStorm = require('./weather-thunderstorm.json'); +const weatherExampleOther = require('./weather-other.json'); + +const workingAxiosClear = { + axios: { + default: { + get: () => ({ data: weatherExampleClear }), + }, + }, +}; + +const workingAxiosClouds = { + axios: { + default: { + get: () => ({ data: weatherExampleClouds }), + }, + }, +}; + +const workingAxiosRain = { + axios: { + default: { + get: () => ({ data: weatherExampleRain }), + }, + }, +}; + +const workingAxiosSnow = { + axios: { + default: { + get: () => ({ data: weatherExampleSnow }), + }, + }, +}; + +const workingAxiosDrizzle = { + axios: { + default: { + get: () => ({ data: weatherExampleDrizzle }), + }, + }, +}; + +const workingAxiosFog = { + axios: { + default: { + get: () => ({ data: weatherExampleFog }), + }, + }, +}; + +const workingAxiosThunderStorm = { + axios: { + default: { + get: () => ({ data: weatherExampleThunderStorm }), + }, + }, +}; + +const workingAxiosOther = { + axios: { + default: { + get: () => ({ data: weatherExampleOther }), + }, + }, +}; + +const brokenAxios = { + axios: { + default: { + get: () => Promise.reject(new Error('broken')), + }, + }, +}; + +const gladys = { + variable: { + getValue: () => Promise.resolve('OPEN_WEATHER_API_KEY'), + }, +}; + +describe('OpenWeatherService', () => { + it('should start service', async () => { + const OpenWeatherService = proxyquire('../../../services/openweather/index', workingAxiosClear); + const openWeatherService = OpenWeatherService(gladys, '35deac79-f295-4adf-8512-f2f48e1ea0f8'); + await openWeatherService.start(); + }); + it('should stop service', async () => { + const OpenWeatherService = proxyquire('../../../services/openweather/index', workingAxiosClear); + const openWeatherService = OpenWeatherService(gladys, '35deac79-f295-4adf-8512-f2f48e1ea0f8'); + await openWeatherService.stop(); + }); + it('should return clear weather formatted', async () => { + const OpenWeatherService = proxyquire('../../../services/openweather/index', workingAxiosClear); + const openWeatherService = OpenWeatherService(gladys, '35deac79-f295-4adf-8512-f2f48e1ea0f8'); + await openWeatherService.start(); + const weather = await openWeatherService.weather.get({ + latitude: 12, + longitude: 10, + }); + expect(weather).to.deep.equal({ + temperature: 17.31, + humidity: 48, + name: 'Belvedere Tiburon', + pressure: 1020, + datetime: new Date('2019-03-28T07:50:18.000Z'), + units: 'metric', + wind_speed: 4.02, + wind_direction: 265, + weather: 'clear', + }); + }); + it('should return error, unable to contact third party provider', async () => { + const OpenWeatherService = proxyquire('../../../services/openweather/index', brokenAxios); + const openWeatherService = OpenWeatherService(gladys, '35deac79-f295-4adf-8512-f2f48e1ea0f8'); + await openWeatherService.start(); + const promise = openWeatherService.weather.get({ + latitude: 12, + longitude: 10, + }); + return assert.isRejected(promise, 'REQUEST_TO_THIRD_PARTY_FAILED'); + }); + it('should return clouds weather formatted', async () => { + const OpenWeatherService = proxyquire('../../../services/openweather/index', workingAxiosClouds); + const openWeatherService = OpenWeatherService(gladys, '35deac79-f295-4adf-8512-f2f48e1ea0f8'); + await openWeatherService.start(); + const weather = await openWeatherService.weather.get({ + latitude: 12, + longitude: 10, + }); + expect(weather).to.deep.equal({ + temperature: 17.31, + humidity: 48, + name: 'Belvedere Tiburon', + pressure: 1020, + datetime: new Date('2019-03-28T07:50:18.000Z'), + units: 'metric', + wind_speed: 4.02, + wind_direction: 265, + weather: 'cloud', + }); + }); + it('should return rain weather formatted', async () => { + const OpenWeatherService = proxyquire('../../../services/openweather/index', workingAxiosRain); + const openWeatherService = OpenWeatherService(gladys, '35deac79-f295-4adf-8512-f2f48e1ea0f8'); + await openWeatherService.start(); + const weather = await openWeatherService.weather.get({ + latitude: 12, + longitude: 10, + }); + expect(weather).to.deep.equal({ + temperature: 17.31, + humidity: 48, + name: 'Belvedere Tiburon', + pressure: 1020, + datetime: new Date('2019-03-28T07:50:18.000Z'), + units: 'metric', + wind_speed: 4.02, + wind_direction: 265, + weather: 'rain', + }); + }); + it('should return snow weather formatted', async () => { + const OpenWeatherService = proxyquire('../../../services/openweather/index', workingAxiosSnow); + const openWeatherService = OpenWeatherService(gladys, '35deac79-f295-4adf-8512-f2f48e1ea0f8'); + await openWeatherService.start(); + const weather = await openWeatherService.weather.get({ + latitude: 12, + longitude: 10, + }); + expect(weather).to.deep.equal({ + temperature: 17.31, + humidity: 48, + name: 'Belvedere Tiburon', + pressure: 1020, + datetime: new Date('2019-03-28T07:50:18.000Z'), + units: 'metric', + wind_speed: 4.02, + wind_direction: 265, + weather: 'snow', + }); + }); + it('should return snow weather formatted', async () => { + const OpenWeatherService = proxyquire('../../../services/openweather/index', workingAxiosDrizzle); + const openWeatherService = OpenWeatherService(gladys, '35deac79-f295-4adf-8512-f2f48e1ea0f8'); + await openWeatherService.start(); + const weather = await openWeatherService.weather.get({ + latitude: 12, + longitude: 10, + }); + expect(weather).to.deep.equal({ + temperature: 17.31, + humidity: 48, + name: 'Belvedere Tiburon', + pressure: 1020, + datetime: new Date('2019-03-28T07:50:18.000Z'), + units: 'metric', + wind_speed: 4.02, + wind_direction: 265, + weather: 'drizzle', + }); + }); + it('should return snow weather formatted', async () => { + const OpenWeatherService = proxyquire('../../../services/openweather/index', workingAxiosFog); + const openWeatherService = OpenWeatherService(gladys, '35deac79-f295-4adf-8512-f2f48e1ea0f8'); + await openWeatherService.start(); + const weather = await openWeatherService.weather.get({ + latitude: 12, + longitude: 10, + }); + expect(weather).to.deep.equal({ + temperature: 17.31, + humidity: 48, + name: 'Belvedere Tiburon', + pressure: 1020, + datetime: new Date('2019-03-28T07:50:18.000Z'), + units: 'metric', + wind_speed: 4.02, + wind_direction: 265, + weather: 'fog', + }); + }); + it('should return snow weather formatted', async () => { + const OpenWeatherService = proxyquire('../../../services/openweather/index', workingAxiosThunderStorm); + const openWeatherService = OpenWeatherService(gladys, '35deac79-f295-4adf-8512-f2f48e1ea0f8'); + await openWeatherService.start(); + const weather = await openWeatherService.weather.get({ + latitude: 12, + longitude: 10, + }); + expect(weather).to.deep.equal({ + temperature: 17.31, + humidity: 48, + name: 'Belvedere Tiburon', + pressure: 1020, + datetime: new Date('2019-03-28T07:50:18.000Z'), + units: 'metric', + wind_speed: 4.02, + wind_direction: 265, + weather: 'thunderstorm', + }); + }); + it('should return snow weather formatted', async () => { + const OpenWeatherService = proxyquire('../../../services/openweather/index', workingAxiosOther); + const openWeatherService = OpenWeatherService(gladys, '35deac79-f295-4adf-8512-f2f48e1ea0f8'); + await openWeatherService.start(); + const weather = await openWeatherService.weather.get({ + latitude: 12, + longitude: 10, + }); + expect(weather).to.deep.equal({ + temperature: 17.31, + humidity: 48, + name: 'Belvedere Tiburon', + pressure: 1020, + datetime: new Date('2019-03-28T07:50:18.000Z'), + units: 'metric', + wind_speed: 4.02, + wind_direction: 265, + weather: 'unknown', + }); + }); +}); diff --git a/server/test/services/openweather/weather-clear.json b/server/test/services/openweather/weather-clear.json new file mode 100644 index 0000000000..2a39746ad9 --- /dev/null +++ b/server/test/services/openweather/weather-clear.json @@ -0,0 +1,43 @@ +{ + "coord": { + "lon": -122.46, + "lat": 37.87 + }, + "weather": [ + { + "id": 800, + "main": "Clear", + "description": "clear sky", + "icon": "01d" + } + ], + "base": "stations", + "main": { + "temp": 17.31, + "feels_like": 13.62, + "temp_min": 13.89, + "temp_max": 20, + "pressure": 1020, + "humidity": 48 + }, + "wind": { + "speed": 4.02, + "deg": 265, + "gust": 6.26 + }, + "clouds": { + "all": 0 + }, + "dt": 1553759418, + "sys": { + "type": 3, + "id": 2002962, + "country": "US", + "sunrise": 1588511452, + "sunset": 1588561339 + }, + "timezone": -25200, + "id": 5327490, + "name": "Belvedere Tiburon", + "cod": 200 +} diff --git a/server/test/services/openweather/weather-clouds.json b/server/test/services/openweather/weather-clouds.json new file mode 100644 index 0000000000..3e78a338e3 --- /dev/null +++ b/server/test/services/openweather/weather-clouds.json @@ -0,0 +1,43 @@ +{ + "coord": { + "lon": -122.46, + "lat": 37.87 + }, + "weather": [ + { + "id": 800, + "main": "Clouds", + "description": "clouds", + "icon": "01d" + } + ], + "base": "stations", + "main": { + "temp": 17.31, + "feels_like": 13.62, + "temp_min": 13.89, + "temp_max": 20, + "pressure": 1020, + "humidity": 48 + }, + "wind": { + "speed": 4.02, + "deg": 265, + "gust": 6.26 + }, + "clouds": { + "all": 0 + }, + "dt": 1553759418, + "sys": { + "type": 3, + "id": 2002962, + "country": "US", + "sunrise": 1588511452, + "sunset": 1588561339 + }, + "timezone": -25200, + "id": 5327490, + "name": "Belvedere Tiburon", + "cod": 200 +} diff --git a/server/test/services/openweather/weather-drizzle.json b/server/test/services/openweather/weather-drizzle.json new file mode 100644 index 0000000000..437bc607a6 --- /dev/null +++ b/server/test/services/openweather/weather-drizzle.json @@ -0,0 +1,43 @@ +{ + "coord": { + "lon": -122.46, + "lat": 37.87 + }, + "weather": [ + { + "id": 800, + "main": "Drizzle", + "description": "drizzle", + "icon": "01d" + } + ], + "base": "stations", + "main": { + "temp": 17.31, + "feels_like": 13.62, + "temp_min": 13.89, + "temp_max": 20, + "pressure": 1020, + "humidity": 48 + }, + "wind": { + "speed": 4.02, + "deg": 265, + "gust": 6.26 + }, + "clouds": { + "all": 0 + }, + "dt": 1553759418, + "sys": { + "type": 3, + "id": 2002962, + "country": "US", + "sunrise": 1588511452, + "sunset": 1588561339 + }, + "timezone": -25200, + "id": 5327490, + "name": "Belvedere Tiburon", + "cod": 200 +} diff --git a/server/test/services/openweather/weather-fog.json b/server/test/services/openweather/weather-fog.json new file mode 100644 index 0000000000..ef9bf53959 --- /dev/null +++ b/server/test/services/openweather/weather-fog.json @@ -0,0 +1,43 @@ +{ + "coord": { + "lon": -122.46, + "lat": 37.87 + }, + "weather": [ + { + "id": 800, + "main": "Mist", + "description": "fog", + "icon": "01d" + } + ], + "base": "stations", + "main": { + "temp": 17.31, + "feels_like": 13.62, + "temp_min": 13.89, + "temp_max": 20, + "pressure": 1020, + "humidity": 48 + }, + "wind": { + "speed": 4.02, + "deg": 265, + "gust": 6.26 + }, + "clouds": { + "all": 0 + }, + "dt": 1553759418, + "sys": { + "type": 3, + "id": 2002962, + "country": "US", + "sunrise": 1588511452, + "sunset": 1588561339 + }, + "timezone": -25200, + "id": 5327490, + "name": "Belvedere Tiburon", + "cod": 200 +} diff --git a/server/test/services/openweather/weather-other.json b/server/test/services/openweather/weather-other.json new file mode 100644 index 0000000000..d553f48c85 --- /dev/null +++ b/server/test/services/openweather/weather-other.json @@ -0,0 +1,43 @@ +{ + "coord": { + "lon": -122.46, + "lat": 37.87 + }, + "weather": [ + { + "id": 800, + "main": "unkown", + "description": "unkown", + "icon": "01d" + } + ], + "base": "stations", + "main": { + "temp": 17.31, + "feels_like": 13.62, + "temp_min": 13.89, + "temp_max": 20, + "pressure": 1020, + "humidity": 48 + }, + "wind": { + "speed": 4.02, + "deg": 265, + "gust": 6.26 + }, + "clouds": { + "all": 0 + }, + "dt": 1553759418, + "sys": { + "type": 3, + "id": 2002962, + "country": "US", + "sunrise": 1588511452, + "sunset": 1588561339 + }, + "timezone": -25200, + "id": 5327490, + "name": "Belvedere Tiburon", + "cod": 200 +} diff --git a/server/test/services/openweather/weather-rain.json b/server/test/services/openweather/weather-rain.json new file mode 100644 index 0000000000..6c054a57c1 --- /dev/null +++ b/server/test/services/openweather/weather-rain.json @@ -0,0 +1,43 @@ +{ + "coord": { + "lon": -122.46, + "lat": 37.87 + }, + "weather": [ + { + "id": 800, + "main": "Rain", + "description": "rain", + "icon": "01d" + } + ], + "base": "stations", + "main": { + "temp": 17.31, + "feels_like": 13.62, + "temp_min": 13.89, + "temp_max": 20, + "pressure": 1020, + "humidity": 48 + }, + "wind": { + "speed": 4.02, + "deg": 265, + "gust": 6.26 + }, + "clouds": { + "all": 0 + }, + "dt": 1553759418, + "sys": { + "type": 3, + "id": 2002962, + "country": "US", + "sunrise": 1588511452, + "sunset": 1588561339 + }, + "timezone": -25200, + "id": 5327490, + "name": "Belvedere Tiburon", + "cod": 200 +} diff --git a/server/test/services/openweather/weather-snow.json b/server/test/services/openweather/weather-snow.json new file mode 100644 index 0000000000..901f84ed55 --- /dev/null +++ b/server/test/services/openweather/weather-snow.json @@ -0,0 +1,43 @@ +{ + "coord": { + "lon": -122.46, + "lat": 37.87 + }, + "weather": [ + { + "id": 800, + "main": "Snow", + "description": "snow", + "icon": "01d" + } + ], + "base": "stations", + "main": { + "temp": 17.31, + "feels_like": 13.62, + "temp_min": 13.89, + "temp_max": 20, + "pressure": 1020, + "humidity": 48 + }, + "wind": { + "speed": 4.02, + "deg": 265, + "gust": 6.26 + }, + "clouds": { + "all": 0 + }, + "dt": 1553759418, + "sys": { + "type": 3, + "id": 2002962, + "country": "US", + "sunrise": 1588511452, + "sunset": 1588561339 + }, + "timezone": -25200, + "id": 5327490, + "name": "Belvedere Tiburon", + "cod": 200 +} diff --git a/server/test/services/openweather/weather-thunderstorm.json b/server/test/services/openweather/weather-thunderstorm.json new file mode 100644 index 0000000000..dcc4dc4722 --- /dev/null +++ b/server/test/services/openweather/weather-thunderstorm.json @@ -0,0 +1,43 @@ +{ + "coord": { + "lon": -122.46, + "lat": 37.87 + }, + "weather": [ + { + "id": 800, + "main": "Thunderstorm", + "description": "thunderstorm", + "icon": "01d" + } + ], + "base": "stations", + "main": { + "temp": 17.31, + "feels_like": 13.62, + "temp_min": 13.89, + "temp_max": 20, + "pressure": 1020, + "humidity": 48 + }, + "wind": { + "speed": 4.02, + "deg": 265, + "gust": 6.26 + }, + "clouds": { + "all": 0 + }, + "dt": 1553759418, + "sys": { + "type": 3, + "id": 2002962, + "country": "US", + "sunrise": 1588511452, + "sunset": 1588561339 + }, + "timezone": -25200, + "id": 5327490, + "name": "Belvedere Tiburon", + "cod": 200 +}