Add option for exchange rate sensor precision to Coinbase (#68792)
* Add user option for precision to exchange rate sensors * Add tests * Add strings
This commit is contained in:
parent
259b069dd9
commit
bb7593351b
6 changed files with 36 additions and 13 deletions
|
@ -18,6 +18,8 @@ from .const import (
|
||||||
API_TYPE_VAULT,
|
API_TYPE_VAULT,
|
||||||
CONF_CURRENCIES,
|
CONF_CURRENCIES,
|
||||||
CONF_EXCHANGE_BASE,
|
CONF_EXCHANGE_BASE,
|
||||||
|
CONF_EXCHANGE_PRECISION,
|
||||||
|
CONF_EXCHANGE_PRECISION_DEFAULT,
|
||||||
CONF_EXCHANGE_RATES,
|
CONF_EXCHANGE_RATES,
|
||||||
CONF_OPTIONS,
|
CONF_OPTIONS,
|
||||||
CONF_YAML_API_TOKEN,
|
CONF_YAML_API_TOKEN,
|
||||||
|
@ -177,6 +179,9 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
||||||
default_currencies = self.config_entry.options.get(CONF_CURRENCIES, [])
|
default_currencies = self.config_entry.options.get(CONF_CURRENCIES, [])
|
||||||
default_exchange_rates = self.config_entry.options.get(CONF_EXCHANGE_RATES, [])
|
default_exchange_rates = self.config_entry.options.get(CONF_EXCHANGE_RATES, [])
|
||||||
default_exchange_base = self.config_entry.options.get(CONF_EXCHANGE_BASE, "USD")
|
default_exchange_base = self.config_entry.options.get(CONF_EXCHANGE_BASE, "USD")
|
||||||
|
default_exchange_precision = self.config_entry.options.get(
|
||||||
|
CONF_EXCHANGE_PRECISION, CONF_EXCHANGE_PRECISION_DEFAULT
|
||||||
|
)
|
||||||
|
|
||||||
if user_input is not None:
|
if user_input is not None:
|
||||||
# Pass back user selected options, even if bad
|
# Pass back user selected options, even if bad
|
||||||
|
@ -189,6 +194,9 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
||||||
if CONF_EXCHANGE_RATES in user_input:
|
if CONF_EXCHANGE_RATES in user_input:
|
||||||
default_exchange_base = user_input[CONF_EXCHANGE_BASE]
|
default_exchange_base = user_input[CONF_EXCHANGE_BASE]
|
||||||
|
|
||||||
|
if CONF_EXCHANGE_PRECISION in user_input:
|
||||||
|
default_exchange_precision = user_input[CONF_EXCHANGE_PRECISION]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await validate_options(self.hass, self.config_entry, user_input)
|
await validate_options(self.hass, self.config_entry, user_input)
|
||||||
except CurrencyUnavailable:
|
except CurrencyUnavailable:
|
||||||
|
@ -217,6 +225,9 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
||||||
CONF_EXCHANGE_BASE,
|
CONF_EXCHANGE_BASE,
|
||||||
default=default_exchange_base,
|
default=default_exchange_base,
|
||||||
): vol.In(WALLETS),
|
): vol.In(WALLETS),
|
||||||
|
vol.Optional(
|
||||||
|
CONF_EXCHANGE_PRECISION, default=default_exchange_precision
|
||||||
|
): int,
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
errors=errors,
|
errors=errors,
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
CONF_CURRENCIES = "account_balance_currencies"
|
CONF_CURRENCIES = "account_balance_currencies"
|
||||||
CONF_EXCHANGE_BASE = "exchange_base"
|
CONF_EXCHANGE_BASE = "exchange_base"
|
||||||
CONF_EXCHANGE_RATES = "exchange_rate_currencies"
|
CONF_EXCHANGE_RATES = "exchange_rate_currencies"
|
||||||
|
CONF_EXCHANGE_PRECISION = "exchange_rate_precision"
|
||||||
|
CONF_EXCHANGE_PRECISION_DEFAULT = 2
|
||||||
CONF_OPTIONS = "options"
|
CONF_OPTIONS = "options"
|
||||||
CONF_TITLE = "title"
|
CONF_TITLE = "title"
|
||||||
DOMAIN = "coinbase"
|
DOMAIN = "coinbase"
|
||||||
|
|
|
@ -22,6 +22,8 @@ from .const import (
|
||||||
API_RESOURCE_TYPE,
|
API_RESOURCE_TYPE,
|
||||||
API_TYPE_VAULT,
|
API_TYPE_VAULT,
|
||||||
CONF_CURRENCIES,
|
CONF_CURRENCIES,
|
||||||
|
CONF_EXCHANGE_PRECISION,
|
||||||
|
CONF_EXCHANGE_PRECISION_DEFAULT,
|
||||||
CONF_EXCHANGE_RATES,
|
CONF_EXCHANGE_RATES,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
)
|
)
|
||||||
|
@ -66,6 +68,10 @@ async def async_setup_entry(
|
||||||
|
|
||||||
exchange_base_currency = instance.exchange_rates[API_ACCOUNT_CURRENCY]
|
exchange_base_currency = instance.exchange_rates[API_ACCOUNT_CURRENCY]
|
||||||
|
|
||||||
|
exchange_precision = config_entry.options.get(
|
||||||
|
CONF_EXCHANGE_PRECISION, CONF_EXCHANGE_PRECISION_DEFAULT
|
||||||
|
)
|
||||||
|
|
||||||
for currency in desired_currencies:
|
for currency in desired_currencies:
|
||||||
if currency not in provided_currencies:
|
if currency not in provided_currencies:
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
|
@ -80,9 +86,7 @@ async def async_setup_entry(
|
||||||
for rate in config_entry.options[CONF_EXCHANGE_RATES]:
|
for rate in config_entry.options[CONF_EXCHANGE_RATES]:
|
||||||
entities.append(
|
entities.append(
|
||||||
ExchangeRateSensor(
|
ExchangeRateSensor(
|
||||||
instance,
|
instance, rate, exchange_base_currency, exchange_precision
|
||||||
rate,
|
|
||||||
exchange_base_currency,
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -178,14 +182,16 @@ class AccountSensor(SensorEntity):
|
||||||
class ExchangeRateSensor(SensorEntity):
|
class ExchangeRateSensor(SensorEntity):
|
||||||
"""Representation of a Coinbase.com sensor."""
|
"""Representation of a Coinbase.com sensor."""
|
||||||
|
|
||||||
def __init__(self, coinbase_data, exchange_currency, exchange_base):
|
def __init__(self, coinbase_data, exchange_currency, exchange_base, precision):
|
||||||
"""Initialize the sensor."""
|
"""Initialize the sensor."""
|
||||||
self._coinbase_data = coinbase_data
|
self._coinbase_data = coinbase_data
|
||||||
self.currency = exchange_currency
|
self.currency = exchange_currency
|
||||||
self._name = f"{exchange_currency} Exchange Rate"
|
self._name = f"{exchange_currency} Exchange Rate"
|
||||||
self._id = f"coinbase-{coinbase_data.user_id}-xe-{exchange_currency}"
|
self._id = f"coinbase-{coinbase_data.user_id}-xe-{exchange_currency}"
|
||||||
|
self._precision = precision
|
||||||
self._state = round(
|
self._state = round(
|
||||||
1 / float(self._coinbase_data.exchange_rates[API_RATES][self.currency]), 2
|
1 / float(self._coinbase_data.exchange_rates[API_RATES][self.currency]),
|
||||||
|
self._precision,
|
||||||
)
|
)
|
||||||
self._unit_of_measurement = exchange_base
|
self._unit_of_measurement = exchange_base
|
||||||
self._attr_state_class = SensorStateClass.MEASUREMENT
|
self._attr_state_class = SensorStateClass.MEASUREMENT
|
||||||
|
@ -231,5 +237,6 @@ class ExchangeRateSensor(SensorEntity):
|
||||||
"""Get the latest state of the sensor."""
|
"""Get the latest state of the sensor."""
|
||||||
self._coinbase_data.update()
|
self._coinbase_data.update()
|
||||||
self._state = round(
|
self._state = round(
|
||||||
1 / float(self._coinbase_data.exchange_rates.rates[self.currency]), 2
|
1 / float(self._coinbase_data.exchange_rates.rates[self.currency]),
|
||||||
|
self._precision,
|
||||||
)
|
)
|
||||||
|
|
|
@ -28,7 +28,8 @@
|
||||||
"data": {
|
"data": {
|
||||||
"account_balance_currencies": "Wallet balances to report.",
|
"account_balance_currencies": "Wallet balances to report.",
|
||||||
"exchange_rate_currencies": "Exchange rates to report.",
|
"exchange_rate_currencies": "Exchange rates to report.",
|
||||||
"exchange_base": "Base currency for exchange rate sensors."
|
"exchange_base": "Base currency for exchange rate sensors.",
|
||||||
|
"exchnage_rate_precision": "Number of decimal places for exchange rates."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -14,9 +14,7 @@
|
||||||
"user": {
|
"user": {
|
||||||
"data": {
|
"data": {
|
||||||
"api_key": "API Key",
|
"api_key": "API Key",
|
||||||
"api_token": "API Secret",
|
"api_token": "API Secret"
|
||||||
"currencies": "Account Balance Currencies",
|
|
||||||
"exchange_rates": "Exchange Rates"
|
|
||||||
},
|
},
|
||||||
"description": "Please enter the details of your API key as provided by Coinbase.",
|
"description": "Please enter the details of your API key as provided by Coinbase.",
|
||||||
"title": "Coinbase API Key Details"
|
"title": "Coinbase API Key Details"
|
||||||
|
@ -26,9 +24,7 @@
|
||||||
"options": {
|
"options": {
|
||||||
"error": {
|
"error": {
|
||||||
"currency_unavailable": "One or more of the requested currency balances is not provided by your Coinbase API.",
|
"currency_unavailable": "One or more of the requested currency balances is not provided by your Coinbase API.",
|
||||||
"currency_unavaliable": "One or more of the requested currency balances is not provided by your Coinbase API.",
|
|
||||||
"exchange_rate_unavailable": "One or more of the requested exchange rates is not provided by Coinbase.",
|
"exchange_rate_unavailable": "One or more of the requested exchange rates is not provided by Coinbase.",
|
||||||
"exchange_rate_unavaliable": "One or more of the requested exchange rates is not provided by Coinbase.",
|
|
||||||
"unknown": "Unexpected error"
|
"unknown": "Unexpected error"
|
||||||
},
|
},
|
||||||
"step": {
|
"step": {
|
||||||
|
@ -36,7 +32,8 @@
|
||||||
"data": {
|
"data": {
|
||||||
"account_balance_currencies": "Wallet balances to report.",
|
"account_balance_currencies": "Wallet balances to report.",
|
||||||
"exchange_base": "Base currency for exchange rate sensors.",
|
"exchange_base": "Base currency for exchange rate sensors.",
|
||||||
"exchange_rate_currencies": "Exchange rates to report."
|
"exchange_rate_currencies": "Exchange rates to report.",
|
||||||
|
"exchnage_rate_precision": "Number of decimal places for exchange rates."
|
||||||
},
|
},
|
||||||
"description": "Adjust Coinbase Options"
|
"description": "Adjust Coinbase Options"
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ from requests.models import Response
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.components.coinbase.const import (
|
from homeassistant.components.coinbase.const import (
|
||||||
CONF_CURRENCIES,
|
CONF_CURRENCIES,
|
||||||
|
CONF_EXCHANGE_PRECISION,
|
||||||
CONF_EXCHANGE_RATES,
|
CONF_EXCHANGE_RATES,
|
||||||
CONF_YAML_API_TOKEN,
|
CONF_YAML_API_TOKEN,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
|
@ -211,6 +212,7 @@ async def test_option_form(hass):
|
||||||
user_input={
|
user_input={
|
||||||
CONF_CURRENCIES: [GOOD_CURRENCY],
|
CONF_CURRENCIES: [GOOD_CURRENCY],
|
||||||
CONF_EXCHANGE_RATES: [GOOD_EXCHANGE_RATE],
|
CONF_EXCHANGE_RATES: [GOOD_EXCHANGE_RATE],
|
||||||
|
CONF_EXCHANGE_PRECISION: 5,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert result2["type"] == "create_entry"
|
assert result2["type"] == "create_entry"
|
||||||
|
@ -237,6 +239,7 @@ async def test_form_bad_account_currency(hass):
|
||||||
user_input={
|
user_input={
|
||||||
CONF_CURRENCIES: [BAD_CURRENCY],
|
CONF_CURRENCIES: [BAD_CURRENCY],
|
||||||
CONF_EXCHANGE_RATES: [],
|
CONF_EXCHANGE_RATES: [],
|
||||||
|
CONF_EXCHANGE_PRECISION: 5,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -263,6 +266,7 @@ async def test_form_bad_exchange_rate(hass):
|
||||||
user_input={
|
user_input={
|
||||||
CONF_CURRENCIES: [],
|
CONF_CURRENCIES: [],
|
||||||
CONF_EXCHANGE_RATES: [BAD_EXCHANGE_RATE],
|
CONF_EXCHANGE_RATES: [BAD_EXCHANGE_RATE],
|
||||||
|
CONF_EXCHANGE_PRECISION: 5,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert result2["type"] == "form"
|
assert result2["type"] == "form"
|
||||||
|
@ -293,6 +297,7 @@ async def test_option_catch_all_exception(hass):
|
||||||
user_input={
|
user_input={
|
||||||
CONF_CURRENCIES: [],
|
CONF_CURRENCIES: [],
|
||||||
CONF_EXCHANGE_RATES: ["ETH"],
|
CONF_EXCHANGE_RATES: ["ETH"],
|
||||||
|
CONF_EXCHANGE_PRECISION: 5,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue