Change name of Forecast.io platform to Dark Sky (#3698)

* Rename Forecast.io platform to Dark Sky

* Upgrade to python-forecastio to 1.3.5

* Update to reflect name change (Forecast.io -> Dark Sky)

* Rename forecast to darksky
This commit is contained in:
Fabian Affolter 2016-10-05 21:42:58 +02:00 committed by GitHub
parent cb3a78b330
commit a94571fd10
5 changed files with 38 additions and 32 deletions

View File

@ -220,6 +220,7 @@ omit =
homeassistant/components/sensor/bom.py homeassistant/components/sensor/bom.py
homeassistant/components/sensor/coinmarketcap.py homeassistant/components/sensor/coinmarketcap.py
homeassistant/components/sensor/cpuspeed.py homeassistant/components/sensor/cpuspeed.py
homeassistant/components/sensor/darksky.py
homeassistant/components/sensor/deutsche_bahn.py homeassistant/components/sensor/deutsche_bahn.py
homeassistant/components/sensor/dht.py homeassistant/components/sensor/dht.py
homeassistant/components/sensor/dte_energy_bridge.py homeassistant/components/sensor/dte_energy_bridge.py
@ -229,7 +230,6 @@ omit =
homeassistant/components/sensor/fastdotcom.py homeassistant/components/sensor/fastdotcom.py
homeassistant/components/sensor/fitbit.py homeassistant/components/sensor/fitbit.py
homeassistant/components/sensor/fixer.py homeassistant/components/sensor/fixer.py
homeassistant/components/sensor/forecast.py
homeassistant/components/sensor/fritzbox_callmonitor.py homeassistant/components/sensor/fritzbox_callmonitor.py
homeassistant/components/sensor/glances.py homeassistant/components/sensor/glances.py
homeassistant/components/sensor/google_travel_time.py homeassistant/components/sensor/google_travel_time.py

View File

@ -1,8 +1,8 @@
""" """
Support for Forecast.io weather service. Support for Dark Sky weather service.
For more details about this platform, please refer to the documentation at For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/sensor.forecast/ https://home-assistant.io/components/sensor.darksky/
""" """
import logging import logging
from datetime import timedelta from datetime import timedelta
@ -18,14 +18,14 @@ from homeassistant.helpers.entity import Entity
from homeassistant.util import Throttle from homeassistant.util import Throttle
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['python-forecastio==1.3.4'] REQUIREMENTS = ['python-forecastio==1.3.5']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
CONF_UNITS = 'units' CONF_UNITS = 'units'
CONF_UPDATE_INTERVAL = 'update_interval' CONF_UPDATE_INTERVAL = 'update_interval'
DEFAULT_NAME = 'Forecast.io' DEFAULT_NAME = 'Dark Sky'
# Sensor types are defined like so: # Sensor types are defined like so:
# Name, si unit, us unit, ca unit, uk unit, uk2 unit # Name, si unit, us unit, ca unit, uk unit, uk2 unit
@ -91,7 +91,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
# pylint: disable=too-many-arguments # pylint: disable=too-many-arguments
def setup_platform(hass, config, add_devices, discovery_info=None): def setup_platform(hass, config, add_devices, discovery_info=None):
"""Setup the Forecast.io sensor.""" """Setup the Dark Sky sensor."""
# Validate the configuration # Validate the configuration
if None in (hass.config.latitude, hass.config.longitude): if None in (hass.config.latitude, hass.config.longitude):
_LOGGER.error("Latitude or longitude not set in Home Assistant config") _LOGGER.error("Latitude or longitude not set in Home Assistant config")
@ -107,7 +107,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
# Create a data fetcher to support all of the configured sensors. Then make # Create a data fetcher to support all of the configured sensors. Then make
# the first call to init the data and confirm we can connect. # the first call to init the data and confirm we can connect.
try: try:
forecast_data = ForeCastData( forecast_data = DarkSkyData(
api_key=config.get(CONF_API_KEY, None), api_key=config.get(CONF_API_KEY, None),
latitude=hass.config.latitude, latitude=hass.config.latitude,
longitude=hass.config.longitude, longitude=hass.config.longitude,
@ -122,14 +122,14 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
sensors = [] sensors = []
for variable in config[CONF_MONITORED_CONDITIONS]: for variable in config[CONF_MONITORED_CONDITIONS]:
sensors.append(ForeCastSensor(forecast_data, variable, name)) sensors.append(DarkSkySensor(forecast_data, variable, name))
add_devices(sensors) add_devices(sensors)
# pylint: disable=too-few-public-methods # pylint: disable=too-few-public-methods
class ForeCastSensor(Entity): class DarkSkySensor(Entity):
"""Implementation of a Forecast.io sensor.""" """Implementation of a Dark Sky sensor."""
def __init__(self, forecast_data, sensor_type, name): def __init__(self, forecast_data, sensor_type, name):
"""Initialize the sensor.""" """Initialize the sensor."""
@ -180,10 +180,10 @@ class ForeCastSensor(Entity):
# pylint: disable=too-many-branches,too-many-statements # pylint: disable=too-many-branches,too-many-statements
def update(self): def update(self):
"""Get the latest data from Forecast.io and updates the states.""" """Get the latest data from Dark Sky and updates the states."""
# Call the API for new forecast data. Each sensor will re-trigger this # Call the API for new forecast data. Each sensor will re-trigger this
# same exact call, but thats fine. We cache results for a short period # same exact call, but that's fine. We cache results for a short period
# of time to prevent hitting API limits. Note that forecast.io will # of time to prevent hitting API limits. Note that Dark Sky will
# charge users for too many calls in 1 day, so take care when updating. # charge users for too many calls in 1 day, so take care when updating.
self.forecast_data.update() self.forecast_data.update()
self.update_unit_of_measurement() self.update_unit_of_measurement()
@ -197,7 +197,8 @@ class ForeCastSensor(Entity):
hourly = self.forecast_data.data_hourly hourly = self.forecast_data.data_hourly
self._state = getattr(hourly, 'summary', '') self._state = getattr(hourly, 'summary', '')
elif self.type in ['daily_summary', elif self.type in ['daily_summary',
'temperature_min', 'temperature_max', 'temperature_min',
'temperature_max',
'apparent_temperature_min', 'apparent_temperature_min',
'apparent_temperature_max', 'apparent_temperature_max',
'precip_intensity_max']: 'precip_intensity_max']:
@ -247,11 +248,10 @@ def convert_to_camel(data):
return components[0] + "".join(x.title() for x in components[1:]) return components[0] + "".join(x.title() for x in components[1:])
class ForeCastData(object): class DarkSkyData(object):
"""Gets the latest data from Forecast.io.""" """Get the latest data from Darksky."""
# pylint: disable=too-many-instance-attributes # pylint: disable=too-many-instance-attributes
def __init__(self, api_key, latitude, longitude, units, interval): def __init__(self, api_key, latitude, longitude, units, interval):
"""Initialize the data object.""" """Initialize the data object."""
self._api_key = api_key self._api_key = api_key
@ -276,14 +276,14 @@ class ForeCastData(object):
self.update() self.update()
def _update(self): def _update(self):
"""Get the latest data from Forecast.io.""" """Get the latest data from Dark Sky."""
import forecastio import forecastio
try: try:
self.data = forecastio.load_forecast( self.data = forecastio.load_forecast(
self._api_key, self.latitude, self.longitude, units=self.units) self._api_key, self.latitude, self.longitude, units=self.units)
except (ConnectError, HTTPError, Timeout, ValueError) as error: except (ConnectError, HTTPError, Timeout, ValueError) as error:
raise ValueError("Unable to init Forecast.io. - %s", error) raise ValueError("Unable to init Dark Sky. %s", error)
self.unit_system = self.data.json['flags']['units'] self.unit_system = self.data.json['flags']['units']
def _update_currently(self): def _update_currently(self):

View File

@ -373,8 +373,8 @@ pysnmp==4.3.2
# homeassistant.components.digital_ocean # homeassistant.components.digital_ocean
python-digitalocean==1.9.0 python-digitalocean==1.9.0
# homeassistant.components.sensor.forecast # homeassistant.components.sensor.darksky
python-forecastio==1.3.4 python-forecastio==1.3.5
# homeassistant.components.sensor.hp_ilo # homeassistant.components.sensor.hp_ilo
python-hpilo==3.8 python-hpilo==3.8

View File

@ -1,4 +1,4 @@
"""The tests for the forecast.io platform.""" """The tests for the Dark Sky platform."""
import re import re
import unittest import unittest
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
@ -8,13 +8,14 @@ from requests.exceptions import HTTPError
import requests_mock import requests_mock
from datetime import timedelta from datetime import timedelta
from homeassistant.components.sensor import forecast from homeassistant.components.sensor import darksky
from homeassistant.bootstrap import setup_component
from tests.common import load_fixture, get_test_home_assistant from tests.common import load_fixture, get_test_home_assistant
class TestForecastSetup(unittest.TestCase): class TestDarkSkySetup(unittest.TestCase):
"""Test the forecast.io platform.""" """Test the Dark Sky platform."""
def setUp(self): def setUp(self):
"""Initialize values for this testcase class.""" """Initialize values for this testcase class."""
@ -30,33 +31,38 @@ class TestForecastSetup(unittest.TestCase):
self.hass.config.latitude = self.lat self.hass.config.latitude = self.lat
self.hass.config.longitude = self.lon self.hass.config.longitude = self.lon
def test_setup_with_config(self):
"""Test the platform setup with configuration."""
self.assertTrue(
setup_component(self.hass, 'sensor', {'darksky': self.config}))
def test_setup_no_latitude(self): def test_setup_no_latitude(self):
"""Test that the component is not loaded without required config.""" """Test that the component is not loaded without required config."""
self.hass.config.latitude = None self.hass.config.latitude = None
self.assertFalse(forecast.setup_platform(self.hass, {}, MagicMock())) self.assertFalse(darksky.setup_platform(self.hass, {}, MagicMock()))
@patch('forecastio.api.get_forecast') @patch('forecastio.api.get_forecast')
def test_setup_bad_api_key(self, mock_get_forecast): def test_setup_bad_api_key(self, mock_get_forecast):
"""Test for handling a bad API key.""" """Test for handling a bad API key."""
# The forecast API wrapper that we use raises an HTTP error # The Dark Sky API wrapper that we use raises an HTTP error
# when you try to use a bad (or no) API key. # when you try to use a bad (or no) API key.
url = 'https://api.forecast.io/forecast/{}/{},{}?units=auto'.format( url = 'https://api.darksky.net/forecast/{}/{},{}?units=auto'.format(
self.key, str(self.lat), str(self.lon) self.key, str(self.lat), str(self.lon)
) )
msg = '400 Client Error: Bad Request for url: {}'.format(url) msg = '400 Client Error: Bad Request for url: {}'.format(url)
mock_get_forecast.side_effect = HTTPError(msg,) mock_get_forecast.side_effect = HTTPError(msg,)
response = forecast.setup_platform(self.hass, self.config, MagicMock()) response = darksky.setup_platform(self.hass, self.config, MagicMock())
self.assertFalse(response) self.assertFalse(response)
@requests_mock.Mocker() @requests_mock.Mocker()
@patch('forecastio.api.get_forecast', wraps=forecastio.api.get_forecast) @patch('forecastio.api.get_forecast', wraps=forecastio.api.get_forecast)
def test_setup(self, m, mock_get_forecast): def test_setup(self, m, mock_get_forecast):
"""Test for successfully setting up the forecast.io platform.""" """Test for successfully setting up the forecast.io platform."""
uri = ('https://api.forecast.io\/forecast\/(\w+)\/' uri = ('https://api.darksky.net\/forecast\/(\w+)\/'
'(-?\d+\.?\d*),(-?\d+\.?\d*)') '(-?\d+\.?\d*),(-?\d+\.?\d*)')
m.get(re.compile(uri), m.get(re.compile(uri),
text=load_fixture('forecast.json')) text=load_fixture('darksky.json'))
forecast.setup_platform(self.hass, self.config, MagicMock()) darksky.setup_platform(self.hass, self.config, MagicMock())
self.assertTrue(mock_get_forecast.called) self.assertTrue(mock_get_forecast.called)
self.assertEqual(mock_get_forecast.call_count, 1) self.assertEqual(mock_get_forecast.call_count, 1)