Add display currency setting to CoinMarketCap sensor (#10093)

* Add support for different display currencies in CoinMarkerCap sensor.

* Add test for CoinMarketCap sensor.

* Add test dependency to gen_requirements_all.

* Fix review comments: use string formatting and less string case chanes.
This commit is contained in:
Richard Leurs 2017-10-26 18:49:17 +02:00 committed by Fabian Affolter
parent 2561efe45d
commit c2ef22bd08
7 changed files with 98 additions and 15 deletions

View File

@ -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

View File

@ -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)

View File

@ -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'

View File

@ -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

View File

@ -39,6 +39,7 @@ TEST_REQUIREMENTS = (
'aioautomatic',
'aiohttp_cors',
'apns2',
'coinmarketcap',
'defusedxml',
'dsmr_parser',
'ephem',

View File

@ -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'

21
tests/fixtures/coinmarketcap.json vendored Normal file
View File

@ -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"
}
]