diff --git a/pyasic/miners/backends/epic.py b/pyasic/miners/backends/epic.py index d303d226..a89a01c7 100644 --- a/pyasic/miners/backends/epic.py +++ b/pyasic/miners/backends/epic.py @@ -14,6 +14,7 @@ # limitations under the License. - # ------------------------------------------------------------------------------ +from pathlib import Path from typing import List, Optional from pyasic.config import MinerConfig @@ -452,3 +453,17 @@ class ePIC(ePICFirmware): return pool_data except LookupError: pass + + async def upgrade_firmware(self, file: Path | str, keep_settings: bool = True) -> bool: + + """ + Upgrade the firmware of the ePIC miner device. + + Args: + file (Path | str): The local file path of the firmware to be uploaded. + keep_settings (bool): Whether to keep the current settings after the update. + + Returns: + bool: Whether the firmware update succeeded. + """ + return await self.web.system_update(file=file, keep_settings=keep_settings) \ No newline at end of file diff --git a/pyasic/web/epic.py b/pyasic/web/epic.py index 8f0e1b41..5c19a98e 100644 --- a/pyasic/web/epic.py +++ b/pyasic/web/epic.py @@ -19,6 +19,10 @@ import json from typing import Any import httpx +import aiofiles +import aiohttp +import hashlib +from pathlib import Path from pyasic import settings from pyasic.errors import APIError @@ -46,6 +50,14 @@ class ePICWebAPI(BaseWebAPI): async with httpx.AsyncClient(transport=settings.transport()) as client: for retry_cnt in range(settings.get("get_data_retries", 1)): try: + if parameters.get("form") is not None: + form_data = parameters["form"] + form_data.add_field('password', self.pwd) + response = await client.post( + f"http://{self.ip}:{self.port}/{command}", + timeout=5, + data=form_data, + ) if post: response = await client.post( f"http://{self.ip}:{self.port}/{command}", @@ -135,3 +147,22 @@ class ePICWebAPI(BaseWebAPI): async def capabilities(self) -> dict: return await self.send_command("capabilities") + + async def system_update(self, file: Path | str, keep_settings: bool = True): + """Perform a system update by uploading a firmware file and sending a + command to initiate the update.""" + + # calculate the SHA256 checksum of the firmware file + sha256_hash = hashlib.sha256() + async with aiofiles.open(str(file), "rb") as f: + while chunk := await f.read(8192): + sha256_hash.update(chunk) + checksum = sha256_hash.hexdigest() + + # prepare the multipart/form-data request + form_data = aiohttp.FormData() + form_data.add_field('checksum', checksum) + form_data.add_field('keepsettings', str(keep_settings).lower()) + form_data.add_field('update.zip', open(file, 'rb'), filename='update.zip') + + await self.send_command("systemupdate", form=form_data) \ No newline at end of file