Skip to content

Commit

Permalink
Add fan speed data.
Browse files Browse the repository at this point in the history
  • Loading branch information
UpstreamData committed Jan 5, 2024
1 parent ea85ccf commit 1524400
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 23 deletions.
2 changes: 1 addition & 1 deletion custom_components/miner/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@
DEVICE_CLASS_HASHRATE = "hashrate"
DEVICE_CLASS_EFFICIENCY = "efficiency"
TERA_HASH_PER_SECOND = "TH/s"
JOULES_PER_TERAHASH = "J/TH"
JOULES_PER_TERA_HASH = "J/TH"
24 changes: 14 additions & 10 deletions custom_components/miner/coordinator.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""IoTaWatt DataUpdateCoordinator."""
"""Miner DataUpdateCoordinator."""
import logging
from datetime import timedelta

Expand Down Expand Up @@ -52,15 +52,16 @@ async def _async_update_data(self):

miner_data = await self.miner.get_data(
include=[
"hostname",
"mac",
"is_mining",
"fw_ver",
"hashrate",
"expected_hashrate",
"hashboards",
"wattage",
"wattage_limit",
pyasic.DataOptions.HOSTNAME,
pyasic.DataOptions.MAC,
pyasic.DataOptions.IS_MINING,
pyasic.DataOptions.FW_VERSION,
pyasic.DataOptions.HASHRATE,
pyasic.DataOptions.EXPECTED_HASHRATE,
pyasic.DataOptions.HASHBOARDS,
pyasic.DataOptions.WATTAGE,
pyasic.DataOptions.WATTAGE_LIMIT,
pyasic.DataOptions.FANS,
]
)

Expand Down Expand Up @@ -96,5 +97,8 @@ async def _async_update_data(self):
}
for board in miner_data.hashboards
},
"fan_sensors": {
idx: {"fan_speed": fan.speed} for idx, fan in enumerate(miner_data.fans)
},
}
return data
2 changes: 1 addition & 1 deletion custom_components/miner/number.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Support for IoTaWatt Energy monitor."""
"""Support for Bitcoin ASIC miners."""
from __future__ import annotations

import logging
Expand Down
109 changes: 100 additions & 9 deletions custom_components/miner/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
SensorStateClass,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import POWER_WATT, TEMP_CELSIUS
from homeassistant.const import UnitOfPower, UnitOfTemperature, REVOLUTIONS_PER_MINUTE
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import entity
from homeassistant.helpers.entity_platform import AddEntitiesCallback
Expand All @@ -23,7 +23,7 @@
DEVICE_CLASS_EFFICIENCY,
DEVICE_CLASS_HASHRATE,
DOMAIN,
JOULES_PER_TERAHASH,
JOULES_PER_TERA_HASH,
TERA_HASH_PER_SECOND,
)
from .coordinator import MinerCoordinator
Expand All @@ -49,19 +49,19 @@ class MinerNumberEntityDescription(SensorEntityDescription):
] = {
"temperature": MinerSensorEntityDescription(
"Temperature",
native_unit_of_measurement=TEMP_CELSIUS,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.TEMPERATURE,
),
"board_temperature": MinerSensorEntityDescription(
"Board Temperature",
native_unit_of_measurement=TEMP_CELSIUS,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.TEMPERATURE,
),
"chip_temperature": MinerSensorEntityDescription(
"Chip Temperature",
native_unit_of_measurement=TEMP_CELSIUS,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.TEMPERATURE,
),
Expand All @@ -86,21 +86,27 @@ class MinerNumberEntityDescription(SensorEntityDescription):
"power_limit": MinerSensorEntityDescription(
"Power Limit",
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=POWER_WATT,
native_unit_of_measurement=UnitOfPower.WATT,
device_class=SensorDeviceClass.POWER,
),
"miner_consumption": MinerSensorEntityDescription(
"Miner Consumption",
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=POWER_WATT,
native_unit_of_measurement=UnitOfPower.WATT,
device_class=SensorDeviceClass.POWER,
),
"efficiency": MinerSensorEntityDescription(
"Efficiency",
native_unit_of_measurement=JOULES_PER_TERAHASH,
native_unit_of_measurement=JOULES_PER_TERA_HASH,
state_class=SensorStateClass.MEASUREMENT,
device_class=DEVICE_CLASS_EFFICIENCY,
),
"fan_speed": MinerSensorEntityDescription(
"Fan Speed",
native_unit_of_measurement=REVOLUTIONS_PER_MINUTE,
state_class=SensorStateClass.MEASUREMENT,
device_class=SensorDeviceClass.SPEED
)
}


