From c4e32d9cfb50ee424005fac28bf03621174adda2 Mon Sep 17 00:00:00 2001 From: Stefan Date: Thu, 14 Nov 2024 09:52:28 +0000 Subject: [PATCH 01/10] Fix repository structure for HACS compatibility - Move integration files into 'custom_components/bitaxe/' - Add 'hacs.json' with necessary HACS metadata - Verify 'manifest.json' for required fields This resolves the error: Repository structure for v1.0.1 is not compliant Now the repository should be compatible with HACS and can be added without issues. --- __init__.py => custom_components/bitaxe/__init__.py | 0 api.py => custom_components/bitaxe/api.py | 0 .../bitaxe/config_flow.py | 0 const.py => custom_components/bitaxe/const.py | 0 .../bitaxe/images}/Sensor.png | Bin .../bitaxe/images}/Setup.png | Bin .../bitaxe/manifest.json | 4 ++-- sensor.py => custom_components/bitaxe/sensor.py | 0 .../bitaxe/translations}/en.json | 0 hacs.json | 6 +++--- 10 files changed, 5 insertions(+), 5 deletions(-) rename __init__.py => custom_components/bitaxe/__init__.py (100%) rename api.py => custom_components/bitaxe/api.py (100%) rename config_flow.py => custom_components/bitaxe/config_flow.py (100%) rename const.py => custom_components/bitaxe/const.py (100%) rename {images => custom_components/bitaxe/images}/Sensor.png (100%) rename {images => custom_components/bitaxe/images}/Setup.png (100%) rename manifest.json => custom_components/bitaxe/manifest.json (75%) rename sensor.py => custom_components/bitaxe/sensor.py (100%) rename {translations => custom_components/bitaxe/translations}/en.json (100%) diff --git a/__init__.py b/custom_components/bitaxe/__init__.py similarity index 100% rename from __init__.py rename to custom_components/bitaxe/__init__.py 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/config_flow.py b/custom_components/bitaxe/config_flow.py similarity index 100% rename from config_flow.py rename to custom_components/bitaxe/config_flow.py 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 75% rename from manifest.json rename to custom_components/bitaxe/manifest.json index ef6ea94..25689eb 100644 --- a/manifest.json +++ b/custom_components/bitaxe/manifest.json @@ -1,10 +1,10 @@ { "domain": "bitaxe", - "name": "Bitaxe", + "name": "Bitaxe Integration", "version": "1.0.1", "config_flow": true, "documentation": "https://github.com/DerMiika/Bitaxe-HA-Integration", "requirements": [], "codeowners": ["@DerMiika"], - "iot_class": "local_push" + "iot_class": "local_polling" } diff --git a/sensor.py b/custom_components/bitaxe/sensor.py similarity index 100% rename from sensor.py rename to custom_components/bitaxe/sensor.py 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..a85c611 100644 --- a/hacs.json +++ b/hacs.json @@ -1,10 +1,10 @@ { - "name": "BitAxe", + "name": "BitAxe 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", From 63fc45909c9aff87442abb117a749f6318f3a9f1 Mon Sep 17 00:00:00 2001 From: Stefan Date: Thu, 14 Nov 2024 10:00:28 +0000 Subject: [PATCH 02/10] Fixed Naming of the HACS Integration and add fixed Syntax --- custom_components/bitaxe/manifest.json | 2 +- hacs.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/custom_components/bitaxe/manifest.json b/custom_components/bitaxe/manifest.json index 25689eb..4e23674 100644 --- a/custom_components/bitaxe/manifest.json +++ b/custom_components/bitaxe/manifest.json @@ -1,6 +1,6 @@ { "domain": "bitaxe", - "name": "Bitaxe Integration", + "name": "Bitaxe Home Assistant Integration", "version": "1.0.1", "config_flow": true, "documentation": "https://github.com/DerMiika/Bitaxe-HA-Integration", diff --git a/hacs.json b/hacs.json index a85c611..f65baeb 100644 --- a/hacs.json +++ b/hacs.json @@ -1,5 +1,5 @@ { - "name": "BitAxe Integration", + "name": "Bitaxe Home Assistant Integration", "content_in_root": false, "country": "DE", "description": "Integration for monitoring BitAxe miners in Home Assistant", @@ -10,6 +10,6 @@ "issue_tracker": "https://github.com/DerMiika/Bitaxe-HA-Integration/issues", "version": "1.0.1", "zip_release": false, - "filename": "custom_components/bitaxe" + "filename": "custom_components/bitaxe", "category": "integration" } From dd1543fc9e87c025526354618ccc5d75e752c8e4 Mon Sep 17 00:00:00 2001 From: Stefan Date: Thu, 14 Nov 2024 10:24:08 +0000 Subject: [PATCH 03/10] Add Bitaxe Logo as integration icon --- .../bitaxe/images/bitaxe-512x512.png | Bin 0 -> 53133 bytes custom_components/bitaxe/manifest.json | 3 ++- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 custom_components/bitaxe/images/bitaxe-512x512.png diff --git a/custom_components/bitaxe/images/bitaxe-512x512.png b/custom_components/bitaxe/images/bitaxe-512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..63c7cbf89e76f4d7e52833b7017781c2335bbd1f GIT binary patch literal 53133 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

QEnkTx%fAiEvs- zmazMlX++5L5dPr?{oqEh*xvvil!0cX!u%CY`4^%c%xLagykMbsxe4#bucA$Ofn^qi zxiPLNh?Qi&{z9%!x%9cED!JWIo}w{un(|y;BShcuze6LPj)vJ(rJNIEDwU+r{RRJ0 zWH$+Q5M~^+3p*t37uRR)01sK*N%UrK@=(2GmYbeOxsxaJjLb)YIv4xL^H+GTwfgy6 zQ;P7SmqneeKXiU%xMO~Oo{|qDq_B=G_4DR$U!$+SMjRUQ;*O3T>T_Nv8J*x#Q%t2DLFzaLez| zW8ys=d+oo>8^8Mck9_gx^iex&`HonkuZs@cn2u#Jg3z5%ySE$X3f4S$_jkpX4GKhb zf;@}<@WgXFula(+>~!;4v$Tr{vAC8JP3H-kHuvb4p$t;D^*B>UKPbQa#Qj>Zshu8M z4Ht;*UD~`&+YobJ^Uh?__%dl?pu7R*gQ(jEV$9KOqG-3%u4jDl!oT(4+zV+iS*zkG z?sL+|dBN-ayR2xiaLRSfdsfZSsU}8$=NUII19sa>Y@kJzc6Ccm!367bYr#x{?_AUG z(rDvHuc8nLsEicci5O%KGWGyk<%uGDOr~)H&#W<@=3C`RfPaHSkTfs>4v=e3STr;T z;5Ga%)U$h^*SBWMk83$rZiQp^ZxItZ8YtH^6!ie*qR)wqyau%+A}6T(&_`ZnZ(;vi z&j|0|uOS2u-_dk^l7S2U0-Z48_24Upzp(hkiP%x-zhV^Ng!VlG4nLjp0e#3%=?cipFLM9Y6$#cAV$Us&XD|y!t_(m>7m%~td{>E%Nq|?m zW&#sLDWv{0&7p0K^59@BbsAgK%mCC|Syx8*7>DovhWCZR@c!o7oJ=|DwbVAxzn$Gg z2Rn;X++GUsVa)7j`DS_SdzY%x{DHJ-8=zhr{a>-Emtc=g27=PBF1iP^J%&Ap%onqK zLHgM>Eq^6DF1?`?wv=bde=Cs;tdip$9@5EU2nRg<#X;a7n45EO=reEgnPG{dlq#3! z=l@SpK{lZAAqZ;zmhCYK;_N_HO1#iUK&cTb1-1SB-*!$Rzy=hd#2qfdKxyysHH&eI zx%mm^%d*eV^565H4BLnrx7q%kol2pmLRgr}(!EpBZn= z;XT7lgBtnE|2woKuR-osvKA9PXaZt?eebbPn(ZN(_pH)m-*o6R8xcZ?q46@~-{!sm z+2w8b5r#TwRrjvHdhEC5TQ5%bfy|sd^0uFbVSg93Or9?I?KUXEDyUnk^c#Y6urm)E zfh>>IUMLq@9mP+uWg2l7D}( z@zqZ6-)d=KB7awk?n_UPf5#XBz4^P{a*y-1G5^^uD8wcaxQ{iKeh&WIIVt!FA^3}c zp=bq$zgy-1`uo3z{BK15w?_WAYyNkR{AX&s-l>0Q@M+Ysi($ HSO)(;ffhjN literal 0 HcmV?d00001 diff --git a/custom_components/bitaxe/manifest.json b/custom_components/bitaxe/manifest.json index 4e23674..e1d521f 100644 --- a/custom_components/bitaxe/manifest.json +++ b/custom_components/bitaxe/manifest.json @@ -6,5 +6,6 @@ "documentation": "https://github.com/DerMiika/Bitaxe-HA-Integration", "requirements": [], "codeowners": ["@DerMiika"], - "iot_class": "local_polling" + "iot_class": "local_polling", + "icon": "custom_components/bitaxe/images/bitaxe-512x512.png } From 1ca0269dcd74cc01e2a368e3cb69408d14ddafa7 Mon Sep 17 00:00:00 2001 From: Stefan Date: Thu, 14 Nov 2024 10:26:28 +0000 Subject: [PATCH 04/10] Fixed manifest --- custom_components/bitaxe/manifest.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/bitaxe/manifest.json b/custom_components/bitaxe/manifest.json index e1d521f..da4c140 100644 --- a/custom_components/bitaxe/manifest.json +++ b/custom_components/bitaxe/manifest.json @@ -7,5 +7,5 @@ "requirements": [], "codeowners": ["@DerMiika"], "iot_class": "local_polling", - "icon": "custom_components/bitaxe/images/bitaxe-512x512.png -} + "icon": "custom_components/bitaxe/images/bitaxe-512x512.png" +} \ No newline at end of file From 7161f9f65f68cd61f2f6f335ae603f2376ab4dfc Mon Sep 17 00:00:00 2001 From: Stefan Date: Thu, 14 Nov 2024 10:29:25 +0000 Subject: [PATCH 05/10] fixed bitaxe_icon.png --- .../{images/bitaxe-512x512.png => bitaxe_icon.png} | Bin custom_components/bitaxe/manifest.json | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename custom_components/bitaxe/{images/bitaxe-512x512.png => bitaxe_icon.png} (100%) diff --git a/custom_components/bitaxe/images/bitaxe-512x512.png b/custom_components/bitaxe/bitaxe_icon.png similarity index 100% rename from custom_components/bitaxe/images/bitaxe-512x512.png rename to custom_components/bitaxe/bitaxe_icon.png diff --git a/custom_components/bitaxe/manifest.json b/custom_components/bitaxe/manifest.json index da4c140..99eefa3 100644 --- a/custom_components/bitaxe/manifest.json +++ b/custom_components/bitaxe/manifest.json @@ -7,5 +7,5 @@ "requirements": [], "codeowners": ["@DerMiika"], "iot_class": "local_polling", - "icon": "custom_components/bitaxe/images/bitaxe-512x512.png" + "icon": "custom_components/bitaxe/bitaxe_icon.png" } \ No newline at end of file From be1001aec4a1bfb830577f7bb96c59985493a5f0 Mon Sep 17 00:00:00 2001 From: Stefan Date: Thu, 14 Nov 2024 10:50:47 +0000 Subject: [PATCH 06/10] Fix unique_id generation for Bitaxe sensors to support multiple devices - Updated unique_id generation to include device-specific identifiers (device_id) alongside sensor type. - Previous implementation used `{DOMAIN}_{sensor_type}`, causing ID conflicts when multiple Bitaxe devices are added. - New unique_id format `{device_id}_{sensor_type}` ensures each sensor has a unique identifier, allowing Home Assistant to recognize and display all devices correctly. This change prevents Home Assistant from ignoring duplicate sensors across devices, enabling reliable multi-device support for the Bitaxe integration. --- custom_components/bitaxe/sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/bitaxe/sensor.py b/custom_components/bitaxe/sensor.py index 3f7fbda..b7f77d7 100644 --- a/custom_components/bitaxe/sensor.py +++ b/custom_components/bitaxe/sensor.py @@ -51,7 +51,7 @@ def __init__(self, coordinator, sensor_type, device_name): 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._attr_unique_id = f"{device_id}_{sensor_type}" self._attr_icon = self._get_icon(sensor_type) @property From 14f5e54de99092dcf9ee24e272b3b42a18d28567 Mon Sep 17 00:00:00 2001 From: Stefan Date: Thu, 14 Nov 2024 10:51:41 +0000 Subject: [PATCH 07/10] bump up version to 1.0.2 --- custom_components/bitaxe/manifest.json | 2 +- hacs.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/bitaxe/manifest.json b/custom_components/bitaxe/manifest.json index 99eefa3..36ff55e 100644 --- a/custom_components/bitaxe/manifest.json +++ b/custom_components/bitaxe/manifest.json @@ -1,7 +1,7 @@ { "domain": "bitaxe", "name": "Bitaxe Home Assistant Integration", - "version": "1.0.1", + "version": "1.0.2", "config_flow": true, "documentation": "https://github.com/DerMiika/Bitaxe-HA-Integration", "requirements": [], diff --git a/hacs.json b/hacs.json index f65baeb..f3c3501 100644 --- a/hacs.json +++ b/hacs.json @@ -8,7 +8,7 @@ "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", "category": "integration" From 4176a8df4688ad97f7d39312082f9cad75543fe9 Mon Sep 17 00:00:00 2001 From: Stefan Date: Thu, 14 Nov 2024 11:05:32 +0000 Subject: [PATCH 08/10] Refactor Bitaxe integration to support multiple devices and unique sensor IDs - Updated async_setup_entry in sensor.py to pass a unique device ID for each Bitaxe device. - Enhanced BitAxeSensor class to generate unique_id using device_id and sensor_type. - Fixed potential import issues and ensured each sensor entity has a unique name and identifier. - Refactored entity initialization to improve compatibility with multiple Bitaxe devices. This update resolves issues with duplicate sensor IDs and enables reliable multi-device support. --- README.md | 2 +- custom_components/bitaxe/__init__.py | 38 ++++++++++++++++++++++++--- custom_components/bitaxe/sensor.py | 39 +++++++++++++++------------- 3 files changed, 56 insertions(+), 23 deletions(-) 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/custom_components/bitaxe/__init__.py b/custom_components/bitaxe/__init__.py index 5dd5aee..99d87e1 100644 --- a/custom_components/bitaxe/__init__.py +++ b/custom_components/bitaxe/__init__.py @@ -4,6 +4,7 @@ from homeassistant import config_entries from homeassistant.core import HomeAssistant from homeassistant.helpers.update_coordinator import DataUpdateCoordinator +from homeassistant.helpers.entity import Entity from homeassistant.helpers.event import async_track_time_interval DOMAIN = "bitaxe" @@ -26,21 +27,24 @@ 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 # Generiere eine eindeutige Geräte-ID # 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), # Interval auf 30 Sekunden setzen ) # Start the coordinator await coordinator.async_refresh() - # Store the coordinator in hass.data - hass.data[DOMAIN] = {"coordinator": coordinator} + # Store the coordinator in hass.data with the unique device ID + 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"]) @@ -73,3 +77,29 @@ async def fetch_bitaxe_data(ip_address): except Exception as e: _LOGGER.error("Error fetching data from BitAxe API: %s", e) return None + +class BitAxeSensor(Entity): + """Representation of a BitAxe sensor.""" + + def __init__(self, coordinator, sensor_type, device_id): + """Initialize the BitAxe sensor.""" + super().__init__() + self.coordinator = coordinator + self._sensor_type = sensor_type + self._device_id = device_id + self._attr_unique_id = f"{self._device_id}_{self._sensor_type}" + self._attr_name = f"{SENSOR_NAME_MAP.get(sensor_type, sensor_type)} ({device_id})" + + @property + def state(self): + """Return the state of the sensor.""" + return self.coordinator.data.get(self._sensor_type) + + @property + def available(self): + """Return if the sensor is available.""" + return self.coordinator.last_update_success + + async def async_update(self): + """Update the sensor.""" + await self.coordinator.async_request_refresh() \ No newline at end of file diff --git a/custom_components/bitaxe/sensor.py b/custom_components/bitaxe/sensor.py index b7f77d7..0e0e3c0 100644 --- a/custom_components/bitaxe/sensor.py +++ b/custom_components/bitaxe/sensor.py @@ -1,5 +1,6 @@ import logging from homeassistant.helpers.entity import Entity +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator # Set up logging for debugging _LOGGER = logging.getLogger(__name__) @@ -7,7 +8,7 @@ # Define the integration domain DOMAIN = "bitaxe" -# Mapping for sensor-names +# Mapping for sensor names SENSOR_NAME_MAP = { "power": "Power Consumption", "temp": "Temperature", @@ -23,21 +24,22 @@ 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 + # Fetch coordinator for the specific device from hass.data using a unique device ID + coordinator = hass.data[DOMAIN][entry.unique_id]["coordinator"] + device_id = entry.unique_id or entry.data["device_name"] # Eindeutige ID oder Geräte-Name verwenden # Create sensors based on the fetched data from the coordinator sensors = [ - BitAxeSensor(coordinator, "power", device_name), - BitAxeSensor(coordinator, "temp", device_name), - BitAxeSensor(coordinator, "hashRate", device_name), - BitAxeSensor(coordinator, "bestDiff", device_name), - BitAxeSensor(coordinator, "bestSessionDiff", device_name), - BitAxeSensor(coordinator, "sharesAccepted", device_name), - BitAxeSensor(coordinator, "sharesRejected", device_name), - BitAxeSensor(coordinator, "fanspeed", device_name), - BitAxeSensor(coordinator, "fanrpm", device_name), - BitAxeSensor(coordinator, "uptimeSeconds", device_name), + BitAxeSensor(coordinator, "power", device_id), + BitAxeSensor(coordinator, "temp", device_id), + BitAxeSensor(coordinator, "hashRate", device_id), + BitAxeSensor(coordinator, "bestDiff", device_id), + BitAxeSensor(coordinator, "bestSessionDiff", device_id), + BitAxeSensor(coordinator, "sharesAccepted", device_id), + BitAxeSensor(coordinator, "sharesRejected", device_id), + BitAxeSensor(coordinator, "fanspeed", device_id), + BitAxeSensor(coordinator, "fanrpm", device_id), + BitAxeSensor(coordinator, "uptimeSeconds", device_id), ] # Add sensors to Home Assistant with an initial update @@ -46,12 +48,13 @@ async def async_setup_entry(hass, entry, async_add_entities): 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_id: str): + """Initialize the sensor with its type, data coordinator, and device ID.""" 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"{device_id}_{sensor_type}" + self._device_id = device_id # Speichern des Geräte-ID + self._attr_name = f"{SENSOR_NAME_MAP.get(sensor_type, f'BitAxe {sensor_type.capitalize()}')} ({device_id})" + self._attr_unique_id = f"{device_id}_{sensor_type}" # Verwenden von device_id und sensor_type self._attr_icon = self._get_icon(sensor_type) @property @@ -111,4 +114,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" # Default icon if none matched \ No newline at end of file From c08e4864ba16055204d2171db388e75e7788d3a0 Mon Sep 17 00:00:00 2001 From: Stefan Date: Thu, 14 Nov 2024 11:20:31 +0000 Subject: [PATCH 09/10] Refactor BitAxe Integration: Add unique ID handling and multi-device support - Updated config_flow.py to set unique IDs based on IP addresses, preventing duplicate entries. - Refined async_setup_entry in __init__.py to store coordinators per device and ensure unique identifiers. - Enhanced sensor.py to initialize each sensor with a device-specific unique_id, improving compatibility with multiple devices. - Added robust error handling and logging across all files for easier debugging and tracking. - Ensured consistent naming and icon management for all sensors. This update resolves issues with duplicate sensors and allows reliable support for multiple BitAxe devices within the same Home Assistant instance. --- custom_components/bitaxe/__init__.py | 59 +++---------------------- custom_components/bitaxe/config_flow.py | 5 ++- custom_components/bitaxe/sensor.py | 33 ++++++-------- 3 files changed, 22 insertions(+), 75 deletions(-) diff --git a/custom_components/bitaxe/__init__.py b/custom_components/bitaxe/__init__.py index 99d87e1..59b55fc 100644 --- a/custom_components/bitaxe/__init__.py +++ b/custom_components/bitaxe/__init__.py @@ -4,68 +4,45 @@ from homeassistant import config_entries from homeassistant.core import HomeAssistant from homeassistant.helpers.update_coordinator import DataUpdateCoordinator -from homeassistant.helpers.entity import Entity from homeassistant.helpers.event import async_track_time_interval 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 # Generiere eine eindeutige Geräte-ID + device_id = entry.unique_id or ip_address - # Create a coordinator for the data coordinator = DataUpdateCoordinator( hass, _LOGGER, name=f"BitAxe Sensor Data ({device_id})", update_method=lambda: fetch_bitaxe_data(ip_address), - update_interval=timedelta(seconds=30), # Interval auf 30 Sekunden setzen + update_interval=timedelta(seconds=30), ) - # Start the coordinator await coordinator.async_refresh() - # Store the coordinator in hass.data with the unique device ID 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: @@ -76,30 +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 - -class BitAxeSensor(Entity): - """Representation of a BitAxe sensor.""" - - def __init__(self, coordinator, sensor_type, device_id): - """Initialize the BitAxe sensor.""" - super().__init__() - self.coordinator = coordinator - self._sensor_type = sensor_type - self._device_id = device_id - self._attr_unique_id = f"{self._device_id}_{self._sensor_type}" - self._attr_name = f"{SENSOR_NAME_MAP.get(sensor_type, sensor_type)} ({device_id})" - - @property - def state(self): - """Return the state of the sensor.""" - return self.coordinator.data.get(self._sensor_type) - - @property - def available(self): - """Return if the sensor is available.""" - return self.coordinator.last_update_success - - async def async_update(self): - """Update the sensor.""" - await self.coordinator.async_request_refresh() \ No newline at end of file + return None \ No newline at end of file diff --git a/custom_components/bitaxe/config_flow.py b/custom_components/bitaxe/config_flow.py index 5c63d55..8529271 100644 --- a/custom_components/bitaxe/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/custom_components/bitaxe/sensor.py b/custom_components/bitaxe/sensor.py index 0e0e3c0..805f268 100644 --- a/custom_components/bitaxe/sensor.py +++ b/custom_components/bitaxe/sensor.py @@ -2,13 +2,10 @@ 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", @@ -24,11 +21,11 @@ async def async_setup_entry(hass, entry, async_add_entities): """Set up BitAxe sensors from a config entry.""" - # Fetch coordinator for the specific device from hass.data using a unique device ID coordinator = hass.data[DOMAIN][entry.unique_id]["coordinator"] - device_id = entry.unique_id or entry.data["device_name"] # Eindeutige ID oder Geräte-Name verwenden + device_id = entry.unique_id or entry.data.get("device_name", "default_device_id") + + _LOGGER.debug(f"Setting up sensors for device: {device_id}") - # Create sensors based on the fetched data from the coordinator sensors = [ BitAxeSensor(coordinator, "power", device_id), BitAxeSensor(coordinator, "temp", device_id), @@ -42,38 +39,36 @@ async def async_setup_entry(hass, entry, async_add_entities): BitAxeSensor(coordinator, "uptimeSeconds", device_id), ] - # 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: DataUpdateCoordinator, sensor_type: str, device_id: str): - """Initialize the sensor with its type, data coordinator, and device ID.""" + super().__init__() self.coordinator = coordinator self.sensor_type = sensor_type - self._device_id = device_id # Speichern des Geräte-ID + self._device_id = device_id self._attr_name = f"{SENSOR_NAME_MAP.get(sensor_type, f'BitAxe {sensor_type.capitalize()}')} ({device_id})" - self._attr_unique_id = f"{device_id}_{sensor_type}" # Verwenden von device_id und sensor_type + self._attr_unique_id = f"{device_id}_{sensor_type}" 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) @@ -81,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": @@ -95,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": @@ -114,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 \ No newline at end of file + return "mdi:help-circle" \ No newline at end of file From 94c13e252e8a0319c69e3e89faeed35caba30ac8 Mon Sep 17 00:00:00 2001 From: Stefan Date: Thu, 14 Nov 2024 11:28:34 +0000 Subject: [PATCH 10/10] Update BitAxe integration to use device name in sensor entity IDs - Modified sensor.py to use `device_name` instead of IP address in sensor unique_id and entity name. - Ensured that entity_id reflects the user-defined device name, improving readability and usability. - Adjusted `async_setup_entry` and `BitAxeSensor` class to incorporate `device_name` for clear, descriptive sensor IDs. This change improves the identification of sensors by using meaningful names rather than IP addresses in entity IDs. --- custom_components/bitaxe/sensor.py | 32 +++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/custom_components/bitaxe/sensor.py b/custom_components/bitaxe/sensor.py index 805f268..a3f5827 100644 --- a/custom_components/bitaxe/sensor.py +++ b/custom_components/bitaxe/sensor.py @@ -22,21 +22,21 @@ async def async_setup_entry(hass, entry, async_add_entities): """Set up BitAxe sensors from a config entry.""" coordinator = hass.data[DOMAIN][entry.unique_id]["coordinator"] - device_id = entry.unique_id or entry.data.get("device_name", "default_device_id") + 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_id}") + _LOGGER.debug(f"Setting up sensors for device: {device_name}") sensors = [ - BitAxeSensor(coordinator, "power", device_id), - BitAxeSensor(coordinator, "temp", device_id), - BitAxeSensor(coordinator, "hashRate", device_id), - BitAxeSensor(coordinator, "bestDiff", device_id), - BitAxeSensor(coordinator, "bestSessionDiff", device_id), - BitAxeSensor(coordinator, "sharesAccepted", device_id), - BitAxeSensor(coordinator, "sharesRejected", device_id), - BitAxeSensor(coordinator, "fanspeed", device_id), - BitAxeSensor(coordinator, "fanrpm", device_id), - BitAxeSensor(coordinator, "uptimeSeconds", device_id), + BitAxeSensor(coordinator, "power", device_name), + BitAxeSensor(coordinator, "temp", device_name), + BitAxeSensor(coordinator, "hashRate", device_name), + BitAxeSensor(coordinator, "bestDiff", device_name), + BitAxeSensor(coordinator, "bestSessionDiff", device_name), + BitAxeSensor(coordinator, "sharesAccepted", device_name), + BitAxeSensor(coordinator, "sharesRejected", device_name), + BitAxeSensor(coordinator, "fanspeed", device_name), + BitAxeSensor(coordinator, "fanrpm", device_name), + BitAxeSensor(coordinator, "uptimeSeconds", device_name), ] async_add_entities(sensors, update_before_add=True) @@ -44,13 +44,13 @@ async def async_setup_entry(hass, entry, async_add_entities): class BitAxeSensor(Entity): """Representation of a BitAxe sensor.""" - def __init__(self, coordinator: DataUpdateCoordinator, sensor_type: str, device_id: str): + def __init__(self, coordinator: DataUpdateCoordinator, sensor_type: str, device_name: str): super().__init__() self.coordinator = coordinator self.sensor_type = sensor_type - self._device_id = device_id - self._attr_name = f"{SENSOR_NAME_MAP.get(sensor_type, f'BitAxe {sensor_type.capitalize()}')} ({device_id})" - self._attr_unique_id = f"{device_id}_{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}")