diff --git a/pyasic/data/__init__.py b/pyasic/data/__init__.py index 835c28ea..a7860630 100644 --- a/pyasic/data/__init__.py +++ b/pyasic/data/__init__.py @@ -94,9 +94,7 @@ class MinerData: percent_expected_wattage: float = field(init=False) nominal: bool = field(init=False) config: MinerConfig = None - errors: List[ - Union[WhatsminerError, BraiinsOSError, X19Error, InnosiliconError] - ] = field(default_factory=list) + errors: List[Union[WhatsminerError, BraiinsOSError, X19Error, InnosiliconError]] = field(default_factory=list) fault_light: Union[bool, None] = None efficiency: int = field(init=False) is_mining: bool = True diff --git a/pyasic/miners/blockminer/__init__.py b/pyasic/miners/blockminer/__init__.py new file mode 100644 index 00000000..4664d00a --- /dev/null +++ b/pyasic/miners/blockminer/__init__.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------------------ +# Copyright 2022 Upstream Data Inc - +# - +# Licensed under the Apache License, Version 2.0 (the "License"); - +# you may not use this file except in compliance with the License. - +# You may obtain a copy of the License at - +# - +# http://www.apache.org/licenses/LICENSE-2.0 - +# - +# Unless required by applicable law or agreed to in writing, software - +# distributed under the License is distributed on an "AS IS" BASIS, - +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - +# See the License for the specific language governing permissions and - +# limitations under the License. - +# ------------------------------------------------------------------------------ + +from .epic import * diff --git a/pyasic/miners/blockminer/epic/__init__.py b/pyasic/miners/blockminer/epic/__init__.py new file mode 100644 index 00000000..b063d429 --- /dev/null +++ b/pyasic/miners/blockminer/epic/__init__.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------------------ +# Copyright 2022 Upstream Data Inc - +# - +# Licensed under the Apache License, Version 2.0 (the "License"); - +# you may not use this file except in compliance with the License. - +# You may obtain a copy of the License at - +# - +# http://www.apache.org/licenses/LICENSE-2.0 - +# - +# Unless required by applicable law or agreed to in writing, software - +# distributed under the License is distributed on an "AS IS" BASIS, - +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - +# See the License for the specific language governing permissions and - +# limitations under the License. - +# ------------------------------------------------------------------------------ + +from .blockminer import * diff --git a/pyasic/miners/blockminer/epic/blockminer/__init__.py b/pyasic/miners/blockminer/epic/blockminer/__init__.py new file mode 100644 index 00000000..f03cdba4 --- /dev/null +++ b/pyasic/miners/blockminer/epic/blockminer/__init__.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------------------ +# Copyright 2022 Upstream Data Inc - +# - +# Licensed under the Apache License, Version 2.0 (the "License"); - +# you may not use this file except in compliance with the License. - +# You may obtain a copy of the License at - +# - +# http://www.apache.org/licenses/LICENSE-2.0 - +# - +# Unless required by applicable law or agreed to in writing, software - +# distributed under the License is distributed on an "AS IS" BASIS, - +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - +# See the License for the specific language governing permissions and - +# limitations under the License. - +# ------------------------------------------------------------------------------ + +from .blockminer import ( + ePICBlockMiner520i, +) diff --git a/pyasic/miners/blockminer/epic/blockminer/blockminer.py b/pyasic/miners/blockminer/epic/blockminer/blockminer.py new file mode 100644 index 00000000..a80b25b4 --- /dev/null +++ b/pyasic/miners/blockminer/epic/blockminer/blockminer.py @@ -0,0 +1,22 @@ +# ------------------------------------------------------------------------------ +# Copyright 2022 Upstream Data Inc - +# - +# Licensed under the Apache License, Version 2.0 (the "License"); - +# you may not use this file except in compliance with the License. - +# You may obtain a copy of the License at - +# - +# http://www.apache.org/licenses/LICENSE-2.0 - +# - +# Unless required by applicable law or agreed to in writing, software - +# distributed under the License is distributed on an "AS IS" BASIS, - +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - +# See the License for the specific language governing permissions and - +# limitations under the License. - +# ------------------------------------------------------------------------------ + +from pyasic.miners.backends import ePIC +from pyasic.miners.models import BlockMiner520i + + +class ePICBlockMiner520i(ePIC, BlockMiner520i): + pass diff --git a/pyasic/miners/factory.py b/pyasic/miners/factory.py index d9cfeac2..85c8d8ae 100644 --- a/pyasic/miners/factory.py +++ b/pyasic/miners/factory.py @@ -29,6 +29,7 @@ from pyasic import settings from pyasic.logger import logger from pyasic.miners.antminer import * from pyasic.miners.auradine import * +from pyasic.miners.blockminer import * from pyasic.miners.avalonminer import * from pyasic.miners.backends import ( Auradine, @@ -396,6 +397,7 @@ MINER_CLASSES = { "ANTMINER S19K PRO": ePICS19kPro, "ANTMINER S19 XP": ePICS19XP, "ANTMINER S21": ePICS21, + "BLOCKMINER 520I": ePICBlockMiner520i, }, MinerTypes.HIVEON: { None: Hiveon, @@ -942,12 +944,16 @@ class MinerFactory: pass async def get_miner_model_epic(self, ip: str) -> str | None: - sock_json_data = await self.send_web_command(ip, ":4028/capabilities") - try: - miner_model = sock_json_data["Model"] - return miner_model - except (TypeError, LookupError): - pass + for retry_cnt in range(settings.get("get_data_retries", 1)): + sock_json_data = await self.send_web_command(ip, ":4028/capabilities") + try: + miner_model = sock_json_data["Model"] + return miner_model + except (TypeError, LookupError): + if retry_cnt < settings.get("get_data_retries", 1) - 1: + continue + else: + pass async def get_miner_model_hiveon(self, ip: str) -> str | None: sock_json_data = await self.send_api_command(ip, "version") diff --git a/pyasic/miners/makes/__init__.py b/pyasic/miners/makes/__init__.py index de86dfd2..8cbd72c0 100644 --- a/pyasic/miners/makes/__init__.py +++ b/pyasic/miners/makes/__init__.py @@ -39,3 +39,7 @@ class GoldshellMake(BaseMiner): class AuradineMake(BaseMiner): make = "Auradine" + + +class ePICMake(BaseMiner): + make = "ePIC" diff --git a/pyasic/miners/models/__init__.py b/pyasic/miners/models/__init__.py index e9f4f41b..00036809 100644 --- a/pyasic/miners/models/__init__.py +++ b/pyasic/miners/models/__init__.py @@ -20,3 +20,4 @@ from .avalonminer import * from .goldshell import * from .innosilicon import * from .whatsminer import * +from .epic import * diff --git a/pyasic/miners/models/epic/__init__.py b/pyasic/miners/models/epic/__init__.py new file mode 100644 index 00000000..f0b88835 --- /dev/null +++ b/pyasic/miners/models/epic/__init__.py @@ -0,0 +1 @@ +from .blockminer import * diff --git a/pyasic/miners/models/epic/blockminer/__init__.py b/pyasic/miners/models/epic/blockminer/__init__.py new file mode 100644 index 00000000..f0b88835 --- /dev/null +++ b/pyasic/miners/models/epic/blockminer/__init__.py @@ -0,0 +1 @@ +from .blockminer import * diff --git a/pyasic/miners/models/epic/blockminer/blockminer.py b/pyasic/miners/models/epic/blockminer/blockminer.py new file mode 100644 index 00000000..583b8c51 --- /dev/null +++ b/pyasic/miners/models/epic/blockminer/blockminer.py @@ -0,0 +1,7 @@ +from pyasic.miners.makes import ePICMake + + +class BlockMiner520i(ePICMake): + raw_model = "BlockMiner 520i" + expected_chips = 124 + expected_fans = 4 diff --git a/pyasic/web/epic.py b/pyasic/web/epic.py index 8442a905..dd4107ca 100644 --- a/pyasic/web/epic.py +++ b/pyasic/web/epic.py @@ -44,37 +44,40 @@ class ePICWebAPI(BaseWebAPI): post = privileged or not parameters == {} async with httpx.AsyncClient(transport=settings.transport()) as client: - try: - if post: - response = await client.post( - f"http://{self.ip}:{self.port}/{command}", - timeout=5, - json={ - **parameters, - "password": self.pwd, - }, - ) - else: - response = await client.get( - f"http://{self.ip}:{self.port}/{command}", - timeout=5, - ) - if not response.status_code == 200: - if not ignore_errors: - raise APIError( - f"Web command {command} failed with status code {response.status_code}" + for retry_cnt in range(settings.get("get_data_retries", 1)): + try: + if post: + response = await client.post( + f"http://{self.ip}:{self.port}/{command}", + timeout=5, + json={ + **parameters, + "password": self.pwd, + }, ) - return {} - json_data = response.json() - if json_data: - # The API can return a fail status if the miner cannot return the requested data. Catch this and pass - if not json_data.get("result", True) and not post: + else: + response = await client.get( + f"http://{self.ip}:{self.port}/{command}", + timeout=5, + ) + if not response.status_code == 200: if not ignore_errors: - raise APIError(json_data["error"]) - return json_data - return {"success": True} - except (httpx.HTTPError, json.JSONDecodeError, AttributeError): - pass + raise APIError( + f"Web command {command} failed with status code {response.status_code}" + ) + return {} + json_data = response.json() + if json_data: + # The API can return a fail status if the miner cannot return the requested data. Catch this and pass + if not json_data.get("result", True) and not post: + if retry_cnt < settings.get("get_data_retries", 1) - 1: + continue + if not ignore_errors: + raise APIError(json_data["error"]) + return json_data + return {"success": True} + except (httpx.HTTPError, json.JSONDecodeError, AttributeError): + pass async def multicommand( self, *commands: str, ignore_errors: bool = False, allow_warning: bool = True