diff --git a/README.md b/README.md index a512432..a3f82d6 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,8 @@ Supported API permissions and associated sensors - Account balance sensors - Mining Permissions > View mining data... - Rig, device, and payout sensors + - Mining Permissions > Manage Rigs + - Device start/stop switch See this [repository](https://github.com/nicehash/rest-clients-demo) for further assistance generating an API key. diff --git a/custom_components/nicehash/__init__.py b/custom_components/nicehash/__init__.py index b05964d..a04ad61 100644 --- a/custom_components/nicehash/__init__.py +++ b/custom_components/nicehash/__init__.py @@ -118,6 +118,8 @@ async def async_setup(hass: HomeAssistant, config: Config): hass.data[DOMAIN]["rigs_coordinator"] = rigs_coordinator + await discovery.async_load_platform(hass, "switch", DOMAIN, {}, config) await discovery.async_load_platform(hass, "sensor", DOMAIN, {}, config) + return True diff --git a/custom_components/nicehash/control_switches.py b/custom_components/nicehash/control_switches.py new file mode 100644 index 0000000..8f6f3a0 --- /dev/null +++ b/custom_components/nicehash/control_switches.py @@ -0,0 +1,89 @@ +""" +NiceHash Rig controls +""" +from datetime import datetime +import logging + +from homeassistant.const import ATTR_ATTRIBUTION +from homeassistant.helpers.entity import Entity +from homeassistant.components.switch import SwitchEntity + +from .coordinators import MiningRigsDataUpdateCoordinator +from .nicehash import MiningRig, MiningRigDevice, NiceHashPrivateClient +from .const import DOMAIN, NICEHASH_ATTRIBUTION +import asyncio + +class DeviceSwitch(SwitchEntity): + def __init__( + self, + coordinator: MiningRigsDataUpdateCoordinator, + rig: MiningRig, + device: MiningRigDevice, + client: NiceHashPrivateClient, + ): + """Initialize the switch""" + self.coordinator = coordinator + self._rig_id = rig.id + self._rig_name = rig.name + self._device_id = device.id + self._device_name = device.name + self._client = client + self._status = device.status + + + def _get_device(self): + try: + mining_rigs = self.coordinator.data.get("miningRigs") + rig = MiningRig(mining_rigs.get(self._rig_id)) + return rig.devices.get(self._device_id) + except Exception as e: + _LOGGER.error(f"Unable to get mining device ({self._device_id})\n{e}") + + +class GPUSwitch(DeviceSwitch): + + _is_on = False + _last_response = "N/A" + + @property + def name(self): + """switch name""" + return f"{self._device_name} Switch" + + @property + def unique_id(self): + """Unique entity id""" + return f"{self._device_id}:switch" + + @property + def is_on(self): + device = self._get_device() + if device.status == "Mining": + self._is_on = True + elif device: + self._is_on = False + else: + self._is_on = "unavailable" + return self._is_on + + @property + def device_state_attributes(self): + """Sensor device state attributes""" + return { + ATTR_ATTRIBUTION: NICEHASH_ATTRIBUTION, + "status": self._status, + "device": self._device_name, + "last_response": self._last_response, + } + + def turn_on(self, **kwargs): + """Turn the switch on.""" + self._is_on = True + response = asyncio.run(self._client.toggle_device(self._device_id, "START", self._rig_id)) + self._last_response = "Success!" if response["success"] else response["message"] + + def turn_off(self, **kwargs): + """Turn the switch off.""" + self._is_on = False + response = asyncio.run(self._client.toggle_device(self._device_id, "STOP", self._rig_id)) + self._last_response = "Success!" if response["success"] else response["message"] \ No newline at end of file diff --git a/custom_components/nicehash/nicehash.py b/custom_components/nicehash/nicehash.py index 501a3b9..a60f3df 100644 --- a/custom_components/nicehash/nicehash.py +++ b/custom_components/nicehash/nicehash.py @@ -150,6 +150,13 @@ 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 toggle_device(self, device_id, action, rig_id): + query = "" + body = {"deviceId":device_id, + "action":action, + "rigId":rig_id} + return await self.request("POST", "/main/api/v2/mining/rigs/status2", query, body) + async def request(self, method, path, query="", body=None): xtime = self.get_epoch_ms_from_now() xnonce = str(uuid.uuid4()) diff --git a/custom_components/nicehash/switch.py b/custom_components/nicehash/switch.py new file mode 100644 index 0000000..35d7b0b --- /dev/null +++ b/custom_components/nicehash/switch.py @@ -0,0 +1,82 @@ +""" +Sensor platform for NiceHash +""" +import logging + +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import ATTR_ATTRIBUTION +from homeassistant.core import Config, HomeAssistant + +from .const import ( + BALANCE_TYPE_AVAILABLE, + BALANCE_TYPE_PENDING, + BALANCE_TYPE_TOTAL, + CURRENCY_BTC, + CURRENCY_EUR, + CURRENCY_USD, + DOMAIN, + DEVICE_LOAD, + DEVICE_RPM, + DEVICE_SPEED_RATE, + DEVICE_SPEED_ALGORITHM, +) +from .nicehash import ( + MiningRig, + MiningRigDevice, + NiceHashPrivateClient, + NiceHashPublicClient, +) +from .control_switches import ( + GPUSwitch +) + + +_LOGGER = logging.getLogger(__name__) + + +async def async_setup_platform( + hass: HomeAssistant, config: Config, async_add_entities, discovery_info=None +): + """Setup NiceHash sensor platform""" + _LOGGER.debug("Creating new NiceHash switch components") + + data = hass.data[DOMAIN] + # Configuration + organization_id = data.get("organization_id") + client = data.get("client") + # Options + currency = data.get("currency") + balances_enabled = data.get("balances_enabled") + payouts_enabled = data.get("payouts_enabled") + rigs_enabled = data.get("rigs_enabled") + devices_enabled = data.get("devices_enabled") + + + # Mining rig and device sensors + if rigs_enabled or devices_enabled: + rigs_coordinator = data.get("rigs_coordinator") + rig_data = await client.get_mining_rigs() + mining_rigs = rig_data.get("miningRigs") + _LOGGER.debug(f"Found {len(mining_rigs)} rigs") + + if devices_enabled: + _LOGGER.debug("Device sensors enabled") + device_switches = create_device_switches(mining_rigs, rigs_coordinator,client) + async_add_entities(device_switches, True) + + + +def create_device_switches(mining_rigs, coordinator, client): + device_switches = [] + for rig_data in mining_rigs: + rig = MiningRig(rig_data) + devices = rig.devices.values() + _LOGGER.debug( + f"Found {len(devices)} device switches(s) for {rig.name} ({rig.id})" + ) + for device in devices: + _LOGGER.debug(f"Creating {device.name} ({device.id}) switches") + device_switches.append(GPUSwitch(coordinator, rig, device, client)) + + return device_switches + \ No newline at end of file