feat(sensor): add recent payout sensor
- fetches payouts every hour - displays most recently created in BTC
This commit is contained in:
parent
5c99904287
commit
eefd191e51
@ -20,6 +20,7 @@ from .const import (
|
|||||||
CONF_ORGANIZATION_ID,
|
CONF_ORGANIZATION_ID,
|
||||||
CONF_RIGS_ENABLED,
|
CONF_RIGS_ENABLED,
|
||||||
CONF_DEVICES_ENABLED,
|
CONF_DEVICES_ENABLED,
|
||||||
|
CONF_PAYOUTS_ENABLED,
|
||||||
CURRENCY_USD,
|
CURRENCY_USD,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
STARTUP_MESSAGE,
|
STARTUP_MESSAGE,
|
||||||
@ -27,6 +28,7 @@ from .const import (
|
|||||||
from .nicehash import NiceHashPrivateClient
|
from .nicehash import NiceHashPrivateClient
|
||||||
from .data_coordinators import (
|
from .data_coordinators import (
|
||||||
AccountsDataUpdateCoordinator,
|
AccountsDataUpdateCoordinator,
|
||||||
|
MiningPayoutsDataUpdateCoordinator,
|
||||||
MiningRigsDataUpdateCoordinator,
|
MiningRigsDataUpdateCoordinator,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -42,6 +44,7 @@ CONFIG_SCHEMA = vol.Schema(
|
|||||||
vol.Required(CONF_CURRENCY, default=CURRENCY_USD): cv.string,
|
vol.Required(CONF_CURRENCY, default=CURRENCY_USD): cv.string,
|
||||||
vol.Required(CONF_RIGS_ENABLED, default=False): cv.boolean,
|
vol.Required(CONF_RIGS_ENABLED, default=False): cv.boolean,
|
||||||
vol.Required(CONF_DEVICES_ENABLED, default=False): cv.boolean,
|
vol.Required(CONF_DEVICES_ENABLED, default=False): cv.boolean,
|
||||||
|
vol.Required(CONF_PAYOUTS_ENABLED, default=False): cv.boolean,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@ -64,22 +67,39 @@ async def async_setup(hass: HomeAssistant, config: Config):
|
|||||||
currency = nicehash_config.get(CONF_CURRENCY).upper()
|
currency = nicehash_config.get(CONF_CURRENCY).upper()
|
||||||
rigs_enabled = nicehash_config.get(CONF_RIGS_ENABLED)
|
rigs_enabled = nicehash_config.get(CONF_RIGS_ENABLED)
|
||||||
devices_enabled = nicehash_config.get(CONF_DEVICES_ENABLED)
|
devices_enabled = nicehash_config.get(CONF_DEVICES_ENABLED)
|
||||||
|
payouts_enabled = nicehash_config.get(CONF_PAYOUTS_ENABLED)
|
||||||
|
|
||||||
client = NiceHashPrivateClient(organization_id, api_key, api_secret)
|
client = NiceHashPrivateClient(organization_id, api_key, api_secret)
|
||||||
|
|
||||||
accounts_coordinator = AccountsDataUpdateCoordinator(hass, client)
|
hass.data[DOMAIN]["organization_id"] = organization_id
|
||||||
|
hass.data[DOMAIN]["client"] = client
|
||||||
|
hass.data[DOMAIN]["currency"] = currency
|
||||||
|
hass.data[DOMAIN]["rigs_enabled"] = rigs_enabled
|
||||||
|
hass.data[DOMAIN]["devices_enabled"] = devices_enabled
|
||||||
|
hass.data[DOMAIN]["payouts_enabled"] = payouts_enabled
|
||||||
|
|
||||||
|
# Accounts
|
||||||
|
accounts_coordinator = AccountsDataUpdateCoordinator(hass, client)
|
||||||
await accounts_coordinator.async_refresh()
|
await accounts_coordinator.async_refresh()
|
||||||
|
|
||||||
if not accounts_coordinator.last_update_success:
|
if not accounts_coordinator.last_update_success:
|
||||||
_LOGGER.error("Unable to get NiceHash accounts")
|
_LOGGER.error("Unable to get NiceHash accounts")
|
||||||
raise PlatformNotReady
|
raise PlatformNotReady
|
||||||
|
|
||||||
hass.data[DOMAIN]["organization_id"] = organization_id
|
|
||||||
hass.data[DOMAIN]["client"] = client
|
|
||||||
hass.data[DOMAIN]["currency"] = currency
|
|
||||||
hass.data[DOMAIN]["accounts_coordinator"] = accounts_coordinator
|
hass.data[DOMAIN]["accounts_coordinator"] = accounts_coordinator
|
||||||
|
|
||||||
|
# Payouts
|
||||||
|
if payouts_enabled:
|
||||||
|
payouts_coordinator = MiningPayoutsDataUpdateCoordinator(hass, client)
|
||||||
|
await payouts_coordinator.async_refresh()
|
||||||
|
|
||||||
|
if not payouts_coordinator.last_update_success:
|
||||||
|
_LOGGER.error("Unable to get NiceHash mining payouts")
|
||||||
|
raise PlatformNotReady
|
||||||
|
|
||||||
|
hass.data[DOMAIN]["payouts_coordinator"] = payouts_coordinator
|
||||||
|
|
||||||
|
# Rigs
|
||||||
if rigs_enabled or devices_enabled:
|
if rigs_enabled or devices_enabled:
|
||||||
rigs_coordinator = MiningRigsDataUpdateCoordinator(hass, client)
|
rigs_coordinator = MiningRigsDataUpdateCoordinator(hass, client)
|
||||||
await rigs_coordinator.async_refresh()
|
await rigs_coordinator.async_refresh()
|
||||||
@ -88,8 +108,6 @@ async def async_setup(hass: HomeAssistant, config: Config):
|
|||||||
_LOGGER.error("Unable to get NiceHash mining rigs")
|
_LOGGER.error("Unable to get NiceHash mining rigs")
|
||||||
raise PlatformNotReady
|
raise PlatformNotReady
|
||||||
|
|
||||||
hass.data[DOMAIN]["rigs_enabled"] = rigs_enabled
|
|
||||||
hass.data[DOMAIN]["devices_enabled"] = devices_enabled
|
|
||||||
hass.data[DOMAIN]["rigs_coordinator"] = rigs_coordinator
|
hass.data[DOMAIN]["rigs_coordinator"] = rigs_coordinator
|
||||||
|
|
||||||
await discovery.async_load_platform(hass, "sensor", DOMAIN, {}, config)
|
await discovery.async_load_platform(hass, "sensor", DOMAIN, {}, config)
|
||||||
|
@ -31,7 +31,7 @@ CONF_ORGANIZATION_ID = "organization_id"
|
|||||||
CONF_CURRENCY = "currency"
|
CONF_CURRENCY = "currency"
|
||||||
CONF_RIGS_ENABLED = "rigs"
|
CONF_RIGS_ENABLED = "rigs"
|
||||||
CONF_DEVICES_ENABLED = "devices"
|
CONF_DEVICES_ENABLED = "devices"
|
||||||
|
CONF_PAYOUTS_ENABLED = "payouts"
|
||||||
|
|
||||||
# Defaults
|
# Defaults
|
||||||
DEFAULT_NAME = NAME
|
DEFAULT_NAME = NAME
|
||||||
@ -73,3 +73,5 @@ DEVICE_SPEED_RATE = "device-speed-rate"
|
|||||||
DEVICE_SPEED_ALGORITHM = "device-speed-algorithm"
|
DEVICE_SPEED_ALGORITHM = "device-speed-algorithm"
|
||||||
DEVICE_LOAD = "device-load"
|
DEVICE_LOAD = "device-load"
|
||||||
DEVICE_RPM = "device-rpm"
|
DEVICE_RPM = "device-rpm"
|
||||||
|
# Payout types
|
||||||
|
PAYOUT_USER = "USER"
|
||||||
|
@ -18,6 +18,7 @@ from .nicehash import NiceHashPrivateClient, NiceHashPublicClient
|
|||||||
|
|
||||||
SCAN_INTERVAL_RIGS = timedelta(minutes=1)
|
SCAN_INTERVAL_RIGS = timedelta(minutes=1)
|
||||||
SCAN_INTERVAL_ACCOUNTS = timedelta(minutes=60)
|
SCAN_INTERVAL_ACCOUNTS = timedelta(minutes=60)
|
||||||
|
SCAN_INTERVAL_PAYOUTS = timedelta(minutes=60)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -80,3 +81,26 @@ class MiningRigsDataUpdateCoordinator(DataUpdateCoordinator):
|
|||||||
return data
|
return data
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise UpdateFailed(e)
|
raise UpdateFailed(e)
|
||||||
|
|
||||||
|
|
||||||
|
class MiningPayoutsDataUpdateCoordinator(DataUpdateCoordinator):
|
||||||
|
"""Manages fetching mining rig payout data from NiceHash API"""
|
||||||
|
|
||||||
|
def __init__(self, hass: HomeAssistant, client: NiceHashPrivateClient):
|
||||||
|
"""Initialize"""
|
||||||
|
self.name = f"{DOMAIN}_mining_payouts_coordinator"
|
||||||
|
self._client = client
|
||||||
|
|
||||||
|
super().__init__(
|
||||||
|
hass, _LOGGER, name=self.name, update_interval=SCAN_INTERVAL_PAYOUTS
|
||||||
|
)
|
||||||
|
|
||||||
|
async def _async_update_data(self):
|
||||||
|
"""Update mining payouts data"""
|
||||||
|
try:
|
||||||
|
data = await self._client.get_rig_payouts(42) # 6 (per day) * 7 days
|
||||||
|
payouts = data.get("list")
|
||||||
|
payouts.sort(key=lambda payout: payout.get("created"))
|
||||||
|
return payouts
|
||||||
|
except Exception as e:
|
||||||
|
raise UpdateFailed(e)
|
||||||
|
@ -18,7 +18,7 @@ from .const import NICEHASH_API_URL
|
|||||||
|
|
||||||
|
|
||||||
class MiningRigDevice:
|
class MiningRigDevice:
|
||||||
def __init__(self, data):
|
def __init__(self, data: dict):
|
||||||
self.device_id = data.get("id")
|
self.device_id = data.get("id")
|
||||||
self.name = data.get("name")
|
self.name = data.get("name")
|
||||||
self.status = data.get("status").get("description")
|
self.status = data.get("status").get("description")
|
||||||
@ -29,7 +29,7 @@ class MiningRigDevice:
|
|||||||
|
|
||||||
|
|
||||||
class MiningRig:
|
class MiningRig:
|
||||||
def __init__(self, data):
|
def __init__(self, data: dict):
|
||||||
self.rig_id = data.get("rig_id")
|
self.rig_id = data.get("rig_id")
|
||||||
self.name = data.get("name")
|
self.name = data.get("name")
|
||||||
self.status = data.get("minerStatus")
|
self.status = data.get("minerStatus")
|
||||||
@ -46,6 +46,24 @@ class MiningRig:
|
|||||||
self.temperatures.append(device.temperature)
|
self.temperatures.append(device.temperature)
|
||||||
|
|
||||||
|
|
||||||
|
class Payout:
|
||||||
|
def __init__(self, data: dict):
|
||||||
|
self.id = data.get("id")
|
||||||
|
self.currency = "Unknown"
|
||||||
|
self.created = data.get("created")
|
||||||
|
self.amount = data.get("amount")
|
||||||
|
self.fee = data.get("feeAmount")
|
||||||
|
self.account_type = "Unknown"
|
||||||
|
# Currency
|
||||||
|
currency = data.get("currency")
|
||||||
|
if currency:
|
||||||
|
self.currency = currency.get("enumName")
|
||||||
|
# Account Type
|
||||||
|
account_type = data.get("accountType")
|
||||||
|
if account_type:
|
||||||
|
self.account_type = account_type.get("enumName")
|
||||||
|
|
||||||
|
|
||||||
class NiceHashPublicClient:
|
class NiceHashPublicClient:
|
||||||
async def get_exchange_rates(self):
|
async def get_exchange_rates(self):
|
||||||
exchange_data = await self.request("GET", "/main/api/v2/exchangeRate/list")
|
exchange_data = await self.request("GET", "/main/api/v2/exchangeRate/list")
|
||||||
@ -89,6 +107,10 @@ class NiceHashPrivateClient:
|
|||||||
async def get_mining_rig(self, rig_id):
|
async def get_mining_rig(self, rig_id):
|
||||||
return await self.request("GET", f"/main/api/v2/mining/rig2/{rig_id}")
|
return await self.request("GET", f"/main/api/v2/mining/rig2/{rig_id}")
|
||||||
|
|
||||||
|
async def get_rig_payouts(self, size=84):
|
||||||
|
query = f"size={size}"
|
||||||
|
return await self.request("GET", "/main/api/v2/mining/rigs/payouts", query)
|
||||||
|
|
||||||
async def request(self, method, path, query="", body=None):
|
async def request(self, method, path, query="", body=None):
|
||||||
xtime = self.get_epoch_ms_from_now()
|
xtime = self.get_epoch_ms_from_now()
|
||||||
xnonce = str(uuid.uuid4())
|
xnonce = str(uuid.uuid4())
|
||||||
|
118
custom_components/nicehash/payout_sensors.py
Normal file
118
custom_components/nicehash/payout_sensors.py
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
"""
|
||||||
|
NiceHash Rig Payout Sensors
|
||||||
|
"""
|
||||||
|
from datetime import datetime
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from homeassistant.const import ATTR_ATTRIBUTION
|
||||||
|
from homeassistant.helpers.entity import Entity
|
||||||
|
|
||||||
|
from .const import (
|
||||||
|
CURRENCY_BTC,
|
||||||
|
FORMAT_DATETIME,
|
||||||
|
ICON_CURRENCY_BTC,
|
||||||
|
ICON_PULSE,
|
||||||
|
ICON_THERMOMETER,
|
||||||
|
NICEHASH_ATTRIBUTION,
|
||||||
|
PAYOUT_USER,
|
||||||
|
)
|
||||||
|
from .data_coordinators import (
|
||||||
|
MiningPayoutsDataUpdateCoordinator,
|
||||||
|
MiningRigsDataUpdateCoordinator,
|
||||||
|
)
|
||||||
|
from .nicehash import MiningRig, Payout
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class RecentMiningPayoutSensor(Entity):
|
||||||
|
"""
|
||||||
|
Displays most recent payout of a mining rig
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self, coordinator: MiningPayoutsDataUpdateCoordinator, organization_id: str
|
||||||
|
):
|
||||||
|
"""Initialize the sensor"""
|
||||||
|
self.coordinator = coordinator
|
||||||
|
self.organization_id = organization_id
|
||||||
|
self._id = None
|
||||||
|
self._created = None
|
||||||
|
self._currency = None
|
||||||
|
self._amount = 0.00
|
||||||
|
self._fee = 0.00
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
"""Sensor name"""
|
||||||
|
return f"Recent Mining Payout"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def unique_id(self):
|
||||||
|
"""Unique entity id"""
|
||||||
|
return f"{self.organization_id}:payouts:recent"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def should_poll(self):
|
||||||
|
"""No need to poll, Coordinator notifies entity of updates"""
|
||||||
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def available(self):
|
||||||
|
"""Whether sensor is available"""
|
||||||
|
return self.coordinator.last_update_success
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state(self):
|
||||||
|
"""Sensor state"""
|
||||||
|
try:
|
||||||
|
for raw_payout in self.coordinator.data:
|
||||||
|
payout = Payout(raw_payout)
|
||||||
|
if payout.account_type == PAYOUT_USER:
|
||||||
|
self._id = payout.id
|
||||||
|
self._amount = payout.amount
|
||||||
|
self._currency = payout.currency
|
||||||
|
self._created = datetime.fromtimestamp(payout.created / 1000.0)
|
||||||
|
self._fee = payout.fee
|
||||||
|
except Exception as e:
|
||||||
|
_LOGGER.error(f"Unable to get most recent \n{e}")
|
||||||
|
self._id = None
|
||||||
|
self._created = None
|
||||||
|
self._currency = None
|
||||||
|
self._amount = 0.00
|
||||||
|
self._fee = 0.00
|
||||||
|
|
||||||
|
return self._amount
|
||||||
|
|
||||||
|
@property
|
||||||
|
def icon(self):
|
||||||
|
"""Sensor icon"""
|
||||||
|
return ICON_CURRENCY_BTC
|
||||||
|
|
||||||
|
@property
|
||||||
|
def unit_of_measurement(self):
|
||||||
|
"""Sensor unit of measurement"""
|
||||||
|
return CURRENCY_BTC
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_state_attributes(self):
|
||||||
|
"""Sensor device state attributes"""
|
||||||
|
created = None
|
||||||
|
if self._created:
|
||||||
|
created = self._created.strftime(FORMAT_DATETIME)
|
||||||
|
return {
|
||||||
|
ATTR_ATTRIBUTION: NICEHASH_ATTRIBUTION,
|
||||||
|
"amount": self._amount,
|
||||||
|
"created": created,
|
||||||
|
"fee": self._fee,
|
||||||
|
}
|
||||||
|
|
||||||
|
async def async_added_to_hass(self):
|
||||||
|
"""Connect to dispatcher listening for entity data notifications"""
|
||||||
|
self.async_on_remove(
|
||||||
|
self.coordinator.async_add_listener(self.async_write_ha_state)
|
||||||
|
)
|
||||||
|
|
||||||
|
async def async_update(self):
|
||||||
|
"""Update entity"""
|
||||||
|
await self.coordinator.async_request_refresh()
|
@ -23,6 +23,7 @@ from .const import (
|
|||||||
)
|
)
|
||||||
from .nicehash import NiceHashPrivateClient, NiceHashPublicClient
|
from .nicehash import NiceHashPrivateClient, NiceHashPublicClient
|
||||||
from .account_sensors import BalanceSensor
|
from .account_sensors import BalanceSensor
|
||||||
|
from .payout_sensors import RecentMiningPayoutSensor
|
||||||
from .rig_sensors import (
|
from .rig_sensors import (
|
||||||
RigStatusSensor,
|
RigStatusSensor,
|
||||||
RigTemperatureSensor,
|
RigTemperatureSensor,
|
||||||
@ -52,6 +53,7 @@ async def async_setup_platform(
|
|||||||
client = data.get("client")
|
client = data.get("client")
|
||||||
# Options
|
# Options
|
||||||
currency = data.get("currency")
|
currency = data.get("currency")
|
||||||
|
payouts_enabled = data.get("payouts_enabled")
|
||||||
rigs_enabled = data.get("rigs_enabled")
|
rigs_enabled = data.get("rigs_enabled")
|
||||||
devices_enabled = data.get("devices_enabled")
|
devices_enabled = data.get("devices_enabled")
|
||||||
|
|
||||||
@ -62,17 +64,22 @@ async def async_setup_platform(
|
|||||||
)
|
)
|
||||||
async_add_entities(balance_sensors, True)
|
async_add_entities(balance_sensors, True)
|
||||||
|
|
||||||
|
# Payout sensors
|
||||||
|
if payouts_enabled:
|
||||||
|
payouts_coordinator = data.get("payouts_coordinator")
|
||||||
|
payout_sensors = create_payout_sensors(organization_id, payouts_coordinator)
|
||||||
|
async_add_entities(payout_sensors)
|
||||||
|
|
||||||
|
# Mining rig and device sensors
|
||||||
if rigs_enabled or devices_enabled:
|
if rigs_enabled or devices_enabled:
|
||||||
rigs_coordinator = data.get("rigs_coordinator")
|
rigs_coordinator = data.get("rigs_coordinator")
|
||||||
rig_data = await client.get_mining_rigs()
|
rig_data = await client.get_mining_rigs()
|
||||||
mining_rigs = rig_data.get("miningRigs")
|
mining_rigs = rig_data.get("miningRigs")
|
||||||
|
|
||||||
# Add mining rig sensors if enabled
|
|
||||||
if rigs_enabled:
|
if rigs_enabled:
|
||||||
rig_sensors = create_rig_sensors(mining_rigs, rigs_coordinator)
|
rig_sensors = create_rig_sensors(mining_rigs, rigs_coordinator)
|
||||||
async_add_entities(rig_sensors, True)
|
async_add_entities(rig_sensors, True)
|
||||||
|
|
||||||
# Add device sensors if enabled
|
|
||||||
if devices_enabled:
|
if devices_enabled:
|
||||||
device_sensors = create_device_sensors(mining_rigs, rigs_coordinator)
|
device_sensors = create_device_sensors(mining_rigs, rigs_coordinator)
|
||||||
async_add_entities(device_sensors, True)
|
async_add_entities(device_sensors, True)
|
||||||
@ -130,6 +137,13 @@ def create_balance_sensors(organization_id, currency, coordinator):
|
|||||||
return balance_sensors
|
return balance_sensors
|
||||||
|
|
||||||
|
|
||||||
|
def create_payout_sensors(organization_id, coordinator):
|
||||||
|
payout_sensors = []
|
||||||
|
payout_sensors.append(RecentMiningPayoutSensor(coordinator, organization_id))
|
||||||
|
|
||||||
|
return payout_sensors
|
||||||
|
|
||||||
|
|
||||||
def create_rig_sensors(mining_rigs, coordinator):
|
def create_rig_sensors(mining_rigs, coordinator):
|
||||||
rig_sensors = []
|
rig_sensors = []
|
||||||
for rig in mining_rigs:
|
for rig in mining_rigs:
|
||||||
|
Loading…
Reference in New Issue
Block a user