diff --git a/.coveragerc b/.coveragerc index 33e238de0e7..cca5f723e73 100644 --- a/.coveragerc +++ b/.coveragerc @@ -465,7 +465,6 @@ omit = homeassistant/components/sensor/broadlink.py homeassistant/components/sensor/buienradar.py homeassistant/components/sensor/citybikes.py - homeassistant/components/sensor/coinmarketcap.py homeassistant/components/sensor/cert_expiry.py homeassistant/components/sensor/comed_hourly_pricing.py homeassistant/components/sensor/cpuspeed.py diff --git a/homeassistant/components/sensor/coinmarketcap.py b/homeassistant/components/sensor/coinmarketcap.py index 616b30abf2b..dc5048a8176 100644 --- a/homeassistant/components/sensor/coinmarketcap.py +++ b/homeassistant/components/sensor/coinmarketcap.py @@ -12,26 +12,28 @@ import voluptuous as vol import homeassistant.helpers.config_validation as cv from homeassistant.components.sensor import PLATFORM_SCHEMA -from homeassistant.const import ATTR_ATTRIBUTION, CONF_CURRENCY +from homeassistant.const import ( + ATTR_ATTRIBUTION, CONF_CURRENCY, CONF_DISPLAY_CURRENCY) from homeassistant.helpers.entity import Entity REQUIREMENTS = ['coinmarketcap==4.1.1'] _LOGGER = logging.getLogger(__name__) -ATTR_24H_VOLUME_USD = '24h_volume_usd' +ATTR_24H_VOLUME = '24h_volume' ATTR_AVAILABLE_SUPPLY = 'available_supply' -ATTR_MARKET_CAP = 'market_cap_usd' +ATTR_MARKET_CAP = 'market_cap' ATTR_NAME = 'name' ATTR_PERCENT_CHANGE_24H = 'percent_change_24h' ATTR_PERCENT_CHANGE_7D = 'percent_change_7d' -ATTR_PRICE = 'price_usd' +ATTR_PRICE = 'price' ATTR_SYMBOL = 'symbol' ATTR_TOTAL_SUPPLY = 'total_supply' CONF_ATTRIBUTION = "Data provided by CoinMarketCap" DEFAULT_CURRENCY = 'bitcoin' +DEFAULT_DISPLAY_CURRENCY = 'USD' ICON = 'mdi:currency-usd' @@ -39,21 +41,26 @@ SCAN_INTERVAL = timedelta(minutes=15) PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_CURRENCY, default=DEFAULT_CURRENCY): cv.string, + vol.Optional(CONF_DISPLAY_CURRENCY, default=DEFAULT_DISPLAY_CURRENCY): + cv.string, }) def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the CoinMarketCap sensor.""" currency = config.get(CONF_CURRENCY) + display_currency = config.get(CONF_DISPLAY_CURRENCY).lower() try: - CoinMarketCapData(currency).update() + CoinMarketCapData(currency, display_currency).update() except HTTPError: - _LOGGER.warning("Currency %s is not available. Using bitcoin", - currency) + _LOGGER.warning("Currency %s or display currency %s is not available. " + "Using bitcoin and USD.", currency, display_currency) currency = DEFAULT_CURRENCY + display_currency = DEFAULT_DISPLAY_CURRENCY - add_devices([CoinMarketCapSensor(CoinMarketCapData(currency))], True) + add_devices([CoinMarketCapSensor( + CoinMarketCapData(currency, display_currency))], True) class CoinMarketCapSensor(Entity): @@ -63,7 +70,7 @@ class CoinMarketCapSensor(Entity): """Initialize the sensor.""" self.data = data self._ticker = None - self._unit_of_measurement = 'USD' + self._unit_of_measurement = self.data.display_currency.upper() @property def name(self): @@ -73,7 +80,8 @@ class CoinMarketCapSensor(Entity): @property def state(self): """Return the state of the sensor.""" - return round(float(self._ticker.get('price_usd')), 2) + return round(float(self._ticker.get( + 'price_{}'.format(self.data.display_currency))), 2) @property def unit_of_measurement(self): @@ -89,10 +97,12 @@ class CoinMarketCapSensor(Entity): def device_state_attributes(self): """Return the state attributes of the sensor.""" return { - ATTR_24H_VOLUME_USD: self._ticker.get('24h_volume_usd'), + ATTR_24H_VOLUME: self._ticker.get( + '24h_volume_{}'.format(self.data.display_currency)), ATTR_ATTRIBUTION: CONF_ATTRIBUTION, ATTR_AVAILABLE_SUPPLY: self._ticker.get('available_supply'), - ATTR_MARKET_CAP: self._ticker.get('market_cap_usd'), + ATTR_MARKET_CAP: self._ticker.get( + 'market_cap_{}'.format(self.data.display_currency)), ATTR_PERCENT_CHANGE_24H: self._ticker.get('percent_change_24h'), ATTR_PERCENT_CHANGE_7D: self._ticker.get('percent_change_7d'), ATTR_SYMBOL: self._ticker.get('symbol'), @@ -108,12 +118,16 @@ class CoinMarketCapSensor(Entity): class CoinMarketCapData(object): """Get the latest data and update the states.""" - def __init__(self, currency): + def __init__(self, currency, display_currency): """Initialize the data object.""" self.currency = currency + self.display_currency = display_currency self.ticker = None def update(self): """Get the latest data from blockchain.info.""" from coinmarketcap import Market - self.ticker = Market().ticker(self.currency, limit=1) + self.ticker = Market().ticker( + self.currency, + limit=1, + convert=self.display_currency) diff --git a/homeassistant/const.py b/homeassistant/const.py index 6436a2389af..5d871816439 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -89,6 +89,7 @@ CONF_DEVICES = 'devices' CONF_DISARM_AFTER_TRIGGER = 'disarm_after_trigger' CONF_DISCOVERY = 'discovery' CONF_DISPLAY_OPTIONS = 'display_options' +CONF_DISPLAY_CURRENCY = 'display_currency' CONF_DOMAIN = 'domain' CONF_DOMAINS = 'domains' CONF_EFFECT = 'effect' diff --git a/requirements_test_all.txt b/requirements_test_all.txt index df9c49c682e..7bca569060d 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -36,6 +36,9 @@ aiohttp_cors==0.5.3 # homeassistant.components.notify.apns apns2==0.1.1 +# homeassistant.components.sensor.coinmarketcap +coinmarketcap==4.1.1 + # homeassistant.components.device_tracker.upc_connect defusedxml==0.5.0 diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py index 33f5b57bf93..63c4ab2c90d 100755 --- a/script/gen_requirements_all.py +++ b/script/gen_requirements_all.py @@ -39,6 +39,7 @@ TEST_REQUIREMENTS = ( 'aioautomatic', 'aiohttp_cors', 'apns2', + 'coinmarketcap', 'defusedxml', 'dsmr_parser', 'ephem', diff --git a/tests/components/sensor/test_coinmarketcap.py b/tests/components/sensor/test_coinmarketcap.py new file mode 100644 index 00000000000..15c254bfb27 --- /dev/null +++ b/tests/components/sensor/test_coinmarketcap.py @@ -0,0 +1,44 @@ +"""Tests for the CoinMarketCap sensor platform.""" +import json + +import unittest +from unittest.mock import patch + +import homeassistant.components.sensor as sensor +from homeassistant.setup import setup_component +from tests.common import ( + get_test_home_assistant, load_fixture, assert_setup_component) + +VALID_CONFIG = { + 'platform': 'coinmarketcap', + 'currency': 'ethereum', + 'display_currency': 'EUR', +} + + +class TestCoinMarketCapSensor(unittest.TestCase): + """Test the CoinMarketCap sensor.""" + + def setUp(self): + """Set up things to be run when tests are started.""" + self.hass = get_test_home_assistant() + self.config = VALID_CONFIG + + def tearDown(self): + """Stop everything that was started.""" + self.hass.stop() + + @patch('coinmarketcap.Market.ticker', + return_value=json.loads(load_fixture('coinmarketcap.json'))) + def test_setup(self, mock_request): + """Test the setup with custom settings.""" + with assert_setup_component(1, sensor.DOMAIN): + assert setup_component(self.hass, sensor.DOMAIN, { + 'sensor': VALID_CONFIG}) + + state = self.hass.states.get('sensor.ethereum') + assert state is not None + + assert state.state == '240.47' + assert state.attributes.get('symbol') == 'ETH' + assert state.attributes.get('unit_of_measurement') == 'EUR' diff --git a/tests/fixtures/coinmarketcap.json b/tests/fixtures/coinmarketcap.json new file mode 100644 index 00000000000..20f5e4fe91e --- /dev/null +++ b/tests/fixtures/coinmarketcap.json @@ -0,0 +1,21 @@ +[ + { + "id": "ethereum", + "name": "Ethereum", + "symbol": "ETH", + "rank": "2", + "price_usd": "282.423", + "price_btc": "0.048844", + "24h_volume_usd": "407024000.0", + "market_cap_usd": "26908205315.0", + "available_supply": "95276253.0", + "total_supply": "95276253.0", + "percent_change_1h": "0.06", + "percent_change_24h": "-4.57", + "percent_change_7d": "-16.39", + "last_updated": "1508776751", + "price_eur": "240.473299695", + "24h_volume_eur": "346566690.16", + "market_cap_eur": "22911395039.0" + } +] \ No newline at end of file