diff --git a/pyasic/miners/backends/antminer.py b/pyasic/miners/backends/antminer.py index aa5bdd22..814c2b25 100644 --- a/pyasic/miners/backends/antminer.py +++ b/pyasic/miners/backends/antminer.py @@ -15,6 +15,8 @@ # ------------------------------------------------------------------------------ from typing import List, Optional, Union +from pathlib import Path +import logging from pyasic.config import MinerConfig, MiningModeConfig from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit @@ -124,6 +126,34 @@ class AntminerModern(BMMiner): # break # await asyncio.sleep(1) + async def upgrade_firmware(self, file: Path, keep_settings: bool = True) -> str: + """ + Upgrade the firmware of the AntMiner device. + + Args: + file (Path): Path to the firmware file. + keep_settings (bool): Whether to keep the current settings after the update. + + Returns: + str: Result of the upgrade process. + """ + if not file: + raise ValueError("File location must be provided for firmware upgrade.") + + try: + result = await self.web.update_firmware(file=file, keep_settings=keep_settings) + + if result.get("success"): + logging.info("Firmware upgrade process completed successfully for AntMiner.") + return "Firmware upgrade completed successfully." + else: + error_message = result.get("message", "Unknown error") + logging.error(f"Firmware upgrade failed. Response: {error_message}") + return f"Firmware upgrade failed. Response: {error_message}" + except Exception as e: + logging.error(f"An error occurred during the firmware upgrade process: {e}", exc_info=True) + raise + async def fault_light_on(self) -> bool: data = await self.web.blink(blink=True) if data: diff --git a/pyasic/web/antminer.py b/pyasic/web/antminer.py index 9a7a8118..13e91d49 100644 --- a/pyasic/web/antminer.py +++ b/pyasic/web/antminer.py @@ -18,8 +18,9 @@ from __future__ import annotations import asyncio import json from typing import Any - +import aiofiles import httpx +from pathlib import Path from pyasic import settings from pyasic.web.base import BaseWebAPI @@ -59,9 +60,8 @@ class AntminerModernWebAPI(BaseWebAPI): url = f"http://{self.ip}:{self.port}/cgi-bin/{command}.cgi" auth = httpx.DigestAuth(self.username, self.pwd) try: - async with httpx.AsyncClient( - transport=settings.transport(), - ) as client: + async with httpx.AsyncClient(transport=settings.transport()) as client: + if parameters: data = await client.post( url, @@ -71,14 +71,15 @@ class AntminerModernWebAPI(BaseWebAPI): ) else: data = await client.get(url, auth=auth) - except httpx.HTTPError: - pass + except httpx.HTTPError as e: + return {"success": False, "message": f"HTTP error occurred: {str(e)}"} else: if data.status_code == 200: try: return data.json() except json.decoder.JSONDecodeError: - pass + return {"success": False, "message": "Failed to decode JSON"} + return {"success": False, "message": "Unknown error occurred"} async def multicommand( self, *commands: str, ignore_errors: bool = False, allow_warning: bool = True @@ -403,3 +404,20 @@ class AntminerOldWebAPI(BaseWebAPI): dict: Information about the mining pools configured in the miner. """ return await self.send_command("miner_pools") + + async def update_firmware(self, file: Path, keep_settings: bool = True) -> dict: + """Perform a system update by uploading a firmware file and sending a command to initiate the update.""" + + async with aiofiles.open(file, "rb") as firmware: + file_content = await firmware.read() + + parameters = { + "file": (file.name, file_content, "application/octet-stream"), + "filename": file.name, + "keep_settings": keep_settings + } + + return await self.send_command( + command="upgrade", + **parameters + )