""" homeassistant.components.sensor.bitcoin ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Bitcoin information service that uses blockchain.info and its online wallet. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.bitcoin/ """ import logging from datetime import timedelta from homeassistant.util import Throttle from homeassistant.helpers.entity import Entity REQUIREMENTS = ['blockchain==1.2.1'] _LOGGER = logging.getLogger(__name__) OPTION_TYPES = { 'wallet': ['Wallet balance', 'BTC'], 'exchangerate': ['Exchange rate (1 BTC)', None], 'trade_volume_btc': ['Trade volume', 'BTC'], 'miners_revenue_usd': ['Miners revenue', 'USD'], 'btc_mined': ['Mined', 'BTC'], 'trade_volume_usd': ['Trade volume', 'USD'], 'difficulty': ['Difficulty', None], 'minutes_between_blocks': ['Time between Blocks', 'min'], 'number_of_transactions': ['No. of Transactions', None], 'hash_rate': ['Hash rate', 'PH/s'], 'timestamp': ['Timestamp', None], 'mined_blocks': ['Minded Blocks', None], 'blocks_size': ['Block size', None], 'total_fees_btc': ['Total fees', 'BTC'], 'total_btc_sent': ['Total sent', 'BTC'], 'estimated_btc_sent': ['Estimated sent', 'BTC'], 'total_btc': ['Total', 'BTC'], 'total_blocks': ['Total Blocks', None], 'next_retarget': ['Next retarget', None], 'estimated_transaction_volume_usd': ['Est. Transaction volume', 'USD'], 'miners_revenue_btc': ['Miners revenue', 'BTC'], 'market_price_usd': ['Market price', 'USD'] } ICON = 'mdi:currency-btc' # Return cached results if last scan was less then this time ago MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=120) def setup_platform(hass, config, add_devices, discovery_info=None): """ Get the Bitcoin sensor. """ from blockchain.wallet import Wallet from blockchain import exchangerates, exceptions wallet_id = config.get('wallet', None) password = config.get('password', None) currency = config.get('currency', 'USD') if currency not in exchangerates.get_ticker(): _LOGGER.error('Currency "%s" is not available. Using "USD".', currency) currency = 'USD' wallet = Wallet(wallet_id, password) try: wallet.get_balance() except exceptions.APIException as error: _LOGGER.error(error) wallet = None data = BitcoinData() dev = [] if wallet is not None and password is not None: dev.append(BitcoinSensor(data, 'wallet', currency, wallet)) for variable in config['display_options']: if variable not in OPTION_TYPES: _LOGGER.error('Option type: "%s" does not exist', variable) else: dev.append(BitcoinSensor(data, variable, currency)) add_devices(dev) # pylint: disable=too-few-public-methods class BitcoinSensor(Entity): """ Implements a Bitcoin sensor. """ def __init__(self, data, option_type, currency, wallet=''): self.data = data self._name = OPTION_TYPES[option_type][0] self._unit_of_measurement = OPTION_TYPES[option_type][1] self._currency = currency self._wallet = wallet self.type = option_type self._state = None self.update() @property def name(self): """ Returns the name of the device. """ return self._name @property def state(self): """ Returns the state of the device. """ return self._state @property def unit_of_measurement(self): return self._unit_of_measurement @property def icon(self): """ Icon to use in the frontend, if any. """ return ICON # pylint: disable=too-many-branches def update(self): """ Gets the latest data and updates the states. """ self.data.update() stats = self.data.stats ticker = self.data.ticker # pylint: disable=no-member if self.type == 'wallet' and self._wallet is not None: self._state = '{0:.8f}'.format(self._wallet.get_balance() * 0.00000001) elif self.type == 'exchangerate': self._state = ticker[self._currency].p15min self._unit_of_measurement = self._currency elif self.type == 'trade_volume_btc': self._state = '{0:.1f}'.format(stats.trade_volume_btc) elif self.type == 'miners_revenue_usd': self._state = '{0:.0f}'.format(stats.miners_revenue_usd) elif self.type == 'btc_mined': self._state = '{}'.format(stats.btc_mined * 0.00000001) elif self.type == 'trade_volume_usd': self._state = '{0:.1f}'.format(stats.trade_volume_usd) elif self.type == 'difficulty': self._state = '{0:.0f}'.format(stats.difficulty) elif self.type == 'minutes_between_blocks': self._state = '{0:.2f}'.format(stats.minutes_between_blocks) elif self.type == 'number_of_transactions': self._state = '{}'.format(stats.number_of_transactions) elif self.type == 'hash_rate': self._state = '{0:.1f}'.format(stats.hash_rate * 0.000001) elif self.type == 'timestamp': self._state = stats.timestamp elif self.type == 'mined_blocks': self._state = '{}'.format(stats.mined_blocks) elif self.type == 'blocks_size': self._state = '{0:.1f}'.format(stats.blocks_size) elif self.type == 'total_fees_btc': self._state = '{0:.2f}'.format(stats.total_fees_btc * 0.00000001) elif self.type == 'total_btc_sent': self._state = '{0:.2f}'.format(stats.total_btc_sent * 0.00000001) elif self.type == 'estimated_btc_sent': self._state = '{0:.2f}'.format(stats.estimated_btc_sent * 0.00000001) elif self.type == 'total_btc': self._state = '{0:.2f}'.format(stats.total_btc * 0.00000001) elif self.type == 'total_blocks': self._state = '{0:.2f}'.format(stats.total_blocks) elif self.type == 'next_retarget': self._state = '{0:.2f}'.format(stats.next_retarget) elif self.type == 'estimated_transaction_volume_usd': self._state = '{0:.2f}'.format( stats.estimated_transaction_volume_usd) elif self.type == 'miners_revenue_btc': self._state = '{0:.1f}'.format(stats.miners_revenue_btc * 0.00000001) elif self.type == 'market_price_usd': self._state = '{0:.2f}'.format(stats.market_price_usd) class BitcoinData(object): """ Gets the latest data and updates the states. """ def __init__(self): self.stats = None self.ticker = None @Throttle(MIN_TIME_BETWEEN_UPDATES) def update(self): """ Gets the latest data from blockchain.info. """ from blockchain import statistics, exchangerates self.stats = statistics.get() self.ticker = exchangerates.get_ticker()