diff --git a/README.md b/README.md index 70d57e0..d7d1d88 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Release Downloads](https://img.shields.io/github/downloads/DerMiika/Bitaxe-HA-Integration/total)](https://github.com/DerMiika/Bitaxe-HA-Integration/releases) [![GitHub issues](https://img.shields.io/github/issues/DerMiika/Bitaxe-HA-Integration)](https://github.com/DerMiika/Bitaxe-HA-Integration/issues) -[![Version - 1.0.1](https://img.shields.io/badge/version-1.0.1-blue)](https://github.com/DerMiika/Bitaxe-HA-Integration/releases) +[![Version - 1.0.2](https://img.shields.io/badge/version-1.0.2-blue)](https://github.com/DerMiika/Bitaxe-HA-Integration/releases) This is a custom integration for Bitaxe miners in Home Assistant. diff --git a/__init__.py b/custom_components/bitaxe/__init__.py similarity index 56% rename from __init__.py rename to custom_components/bitaxe/__init__.py index 5dd5aee..59b55fc 100644 --- a/__init__.py +++ b/custom_components/bitaxe/__init__.py @@ -9,59 +9,40 @@ DOMAIN = "bitaxe" _LOGGER = logging.getLogger(__name__) -# Mapping for sensor names -SENSOR_NAME_MAP = { - "power": "Power Consumption", - "temp": "Temperature", - "hashRate": "Hash Rate", - "bestDiff": "All-Time Best Difficulty", - "bestSessionDiff": "Best Difficulty Since System Boot", - "sharesAccepted": "Shares Accepted", - "sharesRejected": "Shares Rejected", - "fanspeed": "Fan Speed", - "fanrpm": "Fan RPM", - "uptimeSeconds": "Uptime", -} - async def async_setup_entry(hass: HomeAssistant, entry: config_entries.ConfigEntry): - """Set up BitAxe from a config entry.""" ip_address = entry.data["ip_address"] + device_id = entry.unique_id or ip_address - # Create a coordinator for the data coordinator = DataUpdateCoordinator( hass, _LOGGER, - name="BitAxe Sensor Data", + name=f"BitAxe Sensor Data ({device_id})", update_method=lambda: fetch_bitaxe_data(ip_address), - update_interval=timedelta(seconds=30), # Intervall auf 30 Sekunden setzen + update_interval=timedelta(seconds=30), ) - # Start the coordinator await coordinator.async_refresh() - # Store the coordinator in hass.data - hass.data[DOMAIN] = {"coordinator": coordinator} + if DOMAIN not in hass.data: + hass.data[DOMAIN] = {} + hass.data[DOMAIN][device_id] = {"coordinator": coordinator} - # Set up the sensor platform await hass.config_entries.async_forward_entry_setups(entry, ["sensor"]) - # Schedule the update interval without threading issues async_track_time_interval( hass, - _update_coordinator(coordinator), # Callback als Funktion übergeben - timedelta(seconds=30) # Update-Intervall auf 30 Sekunden + _update_coordinator(coordinator), + timedelta(seconds=30) ) return True def _update_coordinator(coordinator: DataUpdateCoordinator): - """Create a function to refresh the coordinator safely.""" async def refresh(now): await coordinator.async_request_refresh() return refresh async def fetch_bitaxe_data(ip_address): - """Fetch data from the BitAxe API.""" url = f"http://{ip_address}/api/system/info" try: async with aiohttp.ClientSession() as session: @@ -72,4 +53,4 @@ async def fetch_bitaxe_data(ip_address): return data except Exception as e: _LOGGER.error("Error fetching data from BitAxe API: %s", e) - return None + return None \ No newline at end of file diff --git a/api.py b/custom_components/bitaxe/api.py similarity index 100% rename from api.py rename to custom_components/bitaxe/api.py diff --git a/custom_components/bitaxe/bitaxe_icon.png b/custom_components/bitaxe/bitaxe_icon.png new file mode 100644 index 0000000..63c7cbf Binary files /dev/null and b/custom_components/bitaxe/bitaxe_icon.png differ diff --git a/config_flow.py b/custom_components/bitaxe/config_flow.py similarity index 87% rename from config_flow.py rename to custom_components/bitaxe/config_flow.py index 5c63d55..8529271 100644 --- a/config_flow.py +++ b/custom_components/bitaxe/config_flow.py @@ -28,6 +28,9 @@ async def async_step_user(self, user_input=None): ) # Entry mit IP-Adresse und Gerätenamen erstellen + await self.async_set_unique_id(ip_address) # Einzigartige ID auf IP-Adresse setzen + self._abort_if_unique_id_configured() # Sicherstellen, dass die IP-Adresse nicht doppelt hinzugefügt wird + return self.async_create_entry( title=device_name, data={"ip_address": ip_address, "device_name": device_name} @@ -58,4 +61,4 @@ def __init__(self, config_entry): async def async_step_init(self, user_input=None): """Manage the options.""" - return self.async_show_form(step_id="init") + return self.async_show_form(step_id="init") \ No newline at end of file diff --git a/const.py b/custom_components/bitaxe/const.py similarity index 100% rename from const.py rename to custom_components/bitaxe/const.py diff --git a/images/Sensor.png b/custom_components/bitaxe/images/Sensor.png similarity index 100% rename from images/Sensor.png rename to custom_components/bitaxe/images/Sensor.png diff --git a/images/Setup.png b/custom_components/bitaxe/images/Setup.png similarity index 100% rename from images/Setup.png rename to custom_components/bitaxe/images/Setup.png diff --git a/manifest.json b/custom_components/bitaxe/manifest.json similarity index 52% rename from manifest.json rename to custom_components/bitaxe/manifest.json index ef6ea94..36ff55e 100644 --- a/manifest.json +++ b/custom_components/bitaxe/manifest.json @@ -1,10 +1,11 @@ { "domain": "bitaxe", - "name": "Bitaxe", - "version": "1.0.1", + "name": "Bitaxe Home Assistant Integration", + "version": "1.0.2", "config_flow": true, "documentation": "https://github.com/DerMiika/Bitaxe-HA-Integration", "requirements": [], "codeowners": ["@DerMiika"], - "iot_class": "local_push" -} + "iot_class": "local_polling", + "icon": "custom_components/bitaxe/bitaxe_icon.png" +} \ No newline at end of file diff --git a/sensor.py b/custom_components/bitaxe/sensor.py similarity index 71% rename from sensor.py rename to custom_components/bitaxe/sensor.py index 3f7fbda..a3f5827 100644 --- a/sensor.py +++ b/custom_components/bitaxe/sensor.py @@ -1,13 +1,11 @@ import logging from homeassistant.helpers.entity import Entity +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator -# Set up logging for debugging _LOGGER = logging.getLogger(__name__) -# Define the integration domain DOMAIN = "bitaxe" -# Mapping for sensor-names SENSOR_NAME_MAP = { "power": "Power Consumption", "temp": "Temperature", @@ -23,10 +21,11 @@ async def async_setup_entry(hass, entry, async_add_entities): """Set up BitAxe sensors from a config entry.""" - coordinator = hass.data[DOMAIN]["coordinator"] - device_name = entry.data["device_name"] # Gerätname abrufen + coordinator = hass.data[DOMAIN][entry.unique_id]["coordinator"] + device_name = entry.data.get("device_name", "default_device_name") # Geräte-Namen statt IP verwenden + + _LOGGER.debug(f"Setting up sensors for device: {device_name}") - # Create sensors based on the fetched data from the coordinator sensors = [ BitAxeSensor(coordinator, "power", device_name), BitAxeSensor(coordinator, "temp", device_name), @@ -40,37 +39,36 @@ async def async_setup_entry(hass, entry, async_add_entities): BitAxeSensor(coordinator, "uptimeSeconds", device_name), ] - # Add sensors to Home Assistant with an initial update async_add_entities(sensors, update_before_add=True) class BitAxeSensor(Entity): """Representation of a BitAxe sensor.""" - def __init__(self, coordinator, sensor_type, device_name): - """Initialize the sensor with its type, data coordinator, and device name.""" + def __init__(self, coordinator: DataUpdateCoordinator, sensor_type: str, device_name: str): + super().__init__() self.coordinator = coordinator self.sensor_type = sensor_type - self._attr_name = f"{device_name} {SENSOR_NAME_MAP.get(sensor_type, f'BitAxe {sensor_type.capitalize()}')}" - self._attr_unique_id = f"{DOMAIN}_{sensor_type}" + self._device_name = device_name + self._attr_name = f"{SENSOR_NAME_MAP.get(sensor_type, f'BitAxe {sensor_type.capitalize()}')} ({device_name})" + self._attr_unique_id = f"{device_name}_{sensor_type}" # Verwenden von device_name statt IP self._attr_icon = self._get_icon(sensor_type) + _LOGGER.debug(f"Initialized BitAxeSensor: {self._attr_name} with unique ID: {self._attr_unique_id}") + @property def state(self): - """Return the state of the sensor.""" - value = self.coordinator.data.get(self.sensor_type) + value = self.coordinator.data.get(self.sensor_type, None) - # Handle special formatting for uptime, power, and hash rate if self.sensor_type == "uptimeSeconds" and value is not None: return self._format_uptime(value) elif self.sensor_type == "power" and value is not None: - return round(value, 1) # Round power to one decimal place + return round(value, 1) elif self.sensor_type == "hashRate" and value is not None: - return int(value) # Display hash rate in GH/s as an integer - return value + return int(value) + return value if value is not None else "N/A" @staticmethod def _format_uptime(seconds): - """Convert uptime in seconds to a readable format.""" days, remainder = divmod(seconds, 86400) hours, remainder = divmod(remainder, 3600) minutes, seconds = divmod(remainder, 60) @@ -78,7 +76,6 @@ def _format_uptime(seconds): @property def unit_of_measurement(self): - """Return the unit of measurement for each sensor.""" if self.sensor_type == "power": return "W" elif self.sensor_type == "hashRate": @@ -92,7 +89,6 @@ def unit_of_measurement(self): return None def _get_icon(self, sensor_type): - """Return the appropriate MDI icon for each sensor type.""" if sensor_type == "bestSessionDiff": return "mdi:star" elif sensor_type == "bestDiff": @@ -111,4 +107,4 @@ def _get_icon(self, sensor_type): return "mdi:thermometer" elif sensor_type == "uptimeSeconds": return "mdi:clock" - return "mdi:help-circle" # Default icon if none matched + return "mdi:help-circle" \ No newline at end of file diff --git a/translations/en.json b/custom_components/bitaxe/translations/en.json similarity index 100% rename from translations/en.json rename to custom_components/bitaxe/translations/en.json diff --git a/hacs.json b/hacs.json index 125fd1c..f3c3501 100644 --- a/hacs.json +++ b/hacs.json @@ -1,15 +1,15 @@ { - "name": "BitAxe", + "name": "Bitaxe Home Assistant Integration", "content_in_root": false, "country": "DE", "description": "Integration for monitoring BitAxe miners in Home Assistant", - "domain": "bitaxe", - "iot_class": "local_push", + "domains": ["bitaxe"], + "iot_class": "local_polling", "render_readme": true, "documentation": "https://github.com/DerMiika/Bitaxe-HA-Integration", "issue_tracker": "https://github.com/DerMiika/Bitaxe-HA-Integration/issues", - "version": "1.0.1", + "version": "1.0.2", "zip_release": false, - "filename": "custom_components/bitaxe" + "filename": "custom_components/bitaxe", "category": "integration" }