From 945a50dff3b4a80913b72c152667c4e35aecb57f Mon Sep 17 00:00:00 2001 From: Brian Berg Date: Wed, 17 Jun 2020 03:18:24 +0000 Subject: [PATCH] feat(sensor): add rig status sensors - refactor rig temperature sensor - include state value in attributes - remove debug logs --- custom_components/nicehash/const.py | 9 ++ custom_components/nicehash/sensor.py | 10 ++- custom_components/nicehash/sensors.py | 114 +++++++++++++++++++++++--- 3 files changed, 119 insertions(+), 14 deletions(-) diff --git a/custom_components/nicehash/const.py b/custom_components/nicehash/const.py index 56bc67d..7d0232a 100644 --- a/custom_components/nicehash/const.py +++ b/custom_components/nicehash/const.py @@ -14,6 +14,7 @@ ICON = "mdi:pickaxe" ICON_CURRENCY_BTC = "mdi:currency-btc" ICON_CURRENCY_EUR = "mdi:currency-eur" ICON_CURRENCY_USD = "mdi:currency-usd" +ICON_PULSE = "mdi:pulse" ICON_TEMPERATURE = "mdi:thermometer" # Platforms @@ -51,3 +52,11 @@ CURRENCY_EUR = "EUR" BALANCE_TYPE_AVAILABLE = "available" BALANCE_TYPE_PENDING = "pending" BALANCE_TYPE_TOTAL = "total" +DEVICE_STATUS_UNKNOWN = "UNKNOWN" +DEVICE_STATUS_DISABLED = "DISABLED" +DEVICE_STATUS_INACTIVE = "INACTIVE" +DEVICE_STATUS_MINING = "MINING" +DEVICE_STATUS_BENCHMARKING = "BENCHMARKING" +DEVICE_STATUS_ERROR = "ERROR" +DEVICE_STATUS_PENDING = "PENDING" +DEVICE_STATUS_OFFLINE = "OFFLINE" diff --git a/custom_components/nicehash/sensor.py b/custom_components/nicehash/sensor.py index bc82121..0bbaa26 100644 --- a/custom_components/nicehash/sensor.py +++ b/custom_components/nicehash/sensor.py @@ -19,7 +19,11 @@ from .const import ( DOMAIN, ) from .nicehash import NiceHashPrivateClient, NiceHashPublicClient -from .sensors import NiceHashBalanceSensor, NiceHashRigTemperatureSensor +from .sensors import ( + NiceHashBalanceSensor, + NiceHashRigStatusSensor, + NiceHashRigTemperatureSensor, +) _LOGGER = logging.getLogger(__name__) @@ -91,6 +95,10 @@ async def async_setup_platform( # Add mining rig sensors rig_data = await client.get_mining_rigs() mining_rigs = rig_data["miningRigs"] + # Add status sensors + async_add_entities( + [NiceHashRigStatusSensor(rigs_coordinator, rig) for rig in mining_rigs], True, + ) # Add temperature sensors async_add_entities( [NiceHashRigTemperatureSensor(rigs_coordinator, rig) for rig in mining_rigs], diff --git a/custom_components/nicehash/sensors.py b/custom_components/nicehash/sensors.py index 43a34d3..e6513d8 100644 --- a/custom_components/nicehash/sensors.py +++ b/custom_components/nicehash/sensors.py @@ -1,6 +1,7 @@ """ NiceHash Mining Rig Temperature Sensor """ +from datetime import datetime import logging from homeassistant.const import ATTR_ATTRIBUTION @@ -14,9 +15,11 @@ from .const import ( CURRENCY_EUR, CURRENCY_USD, DEFAULT_NAME, + DEVICE_STATUS_UNKNOWN, ICON_CURRENCY_BTC, ICON_CURRENCY_EUR, ICON_CURRENCY_USD, + ICON_PULSE, ICON_TEMPERATURE, ) @@ -139,20 +142,22 @@ class NiceHashRigTemperatureSensor(Entity): """Initialize the sensor""" self.coordinator = coordinator self._rig_id = rig["rigId"] - self._name = rig["name"] + self._rig_name = rig["name"] self._temps = [] self._num_devices = 0 - _LOGGER.debug(f"Mining Rig Temperature Sensor: {self._name} ({self._rig_id})") + _LOGGER.debug( + f"Mining Rig Temperature Sensor: {self._rig_name} ({self._rig_id})" + ) @property def name(self): """Sensor name""" - return self._name + return f"{self._rig_name} Temperature" @property def unique_id(self): """Unique entity id""" - return self._rig_id + return f"{self._rig_id}:temperature" @property def should_poll(self): @@ -168,28 +173,25 @@ class NiceHashRigTemperatureSensor(Entity): def state(self): """Sensor state""" mining_rigs = self.coordinator.data.get("miningRigs") + self._highest_temp = 0 try: rig_data = mining_rigs.get(self._rig_id) devices = rig_data.get("devices") - highest_temp = 0 self._temps = [] self._num_devices = len(devices) if self._num_devices > 0: - _LOGGER.debug(f"{self._name}: Found {self._num_devices} devices") for device in devices: temp = int(device.get("temperature")) self._temps.append(temp) - if temp > highest_temp: - highest_temp = temp - return highest_temp + if temp > self._highest_temp: + self._highest_temp = temp else: - _LOGGER.debug(f"{self._name}: No devices found") self._num_devices = 0 - return 0 except Exception as e: - _LOGGER.error(f"Unable to get mining rig {self._rig_id}\n{e}") - return 0 + _LOGGER.error(f"Unable to get mining rig ({self._rig_id}) temperature\n{e}") + + return self._highest_temp @property def icon(self): @@ -207,6 +209,7 @@ class NiceHashRigTemperatureSensor(Entity): """Sensor device state attributes""" return { ATTR_ATTRIBUTION: ATTRIBUTION, + "highest_temperature": self._highest_temp, "temperatures": self._temps, "total_devices": self._num_devices, } @@ -220,3 +223,88 @@ class NiceHashRigTemperatureSensor(Entity): async def async_update(self): """Update entity""" await self.coordinator.async_request_refresh() + + +class NiceHashRigStatusSensor(Entity): + """Displays status of a mining rig""" + + def __init__(self, coordinator, rig): + """Initialize the sensor""" + self.coordinator = coordinator + self._rig_id = rig["rigId"] + self._rig_name = rig["name"] + self._status = DEVICE_STATUS_UNKNOWN + self._status_time = None + self._num_devices = 0 + self._unit_of_measurement = "\u200b" + _LOGGER.debug(f"Mining Rig Status Sensor: {self._rig_name} ({self._rig_id})") + + @property + def name(self): + """Sensor name""" + return f"{self._rig_name} Status" + + @property + def unique_id(self): + """Unique entity id""" + return f"{self._rig_id}:status" + + @property + def should_poll(self): + """No need to pool, 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""" + mining_rigs = self.coordinator.data.get("miningRigs") + status = DEVICE_STATUS_UNKNOWN + try: + rig_data = mining_rigs.get(self._rig_id) + devices = rig_data.get("devices") + status = rig_data.get("minerStatus") + status_time_ms = int(rig_data.get("statusTime")) + self._num_devices = len(devices) + self._status_time = datetime.fromtimestamp(status_time_ms / 1000.0) + except Exception as e: + _LOGGER.error(f"Unable to get mining rig ({self._rig_id}) status\n{e}") + self._status_time = None + status = DEVICE_STATUS_UNKNOWN + + self._status = status[0].upper() + status.lower()[1:] + return self._status + + @property + def icon(self): + """Sensor icon""" + return ICON_PULSE + + @property + def unit_of_measurement(self): + """Sensor unit of measurement""" + return self._unit_of_measurement + + @property + def device_state_attributes(self): + """Sensor device state attributes""" + return { + ATTR_ATTRIBUTION: ATTRIBUTION, + "status": self._status, + "status_time": self._status_time.strftime(FORMAT_DATETIME), + "total_devices": self._num_devices, + } + + 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()