Expand Down Expand Up @@ -138,6 +144,20 @@ def _create_board_entity(board_num: int, sensor: str) -> MinerBoardSensor:
entity_description=description,
)

@callback
def _create_fan_entity(fan_num: int, sensor: str) -> MinerFanSensor:
"""Create a fan sensor entity."""
sensor_created.add(f"fan_{fan_num}-{sensor}")
description = ENTITY_DESCRIPTION_KEY_MAP.get(
sensor, MinerSensorEntityDescription("base_sensor")
)
return MinerFanSensor(
coordinator=coordinator,
fan_num=fan_num,
sensor=sensor,
entity_description=description,
)

await coordinator.async_config_entry_first_refresh()

sensors = []
Expand All @@ -149,6 +169,11 @@ def _create_board_entity(board_num: int, sensor: str) -> MinerBoardSensor:
_create_board_entity(board, sensor)
for sensor in ["board_temperature", "chip_temperature", "board_hashrate"]
)
for fan in range(coordinator.miner.fan_count):
sensors.extend(
_create_fan_entity(fan, sensor)
for sensor in ["fan_speed"]
)
if sensors:
async_add_entities(sensors)

Expand All @@ -169,6 +194,13 @@ def new_data_received():
for sensor in coordinator.data["board_sensors"][new_board]
if f"{new_board}-{sensor}" not in sensor_created
)
if coordinator.data["fan_sensors"]:
for new_fan in coordinator.data["fan_sensors"]:
new_sensors.extend(
_create_fan_entity(new_fan, sensor)
for sensor in coordinator.data["fan_sensors"][new_fan]
if f"{new_fan}-{sensor}" not in sensor_created
)

if new_sensors:
async_add_entities(new_sensors)
Expand Down Expand Up @@ -228,7 +260,7 @@ def native_value(self) -> StateType:


class MinerBoardSensor(CoordinatorEntity[MinerCoordinator], SensorEntity):
"""Defines a Miner Sensor."""
"""Defines a Miner Board Sensor."""

entity_description: MinerSensorEntityDescription

Expand Down Expand Up @@ -284,3 +316,62 @@ def _handle_coordinator_update(self) -> None:
def native_value(self) -> StateType:
"""Return the state of the sensor."""
return self._sensor_data


class MinerFanSensor(CoordinatorEntity[MinerCoordinator], SensorEntity):
"""Defines a Miner Fan Sensor."""

entity_description: MinerSensorEntityDescription

def __init__(
self,
coordinator: MinerCoordinator,
fan_num: int,
sensor: str,
entity_description: MinerSensorEntityDescription,
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator=coordinator)
self._attr_unique_id = f"{self.coordinator.data['mac']}-{fan_num}-{sensor}"
self._fan_num = fan_num
self._sensor = sensor
self.entity_description = entity_description
self._attr_force_update = True

@property
def _sensor_data(self):
"""Return sensor data."""
if (
self._fan_num in self.coordinator.data["fan_sensors"]
and self._sensor in self.coordinator.data["fan_sensors"][self._fan_num]
):
return self.coordinator.data["fan_sensors"][self._fan_num][self._sensor]
else:
return None

@property
def name(self) -> str | None:
"""Return name of the entity."""
return f"{self.coordinator.entry.title} Fan #{self._fan_num} {self.entity_description.key}"

@property
def device_info(self) -> entity.DeviceInfo:
"""Return device info."""
return entity.DeviceInfo(
identifiers={(DOMAIN, self.coordinator.data["mac"])},
manufacturer=self.coordinator.data["make"],
model=self.coordinator.data["model"],
sw_version=self.coordinator.data["fw_ver"],
name=f"{self.coordinator.entry.title}",
)

@callback
def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator."""

super()._handle_coordinator_update()

@property
def native_value(self) -> StateType:
"""Return the state of the sensor."""
return self._sensor_data
2 changes: 1 addition & 1 deletion custom_components/miner/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ async def async_setup_entry(
created = set()

@callback
def _create_entity(key: str) -> SwitchEntity:
def _create_entity(key: str):
"""Create a sensor entity."""
created.add(key)

Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ colorlog==6.7.0
homeassistant==2024.1.0
pip>=21.0,<23.2
ruff==0.0.267
pyasic==0.45.0
pyasic==0.45.1
pre-commit

0 comments on commit 1524400

Please sign in to comment.