From 4adb7dc92c13f102dd2e214fe0da031bdbf2961b Mon Sep 17 00:00:00 2001 From: 1e9abhi1e10 <2311abhiptdr@gmail.com> Date: Sat, 22 Jun 2024 08:06:44 +0530 Subject: [PATCH 1/5] feat: Add update firmware for ePIC miner --- pyasic/miners/backends/epic.py | 72 ++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/pyasic/miners/backends/epic.py b/pyasic/miners/backends/epic.py index a3c60fdc..bfbf73a7 100644 --- a/pyasic/miners/backends/epic.py +++ b/pyasic/miners/backends/epic.py @@ -14,6 +14,11 @@ # limitations under the License. - # ------------------------------------------------------------------------------ +import logging +import aiofiles +import hashlib +import aiohttp +from pathlib import Path from typing import List, Optional from pyasic.config import MinerConfig @@ -450,3 +455,70 @@ class ePIC(ePICFirmware): return pool_data except LookupError: pass + + async def upgrade_firmware(self, file: Path, keepsettings: bool, password: str): + + """ + Upgrade the firmware of the ePIC miner device. + + Args: + file (Path): The local file path of the firmware to be uploaded. + keepsettings (bool): Whether to keep the current settings after the update. + password (str): The password for authentication. + + Returns: + str: Confirmation message after upgrading the firmware. + """ + try: + logging.info("Starting firmware upgrade process for ePIC miner.") + + if not file: + raise ValueError("File location must be provided for firmware upgrade.") + + # calculate the SHA256 checksum of the firmware file + sha256_hash = hashlib.sha256() + async with aiofiles.open(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(keepsettings).lower()) + form_data.add_field('password', password) + form_data.add_field('update.zip', open(file, 'rb'), filename='update.zip') + + # Send the POST request to the ePIC miner device + async with aiohttp.ClientSession() as session: + async with session.post(f"http://{self.ip}:{self.port}/systemupdate", data=form_data) as response: + if response.status == 200: + result = await response.json() + if result.get("result"): + logging.info("Firmware upgrade process completed successfully for ePIC miner.") + return "Firmware upgrade completed successfully." + else: + error = result.get("error", "Unknown error") + logging.error(f"Firmware upgrade failed: {error}") + raise Exception(f"Firmware upgrade failed: {error}") + else: + logging.error(f"Firmware upgrade failed with status code: {response.status}") + raise Exception(f"Firmware upgrade failed with status code: {response.status}") + + except FileNotFoundError as e: + logging.error(f"File not found during the firmware upgrade process: {e}") + raise + except ValueError as e: + logging.error( + f"Validation error occurred during the firmware upgrade process: {e}" + ) + raise + except OSError as e: + logging.error(f"OS error occurred during the firmware upgrade process: {e}") + raise + except Exception as e: + logging.error( + f"An unexpected error occurred during the firmware upgrade process: {e}", + exc_info=True, + ) + raise \ No newline at end of file From 7803fa60f28e7ffe06e221b904f85739cef8f6bd Mon Sep 17 00:00:00 2001 From: 1e9abhi1e10 <2311abhiptdr@gmail.com> Date: Sat, 22 Jun 2024 08:12:03 +0530 Subject: [PATCH 2/5] removed trailing whitespace --- pyasic/miners/backends/epic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyasic/miners/backends/epic.py b/pyasic/miners/backends/epic.py index bfbf73a7..03ee6673 100644 --- a/pyasic/miners/backends/epic.py +++ b/pyasic/miners/backends/epic.py @@ -16,8 +16,8 @@ import logging import aiofiles -import hashlib -import aiohttp +import hashlib +import aiohttp from pathlib import Path from typing import List, Optional From bd9592c19cc2653d7ffc7d22a7e68968d81153a9 Mon Sep 17 00:00:00 2001 From: 1e9abhi1e10 <2311abhiptdr@gmail.com> Date: Sun, 23 Jun 2024 08:38:35 +0530 Subject: [PATCH 3/5] Use web attribute --- pyasic/miners/backends/epic.py | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/pyasic/miners/backends/epic.py b/pyasic/miners/backends/epic.py index 03ee6673..126bd2bd 100644 --- a/pyasic/miners/backends/epic.py +++ b/pyasic/miners/backends/epic.py @@ -490,20 +490,19 @@ class ePIC(ePICFirmware): form_data.add_field('update.zip', open(file, 'rb'), filename='update.zip') # Send the POST request to the ePIC miner device - async with aiohttp.ClientSession() as session: - async with session.post(f"http://{self.ip}:{self.port}/systemupdate", data=form_data) as response: - if response.status == 200: - result = await response.json() - if result.get("result"): - logging.info("Firmware upgrade process completed successfully for ePIC miner.") - return "Firmware upgrade completed successfully." - else: - error = result.get("error", "Unknown error") - logging.error(f"Firmware upgrade failed: {error}") - raise Exception(f"Firmware upgrade failed: {error}") + async with self.web.post(f"http://{self.ip}:{self.port}/systemupdate", data=form_data) as response: + if response.status == 200: + result = await response.json() + if result.get("result"): + logging.info("Firmware upgrade process completed successfully for ePIC miner.") + return "Firmware upgrade completed successfully." else: - logging.error(f"Firmware upgrade failed with status code: {response.status}") - raise Exception(f"Firmware upgrade failed with status code: {response.status}") + error = result.get("error", "Unknown error") + logging.error(f"Firmware upgrade failed: {error}") + raise Exception(f"Firmware upgrade failed: {error}") + else: + logging.error(f"Firmware upgrade failed with status code: {response.status}") + raise Exception(f"Firmware upgrade failed with status code: {response.status}") except FileNotFoundError as e: logging.error(f"File not found during the firmware upgrade process: {e}") From 092126bded08618aa02fe40d2bbee07adb324190 Mon Sep 17 00:00:00 2001 From: 1e9abhi1e10 <2311abhiptdr@gmail.com> Date: Wed, 3 Jul 2024 08:43:22 +0530 Subject: [PATCH 4/5] Added checksum validation and command handling --- pyasic/miners/backends/epic.py | 68 +++------------------------------- pyasic/web/epic.py | 31 ++++++++++++++++ 2 files changed, 37 insertions(+), 62 deletions(-) diff --git a/pyasic/miners/backends/epic.py b/pyasic/miners/backends/epic.py index 126bd2bd..ad7e7d3f 100644 --- a/pyasic/miners/backends/epic.py +++ b/pyasic/miners/backends/epic.py @@ -14,10 +14,6 @@ # limitations under the License. - # ------------------------------------------------------------------------------ -import logging -import aiofiles -import hashlib -import aiohttp from pathlib import Path from typing import List, Optional @@ -455,69 +451,17 @@ class ePIC(ePICFirmware): return pool_data except LookupError: pass - - async def upgrade_firmware(self, file: Path, keepsettings: bool, password: str): + + async def upgrade_firmware(self, file: Path | str, keep_settings: bool = True) -> bool: """ Upgrade the firmware of the ePIC miner device. Args: - file (Path): The local file path of the firmware to be uploaded. - keepsettings (bool): Whether to keep the current settings after the update. - password (str): The password for authentication. + 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: - str: Confirmation message after upgrading the firmware. + bool: Whether the firmware update succeeded. """ - try: - logging.info("Starting firmware upgrade process for ePIC miner.") - - if not file: - raise ValueError("File location must be provided for firmware upgrade.") - - # calculate the SHA256 checksum of the firmware file - sha256_hash = hashlib.sha256() - async with aiofiles.open(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(keepsettings).lower()) - form_data.add_field('password', password) - form_data.add_field('update.zip', open(file, 'rb'), filename='update.zip') - - # Send the POST request to the ePIC miner device - async with self.web.post(f"http://{self.ip}:{self.port}/systemupdate", data=form_data) as response: - if response.status == 200: - result = await response.json() - if result.get("result"): - logging.info("Firmware upgrade process completed successfully for ePIC miner.") - return "Firmware upgrade completed successfully." - else: - error = result.get("error", "Unknown error") - logging.error(f"Firmware upgrade failed: {error}") - raise Exception(f"Firmware upgrade failed: {error}") - else: - logging.error(f"Firmware upgrade failed with status code: {response.status}") - raise Exception(f"Firmware upgrade failed with status code: {response.status}") - - except FileNotFoundError as e: - logging.error(f"File not found during the firmware upgrade process: {e}") - raise - except ValueError as e: - logging.error( - f"Validation error occurred during the firmware upgrade process: {e}" - ) - raise - except OSError as e: - logging.error(f"OS error occurred during the firmware upgrade process: {e}") - raise - except Exception as e: - logging.error( - f"An unexpected error occurred during the firmware upgrade process: {e}", - exc_info=True, - ) - raise \ No newline at end of file + 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 From e6f9a33b3c58191073d1aa7aad9b1fd1502656d9 Mon Sep 17 00:00:00 2001 From: 1e9abhi1e10 <2311abhiptdr@gmail.com> Date: Wed, 3 Jul 2024 08:50:50 +0530 Subject: [PATCH 5/5] Removed trailing whitespace --- pyasic/miners/backends/epic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyasic/miners/backends/epic.py b/pyasic/miners/backends/epic.py index ad7e7d3f..b357b5a6 100644 --- a/pyasic/miners/backends/epic.py +++ b/pyasic/miners/backends/epic.py @@ -451,7 +451,7 @@ class ePIC(ePICFirmware): return pool_data except LookupError: pass - + async def upgrade_firmware(self, file: Path | str, keep_settings: bool = True) -> bool: """