Compare commits

..

39 Commits

Author SHA1 Message Date
UpstreamData
c7d6f6cd9f version: bump version number. 2023-04-27 10:02:14 -06:00
UpstreamData
bf19232ad9 bug: add chip counts for M30S++ VH100 2023-04-27 10:01:43 -06:00
UpstreamData
b495f22f31 version: bump version number. 2023-04-20 13:35:19 -06:00
UpstreamData
78213c682b feature: add % ideal hashrate and wattage. 2023-04-20 13:34:40 -06:00
Upstream Data
3706c8fb75 version: bump version nuber. 2023-04-16 20:40:49 -06:00
Upstream Data
ed9d386dc2 bug: fix bosminer configs not loading in fan control properly. 2023-04-16 20:39:39 -06:00
UpstreamData
1183b5deb2 version: bump version number. 2023-04-14 13:07:58 -06:00
UpstreamData
c4676438a8 bug: fix a bug with failing to get hashboards and hashrate breaking data. 2023-04-14 13:07:35 -06:00
UpstreamData
5ea9126c77 version: bump version number. 2023-04-13 14:26:34 -06:00
UpstreamData
853756ebcb feature: sum hashrate in MinerData from hashboards, with the hashrate item being a backup. 2023-04-13 14:26:03 -06:00
UpstreamData
05e82b85c5 bug: fix T9+ support. 2023-04-13 14:09:05 -06:00
UpstreamData
9c4c8503d6 feature: add support for antminer D3. 2023-04-13 13:43:41 -06:00
UpstreamData
e25cc1d85e bug: catch errors when sending commands to vnish with a bad token. 2023-04-13 13:34:55 -06:00
UpstreamData
8e37d72337 feature: add support for L3+ and Vnish L3+. 2023-04-13 13:33:02 -06:00
Upstream Data
f84a054ecc version: bump version number. 2023-04-12 22:16:57 -06:00
Upstream Data
6b54607588 feature: add chip count for M30S++VH20. 2023-04-12 22:16:38 -06:00
Upstream Data
85ee8a479b version: bump version number. 2023-04-12 19:53:56 -06:00
Upstream Data
9decbf2a4b bug: fix incorrect board count for M33S++. 2023-04-12 19:53:26 -06:00
UpstreamData
15ce3a3140 tests: Improve binding to 0.0.0.0 in tests. 2023-04-04 09:25:33 -06:00
UpstreamData
d4d48f5582 docs: update docs. 2023-04-04 09:22:36 -06:00
UpstreamData
a577f64d59 bug: add additional whatsminer error codes. 2023-03-31 10:44:51 -06:00
UpstreamData
aaf48cc686 version: bump version number. 2023-03-28 11:40:54 -06:00
UpstreamData
aa6dc74471 minor: reformat a bunch of files to try to make backends more cohesive, add static dict for get_data instead of using inspect, refactored graphql into a bosminer web API, and added supports_autotuning and supports_shutdown attributes to miners. 2023-03-28 11:39:03 -06:00
UpstreamData
63c8fe6868 version: bump version number. 2023-03-27 08:43:03 -06:00
UpstreamData
ee1502c6a0 bug: fix BOSMiner default password. 2023-03-27 08:42:41 -06:00
UpstreamData
2960295385 version: bump version number. 2023-03-23 13:25:11 -06:00
UpstreamData
a9e09f7b1a bug: Check stderr on ssh. 2023-03-23 13:24:38 -06:00
UpstreamData
fd17a20a1b version: bump version number. 2023-03-23 08:15:58 -06:00
UpstreamData
1e03ec5fa3 bug: fix new issue with X19 "NoPic" on braiins. 2023-03-23 08:15:21 -06:00
UpstreamData
a67e4ada8e version: bump version number. 2023-03-14 09:53:26 -06:00
UpstreamData
2d08b10076 feature: add support for S19L. 2023-03-14 09:53:05 -06:00
UpstreamData
92e972aa57 docs: update documentation. 2023-03-14 09:07:26 -06:00
Upstream Data
05cfe8cc5d version: bump version number. 2023-03-05 16:26:36 -07:00
Upstream Data
b4d9e60bff bug: fix E9Pro strop_mining and resume_mining 2023-03-05 16:26:13 -07:00
Upstream Data
6bcf372be6 version: bump version number. 2023-03-04 17:55:46 -07:00
Upstream Data
092a586329 bug: fix an issue with innosilicon A10X not allowing pool config. 2023-03-04 17:46:11 -07:00
Upstream Data
e598d4b63c version: bump version number. 2023-03-04 16:14:02 -07:00
Upstream Data
848acedd52 feature: add support for E9Pro and fix some bugs and update finding chip data for Goldshell models. 2023-03-04 16:13:03 -07:00
DCreason
e3c4464556 fix internal error when not using vnish preset (#33) 2023-03-04 07:54:27 -07:00
291 changed files with 3038 additions and 5099 deletions

View File

@@ -10,6 +10,7 @@ All API implementations inherit from [`BaseMinerAPI`][pyasic.API.BaseMinerAPI],
[`BaseMinerAPI`][pyasic.API.BaseMinerAPI] cannot be instantiated directly, it will raise a `TypeError`.
Use these instead -
#### [BFGMiner API][pyasic.API.bfgminer.BFGMinerAPI]
#### [BMMiner API][pyasic.API.bmminer.BMMinerAPI]
#### [BOSMiner API][pyasic.API.bosminer.BOSMinerAPI]
#### [BTMiner API][pyasic.API.btminer.BTMinerAPI]

7
docs/API/bfgminer.md Normal file
View File

@@ -0,0 +1,7 @@
# pyasic
## BFGMinerAPI
::: pyasic.API.bfgminer.BFGMinerAPI
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -42,21 +42,27 @@ if __name__ == "__main__":
<br>
## Creating miners based on IP
If you already know the IP address of your miner or miners, you can use the [`MinerFactory`][pyasic.miners.miner_factory.MinerFactory] to communicate and identify the miners.
The function [`MinerFactory().get_miner()`][pyasic.miners.miner_factory.MinerFactory.get_miner] will return any miner it found at the IP address specified, or an `UnknownMiner` if it cannot identify the miner.
If you already know the IP address of your miner or miners, you can use the [`MinerFactory`][pyasic.miners.miner_factory.MinerFactory] to communicate and identify the miners, or an abstraction of its functionality, [`get_miner()`][pyasic.miners.miner_factory.MinerFactory.get_miner].
The function [`get_miner()`][pyasic.miners.miner_factory.MinerFactory.get_miner] will return any miner it found at the IP address specified, or an `UnknownMiner` if it cannot identify the miner.
```python
import asyncio # asyncio for handling the async part
from pyasic.miners.miner_factory import MinerFactory # miner factory handles miners creation
from pyasic import get_miner # handles miner creation
async def get_miners(): # define async scan function to allow awaiting
# get the miner with miner factory
# miner factory is a singleton, and will always use the same object and cache
# this means you can always call it as MinerFactory().get_miner()
miner_1 = await MinerFactory().get_miner("192.168.1.75")
miner_2 = await MinerFactory().get_miner("192.168.1.76")
# get the miner with the miner factory
# the miner factory is a singleton, and will always use the same object and cache
# this means you can always call it as MinerFactory().get_miner(), or just get_miner()
miner_1 = await get_miner("192.168.1.75")
miner_2 = await get_miner("192.168.1.76")
print(miner_1, miner_2)
# can also gather these, since they are async
tasks = [get_miner("192.168.1.75"), get_miner("192.168.1.76")]
miners = await asyncio.gather(*tasks)
print(miners)
if __name__ == "__main__":
asyncio.run(get_miners()) # get the miners asynchronously with asyncio.run()
```
@@ -66,7 +72,7 @@ if __name__ == "__main__":
## Getting data from miners
Once you have your miner(s) identified, you will likely want to get data from the miner(s). You can do this using a built in function in each miner called `get_data()`.
This function will return a instance of the dataclass [`MinerData`][pyasic.data.MinerData] with all data it can gather from the miner.
This function will return an instance of the dataclass [`MinerData`][pyasic.data.MinerData] with all data it can gather from the miner.
Each piece of data in a [`MinerData`][pyasic.data.MinerData] instance can be referenced by getting it as an attribute, such as [`MinerData().hashrate`][pyasic.data.MinerData].
```python
import asyncio

View File

@@ -0,0 +1,11 @@
# pyasic
## X15 Models
## Z15
::: pyasic.miners.zec.antminer.cgminer.X15.Z15.CGMinerZ15
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -3,7 +3,7 @@
## S17
::: pyasic.miners.antminer.bmminer.X17.S17.BMMinerS17
::: pyasic.miners.btc.antminer.bmminer.X17.S17.BMMinerS17
handler: python
options:
show_root_heading: false
@@ -11,7 +11,7 @@
## S17+
::: pyasic.miners.antminer.bmminer.X17.S17_Plus.BMMinerS17Plus
::: pyasic.miners.btc.antminer.bmminer.X17.S17_Plus.BMMinerS17Plus
handler: python
options:
show_root_heading: false
@@ -19,7 +19,7 @@
## S17 Pro
::: pyasic.miners.antminer.bmminer.X17.S17_Pro.BMMinerS17Pro
::: pyasic.miners.btc.antminer.bmminer.X17.S17_Pro.BMMinerS17Pro
handler: python
options:
show_root_heading: false
@@ -27,7 +27,7 @@
## S17e
::: pyasic.miners.antminer.bmminer.X17.S17e.BMMinerS17e
::: pyasic.miners.btc.antminer.bmminer.X17.S17e.BMMinerS17e
handler: python
options:
show_root_heading: false
@@ -35,7 +35,7 @@
## T17
::: pyasic.miners.antminer.bmminer.X17.T17.BMMinerT17
::: pyasic.miners.btc.antminer.bmminer.X17.T17.BMMinerT17
handler: python
options:
show_root_heading: false
@@ -43,7 +43,7 @@
## T17+
::: pyasic.miners.antminer.bmminer.X17.T17_Plus.BMMinerT17Plus
::: pyasic.miners.btc.antminer.bmminer.X17.T17_Plus.BMMinerT17Plus
handler: python
options:
show_root_heading: false
@@ -52,7 +52,7 @@
## T17e
::: pyasic.miners.antminer.bmminer.X17.T17e.BMMinerT17e
::: pyasic.miners.btc.antminer.bmminer.X17.T17e.BMMinerT17e
handler: python
options:
show_root_heading: false
@@ -61,7 +61,7 @@
## S17 (BOS)
::: pyasic.miners.antminer.bosminer.X17.S17.BOSMinerS17
::: pyasic.miners.btc.antminer.bosminer.X17.S17.BOSMinerS17
handler: python
options:
show_root_heading: false
@@ -69,7 +69,7 @@
## S17+ (BOS)
::: pyasic.miners.antminer.bosminer.X17.S17_Plus.BOSMinerS17Plus
::: pyasic.miners.btc.antminer.bosminer.X17.S17_Plus.BOSMinerS17Plus
handler: python
options:
show_root_heading: false
@@ -77,7 +77,7 @@
## S17 Pro (BOS)
::: pyasic.miners.antminer.bosminer.X17.S17_Pro.BOSMinerS17Pro
::: pyasic.miners.btc.antminer.bosminer.X17.S17_Pro.BOSMinerS17Pro
handler: python
options:
show_root_heading: false
@@ -85,7 +85,7 @@
## S17e (BOS)
::: pyasic.miners.antminer.bosminer.X17.S17e.BOSMinerS17e
::: pyasic.miners.btc.antminer.bosminer.X17.S17e.BOSMinerS17e
handler: python
options:
show_root_heading: false
@@ -93,7 +93,7 @@
## T17 (BOS)
::: pyasic.miners.antminer.bosminer.X17.T17.BOSMinerT17
::: pyasic.miners.btc.antminer.bosminer.X17.T17.BOSMinerT17
handler: python
options:
show_root_heading: false
@@ -101,7 +101,7 @@
## T17+ (BOS)
::: pyasic.miners.antminer.bosminer.X17.T17_Plus.BOSMinerT17Plus
::: pyasic.miners.btc.antminer.bosminer.X17.T17_Plus.BOSMinerT17Plus
handler: python
options:
show_root_heading: false
@@ -110,7 +110,7 @@
## T17e (BOS)
::: pyasic.miners.antminer.bosminer.X17.T17e.BOSMinerT17e
::: pyasic.miners.btc.antminer.bosminer.X17.T17e.BOSMinerT17e
handler: python
options:
show_root_heading: false

View File

@@ -3,7 +3,15 @@
## S19
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19
::: pyasic.miners.btc.antminer.bmminer.X19.S19.BMMinerS19
handler: python
options:
show_root_heading: false
heading_level: 4
## S19L
::: pyasic.miners.btc.antminer.bmminer.X19.S19L.BMMinerS19L
handler: python
options:
show_root_heading: false
@@ -11,7 +19,7 @@
## S19 Pro
::: pyasic.miners.antminer.bmminer.X19.S19_Pro.BMMinerS19Pro
::: pyasic.miners.btc.antminer.bmminer.X19.S19_Pro.BMMinerS19Pro
handler: python
options:
show_root_heading: false
@@ -20,7 +28,7 @@
## S19a
::: pyasic.miners.antminer.bmminer.X19.S19a.BMMinerS19a
::: pyasic.miners.btc.antminer.bmminer.X19.S19a.BMMinerS19a
handler: python
options:
show_root_heading: false
@@ -29,7 +37,7 @@
## S19j
::: pyasic.miners.antminer.bmminer.X19.S19j.BMMinerS19j
::: pyasic.miners.btc.antminer.bmminer.X19.S19j.BMMinerS19j
handler: python
options:
show_root_heading: false
@@ -37,7 +45,7 @@
## S19j Pro
::: pyasic.miners.antminer.bmminer.X19.S19j_Pro.BMMinerS19jPro
::: pyasic.miners.btc.antminer.bmminer.X19.S19j_Pro.BMMinerS19jPro
handler: python
options:
show_root_heading: false
@@ -45,7 +53,7 @@
## S19 XP
::: pyasic.miners.antminer.bmminer.X19.S19_XP.BMMinerS19XP
::: pyasic.miners.btc.antminer.bmminer.X19.S19_XP.BMMinerS19XP
handler: python
options:
show_root_heading: false
@@ -53,7 +61,7 @@
## T19
::: pyasic.miners.antminer.bmminer.X19.T19.BMMinerT19
::: pyasic.miners.btc.antminer.bmminer.X19.T19.BMMinerT19
handler: python
options:
show_root_heading: false
@@ -62,7 +70,7 @@
## S19 (BOS)
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19
::: pyasic.miners.btc.antminer.bosminer.X19.S19.BOSMinerS19
handler: python
options:
show_root_heading: false
@@ -70,7 +78,7 @@
## S19 Pro (BOS)
::: pyasic.miners.antminer.bosminer.X19.S19_Pro.BOSMinerS19Pro
::: pyasic.miners.btc.antminer.bosminer.X19.S19_Pro.BOSMinerS19Pro
handler: python
options:
show_root_heading: false
@@ -79,7 +87,7 @@
## S19j (BOS)
::: pyasic.miners.antminer.bosminer.X19.S19j.BOSMinerS19j
::: pyasic.miners.btc.antminer.bosminer.X19.S19j.BOSMinerS19j
handler: python
options:
show_root_heading: false
@@ -87,7 +95,7 @@
## S19j Pro (BOS)
::: pyasic.miners.antminer.bosminer.X19.S19j_Pro.BOSMinerS19jPro
::: pyasic.miners.btc.antminer.bosminer.X19.S19j_Pro.BOSMinerS19jPro
handler: python
options:
show_root_heading: false
@@ -95,7 +103,7 @@
## T19 (BOS)
::: pyasic.miners.antminer.bosminer.X19.T19.BOSMinerT19
::: pyasic.miners.btc.antminer.bosminer.X19.T19.BOSMinerT19
handler: python
options:
show_root_heading: false

View File

@@ -0,0 +1,11 @@
# pyasic
## X3 Models
## HS3
::: pyasic.miners.hns.antminer.cgminer.X3.HS3.CGMinerHS3
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -0,0 +1,11 @@
# pyasic
## X5 Models
## DR5
::: pyasic.miners.dcr.antminer.cgminer.X5.DR5.CGMinerDR5
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -0,0 +1,11 @@
# pyasic
## X7 Models
## L7
::: pyasic.miners.ltc.antminer.bmminer.X7.L7.BMMinerL7
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -4,7 +4,7 @@
## X9 (BOS)
::: pyasic.miners.antminer.bosminer.X9.S9.BOSMinerS9
::: pyasic.miners.btc.antminer.bosminer.X9.S9.BOSMinerS9
handler: python
options:
show_root_heading: false
@@ -13,7 +13,7 @@
## S9
::: pyasic.miners.antminer.bmminer.X9.S9.BMMinerS9
::: pyasic.miners.btc.antminer.bmminer.X9.S9.BMMinerS9
handler: python
options:
show_root_heading: false
@@ -21,7 +21,7 @@
## S9i
::: pyasic.miners.antminer.bmminer.X9.S9i.BMMinerS9i
::: pyasic.miners.btc.antminer.bmminer.X9.S9i.BMMinerS9i
handler: python
options:
show_root_heading: false
@@ -29,7 +29,15 @@
## T9
::: pyasic.miners.antminer.bmminer.X9.T9.BMMinerT9
::: pyasic.miners.btc.antminer.bmminer.X9.T9.BMMinerT9
handler: python
options:
show_root_heading: false
heading_level: 4
## E9 Pro
::: pyasic.miners.etc.antminer.cgminer.X9.E9_Pro.CGMinerE9Pro
handler: python
options:
show_root_heading: false

View File

@@ -3,7 +3,7 @@
## A1026
::: pyasic.miners.avalonminer.cgminer.A10X.A1026.CGMinerAvalon1026
::: pyasic.miners.btc.avalonminer.cgminer.A10X.A1026.CGMinerAvalon1026
handler: python
options:
show_root_heading: false
@@ -11,7 +11,7 @@
## A1047
::: pyasic.miners.avalonminer.cgminer.A10X.A1047.CGMinerAvalon1047
::: pyasic.miners.btc.avalonminer.cgminer.A10X.A1047.CGMinerAvalon1047
handler: python
options:
show_root_heading: false
@@ -19,7 +19,7 @@
## A1066
::: pyasic.miners.avalonminer.cgminer.A10X.A1066.CGMinerAvalon1066
::: pyasic.miners.btc.avalonminer.cgminer.A10X.A1066.CGMinerAvalon1066
handler: python
options:
show_root_heading: false

View File

@@ -3,7 +3,7 @@
## A721
::: pyasic.miners.avalonminer.cgminer.A7X.A721.CGMinerAvalon721
::: pyasic.miners.btc.avalonminer.cgminer.A7X.A721.CGMinerAvalon721
handler: python
options:
show_root_heading: false
@@ -11,7 +11,7 @@
## A741
::: pyasic.miners.avalonminer.cgminer.A7X.A741.CGMinerAvalon741
::: pyasic.miners.btc.avalonminer.cgminer.A7X.A741.CGMinerAvalon741
handler: python
options:
show_root_heading: false
@@ -19,7 +19,7 @@
## A761
::: pyasic.miners.avalonminer.cgminer.A7X.A761.CGMinerAvalon761
::: pyasic.miners.btc.avalonminer.cgminer.A7X.A761.CGMinerAvalon761
handler: python
options:
show_root_heading: false

View File

@@ -3,7 +3,7 @@
## A821
::: pyasic.miners.avalonminer.cgminer.A8X.A821.CGMinerAvalon821
::: pyasic.miners.btc.avalonminer.cgminer.A8X.A821.CGMinerAvalon821
handler: python
options:
show_root_heading: false
@@ -11,7 +11,7 @@
## A841
::: pyasic.miners.avalonminer.cgminer.A8X.A841.CGMinerAvalon841
::: pyasic.miners.btc.avalonminer.cgminer.A8X.A841.CGMinerAvalon841
handler: python
options:
show_root_heading: false
@@ -19,7 +19,7 @@
## A851
::: pyasic.miners.avalonminer.cgminer.A8X.A851.CGMinerAvalon851
::: pyasic.miners.btc.avalonminer.cgminer.A8X.A851.CGMinerAvalon851
handler: python
options:
show_root_heading: false

View File

@@ -3,7 +3,7 @@
## A921
::: pyasic.miners.avalonminer.cgminer.A9X.A921.CGMinerAvalon921
::: pyasic.miners.btc.avalonminer.cgminer.A9X.A921.CGMinerAvalon921
handler: python
options:
show_root_heading: false

View File

@@ -0,0 +1,8 @@
# pyasic
## BFGMiner Backend
::: pyasic.miners.backends.bfgminer.BFGMiner
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -1,7 +1,7 @@
# pyasic
## BMMiner Backend
::: pyasic.miners._backends.bmminer.BMMiner
::: pyasic.miners.backends.bmminer.BMMiner
handler: python
options:
show_root_heading: false

View File

@@ -1,7 +1,7 @@
# pyasic
## BOSMiner Backend
::: pyasic.miners._backends.bosminer.BOSMiner
::: pyasic.miners.backends.bosminer.BOSMiner
handler: python
options:
show_root_heading: false

View File

@@ -1,7 +1,7 @@
# pyasic
## BTMiner Backend
::: pyasic.miners._backends.btminer.BTMiner
::: pyasic.miners.backends.btminer.BTMiner
handler: python
options:
show_root_heading: false

View File

@@ -1,7 +1,7 @@
# pyasic
## CGMiner Backend
::: pyasic.miners._backends.cgminer.CGMiner
::: pyasic.miners.backends.cgminer.CGMiner
handler: python
options:
show_root_heading: false

View File

@@ -1,7 +1,7 @@
# pyasic
## Hiveon Backend
::: pyasic.miners._backends.hiveon.Hiveon
::: pyasic.miners.backends.hiveon.Hiveon
handler: python
options:
show_root_heading: false

View File

@@ -0,0 +1,10 @@
# pyasic
## CKX Models
## CK5
::: pyasic.miners.ckb.goldshell.bfgminer.CKX.CK5.BFGMinerCK5
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -0,0 +1,10 @@
# pyasic
## HSX Models
## HS5
::: pyasic.miners.hns.goldshell.bfgminer.HSX.HS5.BFGMinerHS5
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -0,0 +1,19 @@
# pyasic
## KDX Models
## KD5
::: pyasic.miners.kda.goldshell.bfgminer.KDX.KD5.BFGMinerKD5
handler: python
options:
show_root_heading: false
heading_level: 4
## KD Max
::: pyasic.miners.kda.goldshell.bfgminer.KDX.KDMax.BFGMinerKDMax
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -0,0 +1,10 @@
# pyasic
## A10X Models
## A10X
::: pyasic.miners.etc.innosilicon.cgminer.A10X.A10X.CGMinerA10X
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -3,7 +3,7 @@
## T3H+
::: pyasic.miners.innosilicon.cgminer.T3X.T3H_Plus.CGMinerInnosiliconT3HPlus
::: pyasic.miners.btc.innosilicon.cgminer.T3X.T3H_Plus.CGMinerInnosiliconT3HPlus
handler: python
options:
show_root_heading: false

View File

@@ -432,6 +432,7 @@ details {
<summary>X19 Series:</summary>
<ul>
<li><a href="../antminer/X19/#s19">S19</a></li>
<li><a href="../antminer/X19/#s19l">S19L</a></li>
<li><a href="../antminer/X19/#s19-pro">S19 Pro</a></li>
<li><a href="../antminer/X19/#s19a">S19a</a></li>
<li><a href="../antminer/X19/#s19j">S19j</a></li>
@@ -453,11 +454,36 @@ details {
</ul>
</details>
<details>
<summary>X15 Series:</summary>
<ul>
<li><a href="../antminer/X15/#z15">Z15</a></li>
</ul>
</details>
<details>
<summary>X9 Series:</summary>
<ul>
<li><a href="../antminer/X9/#s9">S9</a></li>
<li><a href="../antminer/X9/#s9i">S9i</a></li>
<li><a href="../antminer/X9/#t9">T9</a></li>
<li><a href="../antminer/X9/#e9-pro">E9 Pro</a></li>
</ul>
</details>
<details>
<summary>X7 Series:</summary>
<ul>
<li><a href="../antminer/X7/#l7">L7</a></li>
</ul>
</details>
<details>
<summary>X5 Series:</summary>
<ul>
<li><a href="../antminer/X5/#dr5">DR5</a></li>
</ul>
</details>
<details>
<summary>X3 Series:</summary>
<ul>
<li><a href="../antminer/X3/#hs3">HS3</a></li>
</ul>
</details>
</ul>
@@ -506,5 +532,35 @@ details {
<li><a href="../innosilicon/T3X/#t3h">T3H+</a></li>
</ul>
</details>
<details>
<summary>A10X Series:</summary>
<ul>
<li><a href="../innosilicon/A10X/#a10x">A10X</a></li>
</ul>
</details>
</ul>
</details>
<details>
<summary>Stock Firmware BFGMinerGoldshell Miners:</summary>
<ul>
<details>
<summary>CKX Series:</summary>
<ul>
<li><a href="../goldshell/CKX/#ck5">CK5</a></li>
</ul>
</details>
<details>
<summary>HSX Series:</summary>
<ul>
<li><a href="../goldshell/HSX/#hs5">HS5</a></li>
</ul>
</details>
<details>
<summary>KDX Series:</summary>
<ul>
<li><a href="../goldshell/KDX/#kd5">KD5</a></li>
<li><a href="../goldshell/KDX/#kd-max">KD Max</a></li>
</ul>
</details>
</ul>
</details>

View File

@@ -3,7 +3,7 @@
## M20V10
::: pyasic.miners.whatsminer.btminer.M2X.M20.BTMinerM20V10
::: pyasic.miners.btc.whatsminer.btminer.M2X.M20.BTMinerM20V10
handler: python
options:
show_root_heading: false
@@ -11,7 +11,7 @@
## M20SV10
::: pyasic.miners.whatsminer.btminer.M2X.M20S.BTMinerM20SV10
::: pyasic.miners.btc.whatsminer.btminer.M2X.M20S.BTMinerM20SV10
handler: python
options:
show_root_heading: false
@@ -19,7 +19,7 @@
## M20SV20
::: pyasic.miners.whatsminer.btminer.M2X.M20S.BTMinerM20SV20
::: pyasic.miners.btc.whatsminer.btminer.M2X.M20S.BTMinerM20SV20
handler: python
options:
show_root_heading: false
@@ -27,7 +27,7 @@
## M20SV30
::: pyasic.miners.whatsminer.btminer.M2X.M20S.BTMinerM20SV30
::: pyasic.miners.btc.whatsminer.btminer.M2X.M20S.BTMinerM20SV30
handler: python
options:
show_root_heading: false
@@ -35,7 +35,7 @@
## M20S+V30
::: pyasic.miners.whatsminer.btminer.M2X.M20S_Plus.BTMinerM20SPlusV30
::: pyasic.miners.btc.whatsminer.btminer.M2X.M20S_Plus.BTMinerM20SPlusV30
handler: python
options:
show_root_heading: false
@@ -43,7 +43,7 @@
## M21V10
::: pyasic.miners.whatsminer.btminer.M2X.M21.BTMinerM21V10
::: pyasic.miners.btc.whatsminer.btminer.M2X.M21.BTMinerM21V10
handler: python
options:
show_root_heading: false
@@ -51,7 +51,7 @@
## M21SV20
::: pyasic.miners.whatsminer.btminer.M2X.M21S.BTMinerM21SV20
::: pyasic.miners.btc.whatsminer.btminer.M2X.M21S.BTMinerM21SV20
handler: python
options:
show_root_heading: false
@@ -59,7 +59,7 @@
## M21SV60
::: pyasic.miners.whatsminer.btminer.M2X.M21S.BTMinerM21SV60
::: pyasic.miners.btc.whatsminer.btminer.M2X.M21S.BTMinerM21SV60
handler: python
options:
show_root_heading: false
@@ -67,7 +67,7 @@
## M21SV70
::: pyasic.miners.whatsminer.btminer.M2X.M21S.BTMinerM21SV70
::: pyasic.miners.btc.whatsminer.btminer.M2X.M21S.BTMinerM21SV70
handler: python
options:
show_root_heading: false
@@ -75,7 +75,7 @@
## M21S+V20
::: pyasic.miners.whatsminer.btminer.M2X.M21S_Plus.BTMinerM21SPlusV20
::: pyasic.miners.btc.whatsminer.btminer.M2X.M21S_Plus.BTMinerM21SPlusV20
handler: python
options:
show_root_heading: false
@@ -83,7 +83,7 @@
## M29V10
::: pyasic.miners.whatsminer.btminer.M2X.M29.BTMinerM29V10
::: pyasic.miners.btc.whatsminer.btminer.M2X.M29.BTMinerM29V10
handler: python
options:
show_root_heading: false

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,7 @@
## M50VG30
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VG30
::: pyasic.miners.btc.whatsminer.btminer.M5X.M50.BTMinerM50VG30
handler: python
options:
show_root_heading: false
@@ -11,7 +11,7 @@
## M50VH10
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH10
::: pyasic.miners.btc.whatsminer.btminer.M5X.M50.BTMinerM50VH10
handler: python
options:
show_root_heading: false
@@ -19,7 +19,7 @@
## M50VH20
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH20
::: pyasic.miners.btc.whatsminer.btminer.M5X.M50.BTMinerM50VH20
handler: python
options:
show_root_heading: false
@@ -27,7 +27,7 @@
## M50VH30
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH30
::: pyasic.miners.btc.whatsminer.btminer.M5X.M50.BTMinerM50VH30
handler: python
options:
show_root_heading: false
@@ -35,7 +35,7 @@
## M50VH40
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH40
::: pyasic.miners.btc.whatsminer.btminer.M5X.M50.BTMinerM50VH40
handler: python
options:
show_root_heading: false
@@ -43,7 +43,7 @@
## M50VH50
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH50
::: pyasic.miners.btc.whatsminer.btminer.M5X.M50.BTMinerM50VH50
handler: python
options:
show_root_heading: false
@@ -51,7 +51,7 @@
## M50VH60
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH60
::: pyasic.miners.btc.whatsminer.btminer.M5X.M50.BTMinerM50VH60
handler: python
options:
show_root_heading: false
@@ -59,7 +59,7 @@
## M50VH70
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH70
::: pyasic.miners.btc.whatsminer.btminer.M5X.M50.BTMinerM50VH70
handler: python
options:
show_root_heading: false
@@ -67,7 +67,7 @@
## M50VH80
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH80
::: pyasic.miners.btc.whatsminer.btminer.M5X.M50.BTMinerM50VH80
handler: python
options:
show_root_heading: false
@@ -75,7 +75,7 @@
## M50VJ10
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VJ10
::: pyasic.miners.btc.whatsminer.btminer.M5X.M50.BTMinerM50VJ10
handler: python
options:
show_root_heading: false
@@ -83,7 +83,7 @@
## M50VJ20
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VJ20
::: pyasic.miners.btc.whatsminer.btminer.M5X.M50.BTMinerM50VJ20
handler: python
options:
show_root_heading: false
@@ -91,7 +91,7 @@
## M50VJ30
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VJ30
::: pyasic.miners.btc.whatsminer.btminer.M5X.M50.BTMinerM50VJ30
handler: python
options:
show_root_heading: false
@@ -99,7 +99,7 @@
## M50SVJ10
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVJ10
::: pyasic.miners.btc.whatsminer.btminer.M5X.M50S.BTMinerM50SVJ10
handler: python
options:
show_root_heading: false
@@ -107,7 +107,7 @@
## M50SVJ20
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVJ20
::: pyasic.miners.btc.whatsminer.btminer.M5X.M50S.BTMinerM50SVJ20
handler: python
options:
show_root_heading: false
@@ -115,7 +115,7 @@
## M50SVJ30
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVJ30
::: pyasic.miners.btc.whatsminer.btminer.M5X.M50S.BTMinerM50SVJ30
handler: python
options:
show_root_heading: false
@@ -123,7 +123,7 @@
## M50SVH10
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH10
::: pyasic.miners.btc.whatsminer.btminer.M5X.M50S.BTMinerM50SVH10
handler: python
options:
show_root_heading: false
@@ -131,7 +131,7 @@
## M50SVH20
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH20
::: pyasic.miners.btc.whatsminer.btminer.M5X.M50S.BTMinerM50SVH20
handler: python
options:
show_root_heading: false
@@ -139,7 +139,7 @@
## M50SVH30
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH30
::: pyasic.miners.btc.whatsminer.btminer.M5X.M50S.BTMinerM50SVH30
handler: python
options:
show_root_heading: false
@@ -147,7 +147,7 @@
## M50SVH40
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH40
::: pyasic.miners.btc.whatsminer.btminer.M5X.M50S.BTMinerM50SVH40
handler: python
options:
show_root_heading: false
@@ -155,7 +155,7 @@
## M50SVH50
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH50
::: pyasic.miners.btc.whatsminer.btminer.M5X.M50S.BTMinerM50SVH50
handler: python
options:
show_root_heading: false
@@ -163,7 +163,7 @@
## M50S+VH30
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVH30
::: pyasic.miners.btc.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVH30
handler: python
options:
show_root_heading: false
@@ -171,7 +171,7 @@
## M50S+VH40
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVH40
::: pyasic.miners.btc.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVH40
handler: python
options:
show_root_heading: false
@@ -179,7 +179,7 @@
## M50S+VJ30
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVJ30
::: pyasic.miners.btc.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVJ30
handler: python
options:
show_root_heading: false
@@ -187,7 +187,7 @@
## M53VH30
::: pyasic.miners.whatsminer.btminer.M5X.M53.BTMinerM53VH30
::: pyasic.miners.btc.whatsminer.btminer.M5X.M53.BTMinerM53VH30
handler: python
options:
show_root_heading: false
@@ -195,7 +195,7 @@
## M53SVH30
::: pyasic.miners.whatsminer.btminer.M5X.M53S.BTMinerM53SVH30
::: pyasic.miners.btc.whatsminer.btminer.M5X.M53S.BTMinerM53SVH30
handler: python
options:
show_root_heading: false
@@ -203,7 +203,7 @@
## M53S+VJ30
::: pyasic.miners.whatsminer.btminer.M5X.M53S_Plus.BTMinerM53SPlusVJ30
::: pyasic.miners.btc.whatsminer.btminer.M5X.M53S_Plus.BTMinerM53SPlusVJ30
handler: python
options:
show_root_heading: false
@@ -211,7 +211,7 @@
## M56VH30
::: pyasic.miners.whatsminer.btminer.M5X.M56.BTMinerM56VH30
::: pyasic.miners.btc.whatsminer.btminer.M5X.M56.BTMinerM56VH30
handler: python
options:
show_root_heading: false
@@ -219,7 +219,7 @@
## M56SVH30
::: pyasic.miners.whatsminer.btminer.M5X.M56S.BTMinerM56SVH30
::: pyasic.miners.btc.whatsminer.btminer.M5X.M56S.BTMinerM56SVH30
handler: python
options:
show_root_heading: false
@@ -227,7 +227,7 @@
## M56S+VJ30
::: pyasic.miners.whatsminer.btminer.M5X.M56S_Plus.BTMinerM56SPlusVJ30
::: pyasic.miners.btc.whatsminer.btminer.M5X.M56S_Plus.BTMinerM56SPlusVJ30
handler: python
options:
show_root_heading: false
@@ -235,7 +235,7 @@
## M59VH30
::: pyasic.miners.whatsminer.btminer.M5X.M59.BTMinerM59VH30
::: pyasic.miners.btc.whatsminer.btminer.M5X.M59.BTMinerM59VH30
handler: python
options:
show_root_heading: false

View File

@@ -1,45 +1,54 @@
site_name: pyasic
repo_url: https://github.com/UpstreamData/pyasic
nav:
- Introduction: "index.md"
- Miners:
- Supported Miners: "miners/supported_types.md"
- Miner Factory: "miners/miner_factory.md"
- Backends:
- BMMiner: "miners/backends/bmminer.md"
- BOSMiner: "miners/backends/bosminer.md"
- BTMiner: "miners/backends/btminer.md"
- CGMiner: "miners/backends/cgminer.md"
- Hiveon: "miners/backends/hiveon.md"
- Classes:
- Antminer X9: "miners/antminer/X9.md"
- Antminer X17: "miners/antminer/X17.md"
- Antminer X19: "miners/antminer/X19.md"
- Avalon 7X: "miners/avalonminer/A7X.md"
- Avalon 8X: "miners/avalonminer/A8X.md"
- Avalon 9X: "miners/avalonminer/A9X.md"
- Avalon 10X: "miners/avalonminer/A10X.md"
- Whatsminer M2X: "miners/whatsminer/M2X.md"
- Whatsminer M3X: "miners/whatsminer/M3X.md"
- Whatsminer M5X: "miners/whatsminer/M5X.md"
- Innosilicon T3X: "miners/innosilicon/T3X.md"
- Network:
- Miner Network: "network/miner_network.md"
- Miner Network Range: "network/miner_network_range.md"
- Dataclasses:
- Miner Data: "data/miner_data.md"
- Error Codes: "data/error_codes.md"
- Miner Config: "config/miner_config.md"
- Advanced:
- Miner APIs:
- Intro: "API/api.md"
- BMMiner: "API/bmminer.md"
- BOSMiner: "API/bosminer.md"
- BTMiner: "API/btminer.md"
- CGMiner: "API/cgminer.md"
- Unknown: "API/unknown.md"
- Base Miner: "miners/base_miner.md"
- Introduction: "index.md"
- Miners:
- Supported Miners: "miners/supported_types.md"
- Miner Factory: "miners/miner_factory.md"
- Network:
- Miner Network: "network/miner_network.md"
- Miner Network Range: "network/miner_network_range.md"
- Dataclasses:
- Miner Data: "data/miner_data.md"
- Error Codes: "data/error_codes.md"
- Miner Config: "config/miner_config.md"
- Advanced:
- Miner APIs:
- Intro: "API/api.md"
- BFGMiner: "API/bfgminer.md"
- BMMiner: "API/bmminer.md"
- BOSMiner: "API/bosminer.md"
- BTMiner: "API/btminer.md"
- CGMiner: "API/cgminer.md"
- Unknown: "API/unknown.md"
- Backends:
- BMMiner: "miners/backends/bmminer.md"
- BOSMiner: "miners/backends/bosminer.md"
- BFGMiner: "miners/backends/bfgminer.md"
- BTMiner: "miners/backends/btminer.md"
- CGMiner: "miners/backends/cgminer.md"
- Hiveon: "miners/backends/hiveon.md"
- Classes:
- Antminer X3: "miners/antminer/X3.md"
- Antminer X5: "miners/antminer/X5.md"
- Antminer X7: "miners/antminer/X7.md"
- Antminer X9: "miners/antminer/X9.md"
- Antminer X15: "miners/antminer/X15.md"
- Antminer X17: "miners/antminer/X17.md"
- Antminer X19: "miners/antminer/X19.md"
- Avalon 7X: "miners/avalonminer/A7X.md"
- Avalon 8X: "miners/avalonminer/A8X.md"
- Avalon 9X: "miners/avalonminer/A9X.md"
- Avalon 10X: "miners/avalonminer/A10X.md"
- Whatsminer M2X: "miners/whatsminer/M2X.md"
- Whatsminer M3X: "miners/whatsminer/M3X.md"
- Whatsminer M5X: "miners/whatsminer/M5X.md"
- Innosilicon T3X: "miners/innosilicon/T3X.md"
- Innosilicon A10X: "miners/innosilicon/A10X.md"
- Goldshell CKX: "miners/goldshell/CKX.md"
- Goldshell HSX: "miners/goldshell/HSX.md"
- Goldshell KDX: "miners/goldshell/KDX.md"
- Base Miner: "miners/base_miner.md"
plugins:

View File

@@ -92,9 +92,7 @@ class BaseMinerAPI:
async def send_privileged_command(self, *args, **kwargs) -> dict:
return await self.send_command(*args, **kwargs)
async def multicommand(
self, *commands: str, ignore_errors: bool = False, allow_warning: bool = True
) -> dict:
async def multicommand(self, *commands: str, allow_warning: bool = True) -> dict:
"""Creates and sends multiple commands as one command to the miner.
Parameters:
@@ -103,19 +101,25 @@ class BaseMinerAPI:
allow_warning: A boolean to supress APIWarnings.
"""
# make sure we can actually run each command, otherwise they will fail
commands = self._check_commands(*commands)
# standard multicommand format is "command1+command2"
# standard format doesn't work for X19
command = "+".join(commands)
try:
data = await self.send_command(
command, allow_warning=allow_warning, ignore_errors=ignore_errors
)
except APIError:
return {command: [{}] for command in commands}
logging.debug(f"{self} - (Multicommand) - Received data")
return data
while True:
# make sure we can actually run each command, otherwise they will fail
commands = self._check_commands(*commands)
# standard multicommand format is "command1+command2"
# standard format doesn't work for X19
command = "+".join(commands)
try:
data = await self.send_command(command, allow_warning=allow_warning)
except APIError as e:
# try to identify the error
if ":" in e.message:
err_command = e.message.split(":")[0]
if err_command in commands:
commands.remove(err_command)
continue
return {command: [{}] for command in commands}
logging.debug(f"{self} - (Multicommand) - Received data")
data["multicommand"] = True
return data
@property
def commands(self) -> list:
@@ -146,9 +150,10 @@ class BaseMinerAPI:
]
def _check_commands(self, *commands):
allowed_commands = self.get_commands()
allowed_commands = self.commands
return_commands = []
for command in [*commands]:
for command in commands:
if command in allowed_commands:
return_commands.append(command)
else:

View File

@@ -52,9 +52,10 @@ class BFGMinerAPI(BaseMinerAPI):
except APIError:
logging.debug(f"{self} - (Multicommand) - Handling X19 multicommand.")
data = await self._x19_multicommand(*command.split("+"))
data["multicommand"] = True
return data
async def _x19_multicommand(self, *commands):
async def _x19_multicommand(self, *commands) -> dict:
data = None
try:
data = {}

View File

@@ -53,9 +53,10 @@ class BMMinerAPI(BaseMinerAPI):
data = await self._x19_multicommand(
*command.split("+"), allow_warning=allow_warning
)
data["multicommand"] = True
return data
async def _x19_multicommand(self, *commands, allow_warning: bool = True):
async def _x19_multicommand(self, *commands, allow_warning: bool = True) -> dict:
data = None
try:
data = {}

View File

@@ -224,6 +224,7 @@ class BTMinerAPI(BaseMinerAPI):
logging.debug(f"{self} - (Multicommand) - Received data")
data = dict(**main_data, **get_commands_data)
data["multicommand"] = True
return data
async def send_privileged_command(

View File

@@ -52,9 +52,10 @@ class CGMinerAPI(BaseMinerAPI):
except APIError:
logging.debug(f"{self} - (Multicommand) - Handling X19 multicommand.")
data = await self._x19_multicommand(*command.split("+"))
data["multicommand"] = True
return data
async def _x19_multicommand(self, *commands):
async def _x19_multicommand(self, *commands) -> dict:
data = None
try:
data = {}

View File

@@ -91,20 +91,7 @@ class _Pool:
pool = {"url": self.url, "user": username, "pass": self.password}
return pool
def as_x15(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a dict usable by an X15 device.
Parameters:
user_suffix: The suffix to append to username.
"""
username = self.username
if user_suffix:
username = f"{username}{user_suffix}"
pool = {"url": self.url, "user": username, "pass": self.password}
return pool
def as_x5(self, user_suffix: str = None) -> dict:
def as_x17(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a dict usable by an X5 device.
Parameters:
@@ -227,33 +214,7 @@ class _PoolGroup:
pools.append(pool.as_x19(user_suffix=user_suffix))
return pools
def as_x15(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a list usable by an X15 device.
Parameters:
user_suffix: The suffix to append to username.
"""
pools = {
"_ant_pool1url": "",
"_ant_pool1user": "",
"_ant_pool1pw": "",
"_ant_pool2url": "",
"_ant_pool2user": "",
"_ant_pool2pw": "",
"_ant_pool3url": "",
"_ant_pool3user": "",
"_ant_pool3pw": "",
}
for idx, pool in enumerate(self.pools[:3]):
pools[f"_ant_pool{idx+1}url"] = pool.as_x15(user_suffix=user_suffix)["url"]
pools[f"_ant_pool{idx+1}user"] = pool.as_x15(user_suffix=user_suffix)[
"user"
]
pools[f"_ant_pool{idx+1}pw"] = pool.as_x15(user_suffix=user_suffix)["pass"]
return pools
def as_x5(self, user_suffix: str = None) -> dict:
def as_x17(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a list usable by an X5 device.
Parameters:
@@ -271,9 +232,11 @@ class _PoolGroup:
"_ant_pool3pw": "",
}
for idx, pool in enumerate(self.pools[:3]):
pools[f"_ant_pool{idx+1}url"] = pool.as_x5(user_suffix=user_suffix)["url"]
pools[f"_ant_pool{idx+1}user"] = pool.as_x5(user_suffix=user_suffix)["user"]
pools[f"_ant_pool{idx+1}pw"] = pool.as_x5(user_suffix=user_suffix)["pass"]
pools[f"_ant_pool{idx+1}url"] = pool.as_x17(user_suffix=user_suffix)["url"]
pools[f"_ant_pool{idx+1}user"] = pool.as_x17(user_suffix=user_suffix)[
"user"
]
pools[f"_ant_pool{idx+1}pw"] = pool.as_x17(user_suffix=user_suffix)["pass"]
return pools
@@ -451,13 +414,13 @@ class MinerConfig:
if data[key]:
self.miner_mode = X19PowerMode(int(data[key]))
elif key == "fan_control":
for _key in data[key].keys():
for _key in data[key]:
if _key == "min_fans":
self.minimum_fans = data[key][_key]
elif _key == "speed":
self.fan_speed = data[key][_key]
elif key == "temp_control":
for _key in data[key].keys():
for _key in data[key]:
if _key == "mode":
self.temp_mode = data[key][_key]
elif _key == "target_temp":
@@ -472,7 +435,7 @@ class MinerConfig:
self.asicboost = data[key]["asic_boost"]
if key == "autotuning":
for _key in data[key].keys():
for _key in data[key]:
if _key == "enabled":
self.autotuning_enabled = data[key][_key]
elif _key == "psu_power_limit":
@@ -485,7 +448,7 @@ class MinerConfig:
self.autotuning_mode = data[key][_key].replace("_target", "")
if key in ["power_scaling", "performance_scaling"]:
for _key in data[key].keys():
for _key in data[key]:
if _key == "enabled":
self.dps_enabled = data[key][_key]
elif _key == "power_step":
@@ -598,23 +561,13 @@ class MinerConfig:
return cfg
def as_x15(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a config usable by an X15 device.
Parameters:
user_suffix: The suffix to append to username.
"""
cfg = self.pool_groups[0].as_x15(user_suffix=user_suffix)
return cfg
def as_x5(self, user_suffix: str = None) -> dict:
def as_x17(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a config usable by an X5 device.
Parameters:
user_suffix: The suffix to append to username.
"""
cfg = self.pool_groups[0].as_x5(user_suffix=user_suffix)
cfg = self.pool_groups[0].as_x17(user_suffix=user_suffix)
return cfg
@@ -685,6 +638,13 @@ class MinerConfig:
cfg["hash_chain_global"] = {}
cfg["hash_chain_global"]["asic_boost"] = self.asicboost
if self.minimum_fans is not None or self.fan_speed is not None:
cfg["fan_control"] = {}
if self.minimum_fans is not None:
cfg["fan_control"]["min_fans"] = self.minimum_fans
if self.fan_speed is not None:
cfg["fan_control"]["speed"] = self.fan_speed
if any(
[
getattr(self, item)

View File

@@ -96,7 +96,9 @@ class MinerData:
right_chips: The number of chips online in the left board as an int.
total_chips: The total number of chips on all boards. Calculated automatically.
ideal_chips: The ideal number of chips in the miner as an int.
percent_ideal: The percent of total chips out of the ideal count. Calculated automatically.
percent_ideal_chips: The percent of total chips out of the ideal count. Calculated automatically.
percent_ideal_hashrate: The percent of total hashrate out of the ideal hashrate. Calculated automatically.
percent_ideal_wattage: The percent of total wattage out of the ideal wattage. Calculated automatically.
nominal: Whether the number of chips in the miner is nominal. Calculated automatically.
pool_split: The pool split as a str.
pool_1_url: The first pool url on the miner as a str.
@@ -116,7 +118,8 @@ class MinerData:
api_ver: str = "Unknown"
fw_ver: str = "Unknown"
hostname: str = "Unknown"
hashrate: float = 0
hashrate: float = field(init=False)
_hashrate: float = 0
nominal_hashrate: float = 0
hashboards: List[HashBoard] = field(default_factory=list)
ideal_hashboards: int = 1
@@ -144,7 +147,9 @@ class MinerData:
right_chips: int = field(init=False)
total_chips: int = field(init=False)
ideal_chips: int = 1
percent_ideal: float = field(init=False)
percent_ideal_chips: float = field(init=False)
percent_ideal_hashrate: float = field(init=False)
percent_ideal_wattage: float = field(init=False)
nominal: int = field(init=False)
pool_split: str = "0"
pool_1_url: str = "Unknown"
@@ -213,6 +218,16 @@ class MinerData:
setattr(cp, key, item & other_item)
return cp
@property
def hashrate(self): # noqa - Skip PyCharm inspection
if len(self.hashboards) > 0:
return round(sum(map(lambda x: x.hashrate, self.hashboards)), 2)
return self._hashrate
@hashrate.setter
def hashrate(self, val):
self._hashrate = val
@property
def fan_1(self): # noqa - Skip PyCharm inspection
if len(self.fans) > 0:
@@ -259,8 +274,9 @@ class MinerData:
@property
def left_chips(self): # noqa - Skip PyCharm inspection
if len(self.hashboards) in [2, 3]:
if len(self.hashboards) in [2, 3, 4]:
return self.hashboards[0].chips
return 0
@left_chips.setter
@@ -271,7 +287,7 @@ class MinerData:
def center_chips(self): # noqa - Skip PyCharm inspection
if len(self.hashboards) == 1:
return self.hashboards[0].chips
if len(self.hashboards) == 3:
if len(self.hashboards) in [2, 3, 4]:
return self.hashboards[1].chips
return 0
@@ -285,6 +301,8 @@ class MinerData:
return self.hashboards[1].chips
if len(self.hashboards) == 3:
return self.hashboards[2].chips
if len(self.hashboards) > 3:
return self.hashboards[-1:][0].chips
return 0
@right_chips.setter
@@ -293,7 +311,7 @@ class MinerData:
@property
def left_board_hashrate(self): # noqa - Skip PyCharm inspection
if len(self.hashboards) in [2, 3]:
if len(self.hashboards) in [2, 3, 4]:
return self.hashboards[0].hashrate
return 0
@@ -305,7 +323,7 @@ class MinerData:
def center_board_hashrate(self): # noqa - Skip PyCharm inspection
if len(self.hashboards) == 1:
return self.hashboards[0].hashrate
if len(self.hashboards) == 3:
if len(self.hashboards) in [2, 3, 4]:
return self.hashboards[1].hashrate
return 0
@@ -319,6 +337,8 @@ class MinerData:
return self.hashboards[1].hashrate
if len(self.hashboards) == 3:
return self.hashboards[2].hashrate
if len(self.hashboards) > 3:
return self.hashboards[-1:][0].hashrate
return 0
@right_board_hashrate.setter
@@ -327,7 +347,7 @@ class MinerData:
@property
def left_board_temp(self): # noqa - Skip PyCharm inspection
if len(self.hashboards) in [2, 3]:
if len(self.hashboards) in [2, 3, 4]:
return self.hashboards[0].temp
return 0
@@ -339,7 +359,7 @@ class MinerData:
def center_board_temp(self): # noqa - Skip PyCharm inspection
if len(self.hashboards) == 1:
return self.hashboards[0].temp
if len(self.hashboards) == 3:
if len(self.hashboards) in [2, 3, 4]:
return self.hashboards[1].temp
return 0
@@ -353,6 +373,8 @@ class MinerData:
return self.hashboards[1].temp
if len(self.hashboards) == 3:
return self.hashboards[2].temp
if len(self.hashboards) > 3:
return self.hashboards[-1:][0].temp
return 0
@right_board_temp.setter
@@ -361,7 +383,7 @@ class MinerData:
@property
def left_board_chip_temp(self): # noqa - Skip PyCharm inspection
if len(self.hashboards) in [2, 3]:
if len(self.hashboards) in [2, 3, 4]:
return self.hashboards[0].chip_temp
return 0
@@ -373,7 +395,7 @@ class MinerData:
def center_board_chip_temp(self): # noqa - Skip PyCharm inspection
if len(self.hashboards) == 1:
return self.hashboards[0].chip_temp
if len(self.hashboards) == 3:
if len(self.hashboards) in [2, 3, 4]:
return self.hashboards[1].chip_temp
return 0
@@ -387,6 +409,8 @@ class MinerData:
return self.hashboards[1].chip_temp
if len(self.hashboards) == 3:
return self.hashboards[2].chip_temp
if len(self.hashboards) > 3:
return self.hashboards[-1:][0].chip_temp
return 0
@right_board_chip_temp.setter
@@ -402,13 +426,33 @@ class MinerData:
pass
@property
def percent_ideal(self): # noqa - Skip PyCharm inspection
def percent_ideal_chips(self): # noqa - Skip PyCharm inspection
if self.total_chips == 0 or self.ideal_chips == 0:
return 0
return round((self.total_chips / self.ideal_chips) * 100)
@percent_ideal.setter
def percent_ideal(self, val):
@percent_ideal_chips.setter
def percent_ideal_chips(self, val):
pass
@property
def percent_ideal_hashrate(self): # noqa - Skip PyCharm inspection
if self.hashrate == 0 or self.nominal_hashrate == 0:
return 0
return round((self.hashrate / self.nominal_hashrate) * 100)
@percent_ideal_hashrate.setter
def percent_ideal_hashrate(self, val):
pass
@property
def percent_ideal_wattage(self): # noqa - Skip PyCharm inspection
if self.wattage_limit == 0 or self.wattage == 0:
return 0
return round((self.wattage / self.wattage_limit) * 100)
@percent_ideal_wattage.setter
def percent_ideal_wattage(self, val):
pass
@property

View File

@@ -16,7 +16,7 @@
from dataclasses import asdict, dataclass, field, fields
C_N_CODES = ["52", "53", "54", "55"]
C_N_CODES = ["52", "53", "54", "55", "56"]
@dataclass
@@ -264,6 +264,7 @@ ERROR_CODES = {
53: {"n": {"c": "Slot {n} chip {c} too few nonce."}},
54: {"n": {"c": "Slot {n} chip {c} temp protected."}},
55: {"n": {"c": "Slot {n} chip {c} has been reset."}},
56: {"n": {"c": "Slot {n} chip {c} does not return to the nonce."}},
80: {
0: {0: "The tool version is too low, please update."},
1: {0: "Low freq."},

View File

@@ -19,8 +19,8 @@ from typing import List, Union
from pyasic.errors import APIError
from pyasic.miners import AnyMiner
from pyasic.miners.btc._backends import ( # noqa - Ignore access to _module
X19,
from pyasic.miners.backends import ( # noqa - Ignore access to _module
AntminerModern,
BOSMiner,
BTMiner,
)
@@ -103,7 +103,7 @@ class _MinerPhaseBalancer:
self.miners[str(miner.ip)]["tune"] = True
self.miners[str(miner.ip)]["shutdown"] = True
self.miners[str(miner.ip)]["max"] = 3600
elif isinstance(miner, X19):
elif isinstance(miner, AntminerModern):
self.miners[str(miner.ip)]["tune"] = False
self.miners[str(miner.ip)]["shutdown"] = True
self.miners[str(miner.ip)]["max"] = 3600

View File

@@ -13,7 +13,9 @@
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
from .antminer import AntminerModern, AntminerOld
from .bfgminer import BFGMiner
from .bfgminer_goldshell import BFGMinerGoldshell
from .bmminer import BMMiner
from .bosminer import BOSMiner
from .btminer import BTMiner
@@ -21,4 +23,4 @@ from .cgminer import CGMiner
from .cgminer_avalon import CGMinerAvalon
from .hiveon import Hiveon
from .vnish import VNish
from .X19 import X19
from .whatsminer import M2X, M3X, M5X

View File

@@ -19,17 +19,46 @@ from typing import List, Optional, Union
from pyasic.API import APIError
from pyasic.config import MinerConfig, X19PowerMode
from pyasic.data import HashBoard
from pyasic.data import Fan, HashBoard
from pyasic.data.error_codes import MinerErrorData, X19Error
from pyasic.miners.btc._backends import BMMiner # noqa - Ignore access to _module
from pyasic.web.X7 import X7WebAPI
from pyasic.miners.backends.bmminer import BMMiner
from pyasic.miners.backends.cgminer import CGMiner
from pyasic.web.antminer import AntminerModernWebAPI, AntminerOldWebAPI
ANTMINER_MODERN_DATA_LOC = {
"mac": {"cmd": "get_mac", "kwargs": {}},
"model": {"cmd": "get_model", "kwargs": {}},
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"api_version": {"api": "version"}}},
"hostname": {"cmd": "get_hostname", "kwargs": {}},
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
"nominal_hashrate": {
"cmd": "get_nominal_hashrate",
"kwargs": {"api_stats": {"api": "stats"}},
},
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
"wattage": {"cmd": "get_wattage", "kwargs": {}},
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
"errors": {"cmd": "get_errors", "kwargs": {}},
"fault_light": {"cmd": "get_fault_light", "kwargs": {}},
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
}
class X7(BMMiner):
class AntminerModern(BMMiner):
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
super().__init__(ip, api_ver=api_ver)
self.ip = ip
self.web = X7WebAPI(ip)
super().__init__(ip, api_ver)
# interfaces
self.web = AntminerModernWebAPI(ip)
# static data
# data gathering locations
self.data_locations = ANTMINER_MODERN_DATA_LOC
# autotuning/shutdown support
self.supports_shutdown = True
async def get_config(self) -> MinerConfig:
data = await self.web.get_miner_conf()
@@ -37,97 +66,6 @@ class X7(BMMiner):
self.config = MinerConfig().from_raw(data)
return self.config
async def get_hashrate(self, api_summary: dict = None) -> Optional[float]:
# get hr from API
if not api_summary:
try:
api_summary = await self.api.summary()
except APIError:
pass
if api_summary:
try:
# not actually GHS, MHS.
return round(float(api_summary["SUMMARY"][0]["GHS 5s"] / 1000000), 5)
except (IndexError, KeyError, ValueError, TypeError):
pass
async def get_hashboards(self, api_stats: dict = None) -> List[HashBoard]:
hashboards = []
if not api_stats:
try:
api_stats = await self.api.stats()
except APIError:
pass
if api_stats:
try:
board_offset = -1
boards = api_stats["STATS"]
if len(boards) > 1:
for board_num in range(1, 16, 5):
for _b_num in range(5):
b = boards[1].get(f"chain_acn{board_num + _b_num}")
if b and not b == 0 and board_offset == -1:
board_offset = board_num
if board_offset == -1:
board_offset = 1
for i in range(board_offset, board_offset + self.ideal_hashboards):
hashboard = HashBoard(
slot=i - board_offset, expected_chips=self.nominal_chips
)
chip_temp = boards[1].get(f"temp{i}")
if chip_temp:
hashboard.chip_temp = round(chip_temp)
temp = boards[1].get(f"temp2_{i}")
if temp:
hashboard.temp = round(temp)
hashrate = boards[1].get(f"chain_rate{i}")
if hashrate:
hashboard.hashrate = round(float(hashrate) / 1000, 5)
chips = boards[1].get(f"chain_acn{i}")
if chips:
hashboard.chips = chips
hashboard.missing = False
if (not chips) or (not chips > 0):
hashboard.missing = True
hashboards.append(hashboard)
except (IndexError, KeyError, ValueError, TypeError):
pass
return hashboards
async def get_nominal_hashrate(self, api_stats: dict = None) -> Optional[float]:
# X19 method, not sure compatibility
if not api_stats:
try:
api_stats = await self.api.stats()
except APIError:
pass
if api_stats:
try:
ideal_rate = api_stats["STATS"][1]["total_rateideal"]
try:
rate_unit = api_stats["STATS"][1]["rate_unit"]
except KeyError:
rate_unit = "MH"
if rate_unit == "GH":
return round(ideal_rate, 2)
if rate_unit == "MH":
return round(ideal_rate / 1000000, 5)
else:
return round(ideal_rate, 2)
except (KeyError, IndexError):
pass
async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:
self.config = config
conf = config.as_x19(user_suffix=user_suffix)
@@ -160,19 +98,16 @@ class X7(BMMiner):
return False
async def stop_mining(self) -> bool:
return False
# maybe in a later update
# cfg = await self.get_config()
# cfg.miner_mode = X19PowerMode.Sleep
# await self.send_config(cfg)
# return True
cfg = await self.get_config()
cfg.miner_mode = X19PowerMode.Sleep
await self.send_config(cfg)
return True
async def resume_mining(self) -> bool:
return False
# cfg = await self.get_config()
# cfg.miner_mode = X19PowerMode.Normal
# await self.send_config(cfg)
# return True
cfg = await self.get_config()
cfg.miner_mode = X19PowerMode.Normal
await self.send_config(cfg)
return True
async def get_hostname(self) -> Union[str, None]:
try:
@@ -223,6 +158,29 @@ class X7(BMMiner):
pass
return self.light
async def get_nominal_hashrate(self, api_stats: dict = None) -> Optional[float]:
if not api_stats:
try:
api_stats = await self.api.stats()
except APIError:
pass
if api_stats:
try:
ideal_rate = api_stats["STATS"][1]["total_rateideal"]
try:
rate_unit = api_stats["STATS"][1]["rate_unit"]
except KeyError:
rate_unit = "GH"
if rate_unit == "GH":
return round(ideal_rate / 1000, 2)
if rate_unit == "MH":
return round(ideal_rate / 1000000, 2)
else:
return round(ideal_rate, 2)
except (KeyError, IndexError):
pass
async def set_static_ip(
self,
ip: str,
@@ -264,3 +222,202 @@ class X7(BMMiner):
hostname=hostname,
protocol=protocol,
)
ANTMINER_OLD_DATA_LOC = {
"mac": {"cmd": "get_mac", "kwargs": {}},
"model": {
"cmd": "get_model",
"kwargs": {},
},
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"api_version": {"api": "version"}}},
"hostname": {
"cmd": "get_hostname",
"kwargs": {"web_get_system_info": {"web": "get_system_info"}},
},
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
"nominal_hashrate": {
"cmd": "get_nominal_hashrate",
"kwargs": {"api_stats": {"api": "stats"}},
},
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
"wattage": {"cmd": "get_wattage", "kwargs": {}},
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
"errors": {"cmd": "get_errors", "kwargs": {}},
"fault_light": {
"cmd": "get_fault_light",
"kwargs": {"web_get_blink_status": {"web": "get_blink_status"}},
},
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
}
class AntminerOld(CGMiner):
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
super().__init__(ip, api_ver)
# interfaces
self.web = AntminerOldWebAPI(ip)
# static data
# data gathering locations
self.data_locations = ANTMINER_OLD_DATA_LOC
async def get_config(self) -> MinerConfig:
data = await self.web.get_miner_conf()
if data:
self.config = MinerConfig().from_raw(data)
return self.config
async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:
await self.web.set_miner_conf(config.as_x17(user_suffix=user_suffix))
async def get_mac(self) -> Union[str, None]:
try:
data = await self.web.get_system_info()
if data:
return data["macaddr"]
except KeyError:
pass
async def fault_light_on(self) -> bool:
# this should time out, after it does do a check
await self.web.blink(blink=True)
try:
data = await self.web.get_blink_status()
if data:
if data["isBlinking"]:
self.light = True
except KeyError:
pass
return self.light
async def fault_light_off(self) -> bool:
await self.web.blink(blink=False)
try:
data = await self.web.get_blink_status()
if data:
if not data["isBlinking"]:
self.light = False
except KeyError:
pass
return self.light
async def reboot(self) -> bool:
data = await self.web.reboot()
if data:
return True
return False
async def get_fault_light(self, web_get_blink_status: dict = None) -> bool:
if self.light:
return self.light
if not web_get_blink_status:
try:
web_get_blink_status = await self.web.get_blink_status()
except APIError:
pass
if web_get_blink_status:
try:
self.light = web_get_blink_status["isBlinking"]
except KeyError:
pass
return self.light
async def get_hostname(self, web_get_system_info: dict = None) -> Optional[str]:
if not web_get_system_info:
try:
web_get_system_info = await self.web.get_system_info()
except APIError:
pass
if web_get_system_info:
try:
return web_get_system_info["hostname"]
except KeyError:
pass
async def get_fans(self, api_stats: dict = None) -> List[Fan]:
if not api_stats:
try:
api_stats = await self.api.stats()
except APIError:
pass
fans_data = [Fan(), Fan(), Fan(), Fan()]
if api_stats:
try:
fan_offset = -1
for fan_num in range(1, 8, 4):
for _f_num in range(4):
f = api_stats["STATS"][1].get(f"fan{fan_num + _f_num}")
if f and not f == 0 and fan_offset == -1:
fan_offset = fan_num + 2
if fan_offset == -1:
fan_offset = 3
for fan in range(self.fan_count):
fans_data[fan] = Fan(
api_stats["STATS"][1].get(f"fan{fan_offset+fan}")
)
except (KeyError, IndexError):
pass
return fans_data
async def get_hashboards(self, api_stats: dict = None) -> List[HashBoard]:
hashboards = []
if not api_stats:
try:
api_stats = await self.api.stats()
except APIError:
pass
if api_stats:
try:
board_offset = -1
boards = api_stats["STATS"]
if len(boards) > 1:
for board_num in range(1, 16, 5):
for _b_num in range(5):
b = boards[1].get(f"chain_acn{board_num + _b_num}")
if b and not b == 0 and board_offset == -1:
board_offset = board_num
if board_offset == -1:
board_offset = 1
for i in range(board_offset, board_offset + self.ideal_hashboards):
hashboard = HashBoard(
slot=i - board_offset, expected_chips=self.nominal_chips
)
chip_temp = boards[1].get(f"temp{i}")
if chip_temp:
hashboard.chip_temp = round(chip_temp)
temp = boards[1].get(f"temp2_{i}")
if temp:
hashboard.temp = round(temp)
hashrate = boards[1].get(f"chain_rate{i}")
if hashrate:
hashboard.hashrate = round(float(hashrate) / 1000, 2)
chips = boards[1].get(f"chain_acn{i}")
if chips:
hashboard.chips = chips
hashboard.missing = False
if (not chips) or (not chips > 0):
hashboard.missing = True
hashboards.append(hashboard)
except (IndexError, KeyError, ValueError, TypeError):
pass
return hashboards

View File

@@ -14,7 +14,6 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
import ipaddress
import logging
from collections import namedtuple
from typing import List, Optional, Tuple
@@ -26,18 +25,44 @@ from pyasic.data.error_codes import MinerErrorData
from pyasic.errors import APIError
from pyasic.miners.base import BaseMiner
BFGMINER_DATA_LOC = {
"mac": {"cmd": "get_mac", "kwargs": {}},
"model": {"cmd": "get_model", "kwargs": {}},
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"api_version": {"api": "version"}}},
"hostname": {"cmd": "get_hostname", "kwargs": {}},
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
"nominal_hashrate": {
"cmd": "get_nominal_hashrate",
"kwargs": {"api_stats": {"api": "stats"}},
},
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
"wattage": {"cmd": "get_wattage", "kwargs": {}},
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
"errors": {"cmd": "get_errors", "kwargs": {}},
"fault_light": {"cmd": "get_fault_light", "kwargs": {}},
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
}
class BFGMiner(BaseMiner):
"""Base handler for BFGMiner based miners."""
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
super().__init__(ip)
self.ip = ipaddress.ip_address(ip)
# interfaces
self.api = BFGMinerAPI(ip, api_ver)
# static data
self.api_type = "BFGMiner"
# data gathering locations
self.data_locations = BFGMINER_DATA_LOC
# data storage
self.api_ver = api_ver
self.uname = "root"
self.pwd = "admin"
async def get_config(self) -> MinerConfig:
# get pool data
@@ -77,30 +102,6 @@ class BFGMiner(BaseMiner):
async def get_mac(self) -> str:
return "00:00:00:00:00:00"
async def get_model(self, api_devdetails: dict = None) -> Optional[str]:
if self.model:
logging.debug(f"Found model for {self.ip}: {self.model}")
return self.model
if not api_devdetails:
try:
api_devdetails = await self.api.devdetails()
except APIError:
pass
if api_devdetails:
try:
self.model = api_devdetails["DEVDETAILS"][0]["Model"].replace(
"Antminer ", ""
)
logging.debug(f"Found model for {self.ip}: {self.model}")
return self.model
except (TypeError, IndexError, KeyError):
pass
logging.warning(f"Failed to get model for miner: {self}")
return None
async def get_api_ver(self, api_version: dict = None) -> Optional[str]:
# Check to see if the version info is already cached
if self.api_ver:

View File

@@ -13,20 +13,53 @@
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
from typing import List, Optional
from typing import List
from pyasic.config import MinerConfig
from pyasic.data import Fan, HashBoard
from pyasic.data import HashBoard
from pyasic.errors import APIError
from pyasic.miners.hns._backends import BFGMiner
from pyasic.miners.backends import BFGMiner
from pyasic.web.goldshell import GoldshellWebAPI
GOLDSHELL_DATA_LOC = {
"mac": {"cmd": "get_mac", "kwargs": {"web_setting": {"web": "setting"}}},
"model": {"cmd": "get_model", "kwargs": {}},
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"web_status": {"web": "status"}}},
"hostname": {"cmd": "get_hostname", "kwargs": {}},
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
"nominal_hashrate": {
"cmd": "get_nominal_hashrate",
"kwargs": {"api_stats": {"api": "stats"}},
},
"hashboards": {
"cmd": "get_hashboards",
"kwargs": {
"api_devs": {"api": "devs"},
"api_devdetails": {"api": "devdetails"},
},
},
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
"wattage": {"cmd": "get_wattage", "kwargs": {}},
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
"errors": {"cmd": "get_errors", "kwargs": {}},
"fault_light": {"cmd": "get_fault_light", "kwargs": {}},
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
}
class Goldshell(BFGMiner):
class BFGMinerGoldshell(BFGMiner):
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
super().__init__(ip, api_ver)
# interfaces
self.web = GoldshellWebAPI(ip)
# static data
# data gathering locations
self.data_locations = GOLDSHELL_DATA_LOC
async def get_config(self) -> MinerConfig:
return MinerConfig().from_raw(await self.web.pools())
@@ -75,7 +108,9 @@ class Goldshell(BFGMiner):
except KeyError:
pass
async def get_hashboards(self, api_devs: dict = None) -> List[HashBoard]:
async def get_hashboards(
self, api_devs: dict = None, api_devdetails: dict = None
) -> List[HashBoard]:
if not api_devs:
try:
api_devs = await self.api.devs()
@@ -88,14 +123,37 @@ class Goldshell(BFGMiner):
]
if api_devs:
for board in api_devs["DEVS"]:
if board.get("ID"):
try:
b_id = board["ID"]
hashboards[b_id].hashrate = round(board["MHS 20s"] / 1000000, 2)
hashboards[b_id].temp = board["tstemp-2"]
hashboards[b_id].missing = False
except KeyError:
pass
if api_devs.get("DEVS"):
for board in api_devs["DEVS"]:
if board.get("ID") is not None:
try:
b_id = board["ID"]
hashboards[b_id].hashrate = round(
board["MHS 20s"] / 1000000, 2
)
hashboards[b_id].temp = board["tstemp-2"]
hashboards[b_id].missing = False
except KeyError:
pass
else:
print(self, api_devs)
if not api_devdetails:
try:
api_devdetails = await self.api.devdetails()
except APIError:
pass
if api_devdetails:
if api_devdetails.get("DEVS"):
for board in api_devdetails["DEVS"]:
if board.get("ID") is not None:
try:
b_id = board["ID"]
hashboards[b_id].chips = board["chips-nr"]
except KeyError:
pass
else:
print(self, api_devdetails)
return hashboards

View File

@@ -14,7 +14,6 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
import ipaddress
import logging
from collections import namedtuple
from typing import List, Optional, Tuple
@@ -28,18 +27,44 @@ from pyasic.data.error_codes import MinerErrorData
from pyasic.errors import APIError
from pyasic.miners.base import BaseMiner
BMMINER_DATA_LOC = {
"mac": {"cmd": "get_mac", "kwargs": {}},
"model": {"cmd": "get_model", "kwargs": {}},
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"api_version": {"api": "version"}}},
"hostname": {"cmd": "get_hostname", "kwargs": {}},
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
"nominal_hashrate": {
"cmd": "get_nominal_hashrate",
"kwargs": {"api_stats": {"api": "stats"}},
},
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
"wattage": {"cmd": "get_wattage", "kwargs": {}},
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
"errors": {"cmd": "get_errors", "kwargs": {}},
"fault_light": {"cmd": "get_fault_light", "kwargs": {}},
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
}
class BMMiner(BaseMiner):
"""Base handler for BMMiner based miners."""
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
super().__init__(ip)
self.ip = ipaddress.ip_address(ip)
# interfaces
self.api = BMMinerAPI(ip, api_ver)
# static data
self.api_type = "BMMiner"
# data gathering locations
self.data_locations = BMMINER_DATA_LOC
# data storage
self.api_ver = api_ver
self.uname = "root"
self.pwd = "admin"
async def send_ssh_command(self, cmd: str) -> Optional[str]:
result = None
@@ -115,30 +140,6 @@ class BMMiner(BaseMiner):
async def get_mac(self) -> str:
return "00:00:00:00:00:00"
async def get_model(self, api_devdetails: dict = None) -> Optional[str]:
if self.model:
logging.debug(f"Found model for {self.ip}: {self.model}")
return self.model
if not api_devdetails:
try:
api_devdetails = await self.api.devdetails()
except APIError:
pass
if api_devdetails:
try:
self.model = api_devdetails["DEVDETAILS"][0]["Model"].replace(
"Antminer ", ""
)
logging.debug(f"Found model for {self.ip}: {self.model}")
return self.model
except (TypeError, IndexError, KeyError):
pass
logging.warning(f"Failed to get model for miner: {self}")
return None
async def get_api_ver(self, api_version: dict = None) -> Optional[str]:
# Check to see if the version info is already cached
if self.api_ver:
@@ -193,8 +194,7 @@ class BMMiner(BaseMiner):
async def get_hostname(self) -> Optional[str]:
hn = await self.send_ssh_command("cat /proc/sys/kernel/hostname")
if hn:
self.hostname = hn
return self.hostname
return hn
async def get_hashrate(self, api_summary: dict = None) -> Optional[float]:
# get hr from API

View File

@@ -14,14 +14,11 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
import ipaddress
import json
import logging
from collections import namedtuple
from typing import List, Optional, Tuple, Union
import asyncssh
import httpx
import toml
from pyasic.API.bosminer import BOSMinerAPI
@@ -30,18 +27,167 @@ from pyasic.data import Fan, HashBoard
from pyasic.data.error_codes import BraiinsOSError, MinerErrorData
from pyasic.errors import APIError
from pyasic.miners.base import BaseMiner
from pyasic.web.bosminer import BOSMinerWebAPI
BOSMINER_DATA_LOC = {
"mac": {"cmd": "get_mac", "kwargs": {}},
"model": {"cmd": "get_model", "kwargs": {}},
"api_ver": {
"cmd": "get_api_ver",
"kwargs": {"api_version": {"api": "version"}},
},
"fw_ver": {
"cmd": "get_fw_ver",
"kwargs": {
"graphql_version": {"web": {"bos": {"info": {"version": {"full": None}}}}}
},
},
"hostname": {
"cmd": "get_hostname",
"kwargs": {"graphql_hostname": {"web": {"bos": {"hostname": None}}}},
},
"hashrate": {
"cmd": "get_hashrate",
"kwargs": {
"api_summary": {"api": "summary"},
"graphql_hashrate": {
"web": {
"bosminer": {
"info": {"workSolver": {"realHashrate": {"mhs1M": None}}}
}
},
},
},
},
"nominal_hashrate": {
"cmd": "get_nominal_hashrate",
"kwargs": {"api_devs": {"api": "devs"}},
},
"hashboards": {
"cmd": "get_hashboards",
"kwargs": {
"api_temps": {"api": "temps"},
"api_devdetails": {"api": "devdetails"},
"api_devs": {"api": "devs"},
"graphql_boards": {
"web": {
"bosminer": {
"info": {
"workSolver": {
"childSolvers": {
"name": None,
"realHashrate": {"mhs1M": None},
"hwDetails": {"chips": None},
"temperatures": {"degreesC": None},
}
}
}
}
},
},
},
},
"wattage": {
"cmd": "get_wattage",
"kwargs": {
"api_tunerstatus": {"api": "tunerstatus"},
"graphql_wattage": {
"web": {
"bosminer": {
"info": {"workSolver": {"power": {"approxConsumptionW": None}}}
}
}
},
},
},
"wattage_limit": {
"cmd": "get_wattage_limit",
"kwargs": {
"api_tunerstatus": {"api": "tunerstatus"},
"graphql_wattage_limit": {
"web": {
"bosminer": {"info": {"workSolver": {"power": {"limitW": None}}}}
}
},
},
},
"fans": {
"cmd": "get_fans",
"kwargs": {
"api_fans": {"api": "fans"},
"graphql_fans": {
"web": {"bosminer": {"info": {"fans": {"name": None, "rpm": None}}}}
},
},
},
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
"errors": {
"cmd": "get_errors",
"kwargs": {
"api_tunerstatus": {"api": "tunerstatus"},
"graphql_errors": {
"web": {
"bosminer": {
"info": {
"workSolver": {
"childSolvers": {
"name": None,
"tuner": {"statusMessages": None},
}
}
}
}
}
},
},
},
"fault_light": {
"cmd": "get_fault_light",
"kwargs": {"graphql_fault_light": {"web": {"bos": {"faultLight": None}}}},
},
"pools": {
"cmd": "get_pools",
"kwargs": {
"api_pools": {"api": "pools"},
"graphql_pools": {
"web": {
"bosminer": {
"config": {
"... on BosminerConfig": {
"groups": {
"pools": {"urluser": None},
"strategy": {
"... on QuotaStrategy": {"quota": None}
},
}
}
}
}
}
},
},
},
}
class BOSMiner(BaseMiner):
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
super().__init__(ip)
self.ip = ipaddress.ip_address(ip)
# interfaces
self.api = BOSMinerAPI(ip, api_ver)
self.web = BOSMinerWebAPI(ip)
# static data
self.api_type = "BOSMiner"
# data gathering locations
self.data_locations = BOSMINER_DATA_LOC
# autotuning/shutdown support
self.supports_autotuning = True
self.supports_shutdown = True
# data storage
self.api_ver = api_ver
self.uname = "root"
self.pwd = "admin"
self.config = None
async def send_ssh_command(self, cmd: str) -> Optional[str]:
result = None
@@ -58,8 +204,12 @@ class BOSMiner(BaseMiner):
try:
# run the command and get the result
result = await conn.run(cmd)
stderr = result.stderr
result = result.stdout
if len(stderr) > len(result):
result = stderr
except Exception as e:
# if the command fails, log it
logging.warning(f"{self} command {cmd} error: {e}")
@@ -71,49 +221,6 @@ class BOSMiner(BaseMiner):
# return the result, either command output or None
return result
async def send_graphql_query(self, query) -> Union[dict, None]:
# FW version must be equal to or greater than 21.09 to use this
if self.fw_ver:
try:
if not (
(
int(self.fw_ver.split(".")[0]) == 21
and int(self.fw_ver.split(".")[1]) >= 9
)
or int(self.fw_ver.split(".")[0]) > 21
):
logging.info(f"FW version {self.fw_ver} is too low to use graphql.")
return None
except ValueError:
pass
url = f"http://{self.ip}/graphql"
try:
async with httpx.AsyncClient() as client:
_auth = await client.post(
url,
json={
"query": 'mutation{auth{login(username:"'
+ self.uname
+ '", password:"'
+ self.pwd
+ '"){__typename}}}'
},
)
d = await client.post(url, json={"query": query})
if d.status_code == 200:
try:
data = d.json()
except json.decoder.JSONDecodeError:
raise APIError(f"GraphQL returned malformed data: {d.text}")
if data.get("errors"):
if len(data["errors"]) > 0:
raise APIError(f"GraphQL error: {data['errors'][0]['message']}")
except httpx.HTTPError:
return None
return None
async def fault_light_on(self) -> bool:
"""Sends command to turn on fault light on the miner."""
logging.debug(f"{self}: Sending fault_light on command.")
@@ -136,7 +243,7 @@ class BOSMiner(BaseMiner):
return False
async def restart_backend(self) -> bool:
"""Restart bosminer hashing process. Wraps [`restart_bosminer`][pyasic.miners._backends.bosminer.BOSMiner.restart_bosminer] to standardize."""
"""Restart bosminer hashing process. Wraps [`restart_bosminer`][pyasic.miners.backends.bosminer.BOSMiner.restart_bosminer] to standardize."""
return await self.restart_bosminer()
async def restart_bosminer(self) -> bool:
@@ -267,37 +374,7 @@ class BOSMiner(BaseMiner):
pass
async def get_model(self) -> Optional[str]:
# check if model is cached
if self.model:
logging.debug(f"Found model for {self.ip}: {self.model} (BOS)")
return self.model + " (BOS)"
# get devdetails data
try:
version_data = await self.api.devdetails()
except APIError as e:
version_data = None
if e.message == "Not ready":
cfg = json.loads(await self.send_ssh_command("bosminer config --data"))
model = cfg.get("data").get("format").get("model")
if model:
model = model.replace("Antminer ", "")
self.model = model
return self.model + " (BOS)"
# if we get data back, parse it for model
if version_data:
if not version_data["DEVDETAILS"] == []:
# handle Antminer BOSMiner as a base
self.model = version_data["DEVDETAILS"][0]["Model"].replace(
"Antminer ", ""
)
logging.debug(f"Found model for {self.ip}: {self.model} (BOS)")
return self.model + " (BOS)"
# if we don't get devdetails, log a failed attempt
logging.warning(f"Failed to get model for miner: {self}")
return None
return self.model + " (BOS)"
async def get_version(
self, api_version: dict = None, graphql_version: dict = None
@@ -329,8 +406,8 @@ class BOSMiner(BaseMiner):
async def get_fw_ver(self, graphql_version: dict = None) -> Optional[str]:
if not graphql_version:
try:
graphql_version = await self.send_graphql_query(
"{bos{info{version{full}}}}"
graphql_version = await self.web.send_command(
{"bos": {"info": {"version": {"full"}}}}
)
except APIError:
pass
@@ -357,18 +434,20 @@ class BOSMiner(BaseMiner):
return self.fw_ver
async def get_hostname(self, graphql_hostname: dict = None) -> Union[str, None]:
if self.hostname:
return self.hostname
hostname = None
if not graphql_hostname:
try:
graphql_hostname = await self.send_graphql_query("{bos {hostname}}")
graphql_hostname = await self.web.send_command({"bos": {"hostname"}})
except APIError:
pass
if graphql_hostname:
self.hostname = graphql_hostname["bos"]["hostname"]
return self.hostname
try:
hostname = graphql_hostname["bos"]["hostname"]
return hostname
except KeyError:
pass
try:
async with (await self._get_ssh_connection()) as conn:
@@ -376,12 +455,12 @@ class BOSMiner(BaseMiner):
data = await conn.run("cat /proc/sys/kernel/hostname")
host = data.stdout.strip()
logging.debug(f"Found hostname for {self.ip}: {host}")
self.hostname = host
hostname = host
else:
logging.warning(f"Failed to get hostname for miner: {self}")
except Exception as e:
logging.warning(f"Failed to get hostname for miner: {self}, {e}")
return self.hostname
return hostname
async def get_hashrate(
self, api_summary: dict = None, graphql_hashrate: dict = None
@@ -390,8 +469,8 @@ class BOSMiner(BaseMiner):
# get hr from graphql
if not graphql_hashrate:
try:
graphql_hashrate = await self.send_graphql_query(
"{bosminer{info{workSolver{realHashrate{mhs1M}}}}}"
graphql_hashrate = await self.web.send_command(
{"bosminer": {"info": {"workSolver": {"realHashrate": {"mhs1M"}}}}}
)
except APIError:
pass
@@ -437,8 +516,21 @@ class BOSMiner(BaseMiner):
if not graphql_boards and not (api_devs or api_temps or api_devdetails):
try:
graphql_boards = await self.send_graphql_query(
"{bosminer{info{workSolver{childSolvers{name, realHashrate {mhs1M}, hwDetails {chips}, temperatures {degreesC}}}}}}"
graphql_boards = await self.web.send_command(
{
"bosminer": {
"info": {
"workSolver": {
"childSolvers": {
"name": None,
"realHashrate": {"mhs1M"},
"hwDetails": {"chips"},
"temperatures": {"degreesC"},
}
}
}
}
},
)
except APIError:
pass
@@ -536,7 +628,7 @@ class BOSMiner(BaseMiner):
return hashboards
async def get_env_temp(self, *args, **kwargs) -> Optional[float]:
async def get_env_temp(self) -> Optional[float]:
return None
async def get_wattage(
@@ -544,8 +636,12 @@ class BOSMiner(BaseMiner):
) -> Optional[int]:
if not graphql_wattage and not api_tunerstatus:
try:
graphql_wattage = await self.send_graphql_query(
"{bosminer{info{workSolver{power{approxConsumptionW}}}}}"
graphql_wattage = await self.web.send_command(
{
"bosminer": {
"info": {"workSolver": {"power": {"approxConsumptionW"}}}
}
}
)
except APIError:
pass
@@ -577,8 +673,8 @@ class BOSMiner(BaseMiner):
) -> Optional[int]:
if not graphql_wattage_limit and not api_tunerstatus:
try:
graphql_wattage_limit = await self.send_graphql_query(
"{bosminer{info{workSolver{power{limitW}}}}}"
graphql_wattage_limit = await self.web.send_command(
{"bosminer": {"info": {"workSolver": {"power": {"limitW"}}}}}
)
except APIError:
pass
@@ -608,8 +704,8 @@ class BOSMiner(BaseMiner):
) -> List[Fan]:
if not graphql_fans and not api_fans:
try:
graphql_fans = await self.send_graphql_query(
"{bosminer{info{fans{name, rpm}}}"
graphql_fans = await self.web.send_command(
{"bosminer": {"info": {"fans": {"name", "rpm"}}}}
)
except APIError:
pass
@@ -636,7 +732,7 @@ class BOSMiner(BaseMiner):
for n in range(self.fan_count):
try:
fans[f"fan_{n + 1}"].speed = api_fans["FANS"][n]["RPM"]
except KeyError:
except (IndexError, KeyError):
pass
return [fans["fan_1"], fans["fan_2"], fans["fan_3"], fans["fan_4"]]
return [Fan(), Fan(), Fan(), Fan()]
@@ -649,8 +745,19 @@ class BOSMiner(BaseMiner):
) -> List[dict]:
if not graphql_pools and not api_pools:
try:
graphql_pools = await self.send_graphql_query(
"bosminer{config{... on BosminerConfig{groups{pools{urluser}strategy{... on QuotaStrategy{quota}}}}}"
graphql_pools = await self.web.send_command(
{
"bosminer": {
"config": {
"... on BosminerConfig": {
"groups": {
"pools": {"urluser"},
"strategy": {"... on QuotaStrategy": {"quota"}},
}
}
}
}
}
)
except APIError:
pass
@@ -682,30 +789,44 @@ class BOSMiner(BaseMiner):
if api_pools:
seen = []
groups = [{"quota": "0"}]
for i, pool in enumerate(api_pools["POOLS"]):
if len(seen) == 0:
seen.append(pool["User"])
if not pool["User"] in seen:
# need to use get_config, as this will never read perfectly as there are some bad edge cases
groups = []
cfg = await self.get_config()
if cfg:
for group in cfg.pool_groups:
pools = {"quota": group.quota}
for _i, _pool in enumerate(group.pools):
pools[f"pool_{_i + 1}_url"] = _pool.url.replace(
"stratum+tcp://", ""
).replace("stratum2+tcp://", "")
pools[f"pool_{_i + 1}_user"] = _pool.username
groups.append(pools)
return groups
else:
groups[0][f"pool_{i + 1}_url"] = (
pool["URL"]
.replace("stratum+tcp://", "")
.replace("stratum2+tcp://", "")
)
groups[0][f"pool_{i + 1}_user"] = pool["User"]
if api_pools.get("POOLS"):
for i, pool in enumerate(api_pools["POOLS"]):
if len(seen) == 0:
seen.append(pool["User"])
if not pool["User"] in seen:
# need to use get_config, as this will never read perfectly as there are some bad edge cases
groups = []
cfg = await self.get_config()
if cfg:
for group in cfg.pool_groups:
pools = {"quota": group.quota}
for _i, _pool in enumerate(group.pools):
pools[f"pool_{_i + 1}_url"] = _pool.url.replace(
"stratum+tcp://", ""
).replace("stratum2+tcp://", "")
pools[f"pool_{_i + 1}_user"] = _pool.username
groups.append(pools)
return groups
else:
groups[0][f"pool_{i + 1}_url"] = (
pool["URL"]
.replace("stratum+tcp://", "")
.replace("stratum2+tcp://", "")
)
groups[0][f"pool_{i + 1}_user"] = pool["User"]
else:
groups = []
cfg = await self.get_config()
if cfg:
for group in cfg.pool_groups:
pools = {"quota": group.quota}
for _i, _pool in enumerate(group.pools):
pools[f"pool_{_i + 1}_url"] = _pool.url.replace(
"stratum+tcp://", ""
).replace("stratum2+tcp://", "")
pools[f"pool_{_i + 1}_user"] = _pool.username
groups.append(pools)
return groups
return groups
async def get_errors(
@@ -713,8 +834,19 @@ class BOSMiner(BaseMiner):
) -> List[MinerErrorData]:
if not graphql_errors and not api_tunerstatus:
try:
graphql_errors = await self.send_graphql_query(
"{bosminer{info{workSolver{childSolvers{name, tuner{statusMessages}}}}}}"
graphql_errors = await self.web.send_command(
{
"bosminer": {
"info": {
"workSolver": {
"childSolvers": {
"name": None,
"tuner": {"statusMessages"},
}
}
}
}
}
)
except APIError:
pass
@@ -788,8 +920,8 @@ class BOSMiner(BaseMiner):
and int(self.fw_ver.split(".")[1]) > 9
) or int(self.fw_ver.split(".")[0]) > 21:
try:
graphql_fault_light = await self.send_graphql_query(
"{bos {faultLight}}"
graphql_fault_light = await self.web.send_command(
{"bos": {"faultLight"}}
)
except APIError:
pass
@@ -800,8 +932,8 @@ class BOSMiner(BaseMiner):
else:
# worth trying
try:
graphql_fault_light = await self.send_graphql_query(
"{bos {faultLight}}"
graphql_fault_light = await self.web.send_command(
{"bos": {"faultLight"}}
)
except APIError:
logging.debug(

View File

@@ -14,28 +14,20 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
import ipaddress
import logging
from typing import List, Optional, Tuple
import asyncssh
from pyasic.API.bosminer import BOSMinerAPI
from pyasic.config import MinerConfig
from pyasic.data import Fan, HashBoard, MinerData
from pyasic.data.error_codes import MinerErrorData
from pyasic.errors import APIError
from pyasic.miners.base import BaseMiner
from pyasic.miners.backends import BOSMiner
class BOSMinerOld(BaseMiner):
class BOSMinerOld(BOSMiner):
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
super().__init__(ip)
self.ip = ipaddress.ip_address(ip)
self.api = BOSMinerAPI(ip, api_ver)
self.api_type = "BOSMiner"
self.uname = "root"
self.pwd = "admin"
super().__init__(ip, api_ver)
async def send_ssh_command(self, cmd: str) -> Optional[str]:
result = None
@@ -103,80 +95,59 @@ class BOSMinerOld(BaseMiner):
### DATA GATHERING FUNCTIONS (get_{some_data}) ###
##################################################
async def get_mac(self) -> Optional[str]:
async def get_mac(self, *args, **kwargs) -> Optional[str]:
return None
async def get_model(self) -> str:
async def get_model(self, *args, **kwargs) -> str:
return "S9"
async def get_version(self) -> Tuple[Optional[str], Optional[str]]:
async def get_version(self, *args, **kwargs) -> Tuple[Optional[str], Optional[str]]:
return None, None
async def get_hostname(self) -> Optional[str]:
async def get_hostname(self, *args, **kwargs) -> Optional[str]:
return None
async def get_hashrate(self) -> Optional[float]:
async def get_hashrate(self, *args, **kwargs) -> Optional[float]:
return None
async def get_hashboards(self) -> List[HashBoard]:
async def get_hashboards(self, *args, **kwargs) -> List[HashBoard]:
return []
async def get_env_temp(self) -> Optional[float]:
async def get_env_temp(self, *args, **kwargs) -> Optional[float]:
return None
async def get_wattage(self) -> Optional[int]:
async def get_wattage(self, *args, **kwargs) -> Optional[int]:
return None
async def get_wattage_limit(self) -> Optional[int]:
async def get_wattage_limit(self, *args, **kwargs) -> Optional[int]:
return None
async def get_fans(
self,
*args,
**kwargs,
) -> List[Fan]:
return [Fan(), Fan(), Fan(), Fan()]
async def get_fan_psu(self) -> Optional[int]:
async def get_fan_psu(self, *args, **kwargs) -> Optional[int]:
return None
async def get_api_ver(self) -> Optional[str]:
async def get_api_ver(self, *args, **kwargs) -> Optional[str]:
return None
async def get_fw_ver(self) -> Optional[str]:
async def get_fw_ver(self, *args, **kwargs) -> Optional[str]:
return None
async def get_pools(self, api_pools: dict = None) -> List[dict]:
groups = []
if not api_pools:
try:
api_pools = await self.api.pools()
except APIError:
pass
if api_pools:
try:
pools = {}
for i, pool in enumerate(api_pools["POOLS"]):
pools[f"pool_{i + 1}_url"] = (
pool["URL"]
.replace("stratum+tcp://", "")
.replace("stratum2+tcp://", "")
)
pools[f"pool_{i + 1}_user"] = pool["User"]
pools["quota"] = pool["Quota"] if pool.get("Quota") else "0"
groups.append(pools)
except KeyError:
pass
return groups
async def get_errors(self) -> List[MinerErrorData]:
async def get_pools(self, *args, **kwargs) -> List[dict]:
return []
async def get_fault_light(self) -> bool:
async def get_errors(self, *args, **kwargs) -> List[MinerErrorData]:
return []
async def get_fault_light(self, *args, **kwargs) -> bool:
return False
async def get_nominal_hashrate(self) -> Optional[float]:
async def get_nominal_hashrate(self, *args, **kwargs) -> Optional[float]:
return None
async def get_data(self, allow_warning: bool = False, **kwargs) -> MinerData:

View File

@@ -14,7 +14,6 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
import ipaddress
import logging
import warnings
from collections import namedtuple
@@ -27,13 +26,85 @@ from pyasic.data.error_codes import MinerErrorData, WhatsminerError
from pyasic.errors import APIError
from pyasic.miners.base import BaseMiner
BTMINER_DATA_LOC = {
"mac": {
"cmd": "get_mac",
"kwargs": {
"api_summary": {"api": "summary"},
"api_get_miner_info": {"api": "get_miner_info"},
},
},
"model": {"cmd": "get_model", "kwargs": {}},
"api_ver": {
"cmd": "get_api_ver",
"kwargs": {"api_get_version": {"api": "get_version"}},
},
"fw_ver": {
"cmd": "get_fw_ver",
"kwargs": {
"api_get_version": {"api": "get_version"},
"api_summary": {"api": "summary"},
},
},
"hostname": {
"cmd": "get_hostname",
"kwargs": {"api_get_miner_info": {"api": "get_miner_info"}},
},
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
"nominal_hashrate": {
"cmd": "get_nominal_hashrate",
"kwargs": {"api_summary": {"api": "summary"}},
},
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_devs": {"api": "devs"}}},
"env_temp": {"cmd": "get_env_temp", "kwargs": {"api_summary": {"api": "summary"}}},
"wattage": {"cmd": "get_wattage", "kwargs": {"api_summary": {"api": "summary"}}},
"wattage_limit": {
"cmd": "get_wattage_limit",
"kwargs": {"api_summary": {"api": "summary"}},
},
"fans": {
"cmd": "get_fans",
"kwargs": {
"api_summary": {"api": "summary"},
"api_get_psu": {"api": "get_psu"},
},
},
"fan_psu": {
"cmd": "get_fan_psu",
"kwargs": {
"api_summary": {"api": "summary"},
"api_get_psu": {"api": "get_psu"},
},
},
"errors": {
"cmd": "get_errors",
"kwargs": {
"api_summary": {"api": "summary"},
"api_get_error_code": {"api": "get_error_code"},
},
},
"fault_light": {
"cmd": "get_fault_light",
"kwargs": {"api_get_miner_info": {"api": "get_miner_info"}},
},
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
}
class BTMiner(BaseMiner):
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
super().__init__(ip)
self.ip = ipaddress.ip_address(ip)
# interfaces
self.api = BTMinerAPI(ip, api_ver)
# static data
self.api_type = "BTMiner"
# data gathering locations
self.data_locations = BTMINER_DATA_LOC
# autotuning/shutdown support
self.supports_shutdown = True
# data storage
self.api_ver = api_ver
async def _reset_api_pwd_to_admin(self, pwd: str):
@@ -203,28 +274,6 @@ class BTMiner(BaseMiner):
except (KeyError, IndexError):
pass
async def get_model(self, api_devdetails: dict = None) -> Optional[str]:
if self.model:
logging.debug(f"Found model for {self.ip}: {self.model}")
return self.model
if not api_devdetails:
try:
api_devdetails = await self.api.devdetails()
except APIError:
pass
if api_devdetails:
try:
self.model = api_devdetails["DEVDETAILS"][0]["Model"].split("V")[0]
logging.debug(f"Found model for {self.ip}: {self.model}")
return self.model
except (TypeError, IndexError, KeyError):
pass
logging.warning(f"Failed to get model for miner: {self}")
return None
async def get_version(
self, api_get_version: dict = None, api_summary: dict = None
) -> Tuple[Optional[str], Optional[str]]:
@@ -302,9 +351,7 @@ class BTMiner(BaseMiner):
return self.fw_ver
async def get_hostname(self, api_get_miner_info: dict = None) -> Optional[str]:
if self.hostname:
return self.hostname
hostname = None
if not api_get_miner_info:
try:
api_get_miner_info = await self.api.get_miner_info()
@@ -313,11 +360,11 @@ class BTMiner(BaseMiner):
if api_get_miner_info:
try:
self.hostname = api_get_miner_info["Msg"]["hostname"]
hostname = api_get_miner_info["Msg"]["hostname"]
except KeyError:
return None
return self.hostname
return hostname
async def get_hashrate(self, api_summary: dict = None) -> Optional[float]:
# get hr from API

View File

@@ -14,7 +14,6 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
import ipaddress
import logging
from collections import namedtuple
from typing import List, Optional, Tuple
@@ -28,17 +27,42 @@ from pyasic.data.error_codes import MinerErrorData
from pyasic.errors import APIError
from pyasic.miners.base import BaseMiner
CGMINER_DATA_LOC = {
"mac": {"cmd": "get_mac", "kwargs": {}},
"model": {"cmd": "get_model", "kwargs": {}},
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"api_version": {"api": "version"}}},
"hostname": {"cmd": "get_hostname", "kwargs": {}},
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
"nominal_hashrate": {
"cmd": "get_nominal_hashrate",
"kwargs": {"api_stats": {"api": "stats"}},
},
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
"wattage": {"cmd": "get_wattage", "kwargs": {}},
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
"errors": {"cmd": "get_errors", "kwargs": {}},
"fault_light": {"cmd": "get_fault_light", "kwargs": {}},
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
}
class CGMiner(BaseMiner):
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
super().__init__(ip)
self.ip = ipaddress.ip_address(ip)
# interfaces
self.api = CGMinerAPI(ip, api_ver)
self.api_ver = api_ver
# static data
self.api_type = "CGMiner"
self.uname = "root"
self.pwd = "admin"
self.config = None
# data gathering locations
self.data_locations = CGMINER_DATA_LOC
# data storage
self.api_ver = api_ver
async def send_ssh_command(self, cmd: str) -> Optional[str]:
result = None
@@ -69,7 +93,7 @@ class CGMiner(BaseMiner):
return result
async def restart_backend(self) -> bool:
"""Restart cgminer hashing process. Wraps [`restart_cgminer`][pyasic.miners._backends.cgminer.CGMiner.restart_cgminer] to standardize."""
"""Restart cgminer hashing process. Wraps [`restart_cgminer`][pyasic.miners.backends.cgminer.CGMiner.restart_cgminer] to standardize."""
return await self.restart_cgminer()
async def restart_cgminer(self) -> bool:
@@ -154,30 +178,6 @@ class CGMiner(BaseMiner):
async def get_mac(self) -> Optional[str]:
return None
async def get_model(self, api_devdetails: dict = None) -> Optional[str]:
if self.model:
logging.debug(f"Found model for {self.ip}: {self.model}")
return self.model
if not api_devdetails:
try:
api_devdetails = await self.api.devdetails()
except APIError:
pass
if api_devdetails:
try:
self.model = api_devdetails["DEVDETAILS"][0]["Model"].replace(
"Antminer ", ""
)
logging.debug(f"Found model for {self.ip}: {self.model}")
return self.model
except (TypeError, IndexError, KeyError):
pass
logging.warning(f"Failed to get model for miner: {self}")
return None
async def get_version(
self, api_version: dict = None
) -> Tuple[Optional[str], Optional[str]]:
@@ -229,8 +229,7 @@ class CGMiner(BaseMiner):
except (asyncssh.Error, OSError):
return None
if hn:
self.hostname = hn
return self.hostname
return hn
async def get_hashrate(self, api_summary: dict = None) -> Optional[float]:
# get hr from API

View File

@@ -22,13 +22,37 @@ from pyasic.config import MinerConfig
from pyasic.data import Fan, HashBoard
from pyasic.data.error_codes import MinerErrorData
from pyasic.errors import APIError
from pyasic.miners.btc._backends import CGMiner
from pyasic.miners.backends import CGMiner
AVALON_DATA_LOC = {
"mac": {"cmd": "get_mac", "kwargs": {"api_version": {"api": "version"}}},
"model": {"cmd": "get_model", "kwargs": {}},
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"api_version": {"api": "version"}}},
"hostname": {"cmd": "get_hostname", "kwargs": {"mac": {"web": "mac"}}},
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
"nominal_hashrate": {
"cmd": "get_nominal_hashrate",
"kwargs": {"api_stats": {"api": "stats"}},
},
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
"wattage": {"cmd": "get_wattage", "kwargs": {}},
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
"errors": {"cmd": "get_errors", "kwargs": {}},
"fault_light": {"cmd": "get_fault_light", "kwargs": {}},
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
}
class CGMinerAvalon(CGMiner):
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
super().__init__(ip, api_ver)
self.ip = ip
# data gathering locations
self.data_locations = AVALON_DATA_LOC
async def fault_light_on(self) -> bool:
try:

View File

@@ -14,15 +14,16 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
import ipaddress
from typing import Optional
from pyasic.miners.btc._backends import BMMiner
from pyasic.miners.backends import BMMiner
class Hiveon(BMMiner):
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
super().__init__(ip, api_ver)
self.ip = ipaddress.ip_address(ip)
# static data
self.api_type = "Hiveon"
self.uname = "root"
self.pwd = "admin"
async def get_model(self) -> Optional[str]:
return self.model + " (Hiveon)"

View File

@@ -18,35 +18,48 @@ import logging
from typing import Optional
from pyasic.errors import APIError
from pyasic.miners.btc._backends.bmminer import BMMiner
from pyasic.miners.backends.bmminer import BMMiner
from pyasic.web.vnish import VNishWebAPI
VNISH_DATA_LOC = {
"mac": {"cmd": "get_mac", "kwargs": {"web_summary": {"web": "summary"}}},
"model": {"cmd": "get_model", "kwargs": {}},
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"web_summary": {"web": "summary"}}},
"hostname": {"cmd": "get_hostname", "kwargs": {"web_summary": {"web": "summary"}}},
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
"nominal_hashrate": {
"cmd": "get_nominal_hashrate",
"kwargs": {"api_stats": {"api": "stats"}},
},
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
"wattage": {"cmd": "get_wattage", "kwargs": {"web_summary": {"web": "summary"}}},
"wattage_limit": {
"cmd": "get_wattage_limit",
"kwargs": {"web_settings": {"web": "settings"}},
},
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
"errors": {"cmd": "get_errors", "kwargs": {}},
"fault_light": {"cmd": "get_fault_light", "kwargs": {}},
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
}
class VNish(BMMiner):
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
super().__init__(ip, api_ver)
self.api_type = "VNish"
# interfaces
self.web = VNishWebAPI(ip)
async def get_model(self, api_stats: dict = None) -> Optional[str]:
# check if model is cached
if self.model:
logging.debug(f"Found model for {self.ip}: {self.model} (VNish)")
return self.model + " (VNish)"
# static data
self.api_type = "VNish"
# data gathering locations
self.data_locations = VNISH_DATA_LOC
if not api_stats:
try:
api_stats = await self.api.stats()
except APIError:
pass
if api_stats:
try:
m_type = api_stats["STATS"][0]["Type"]
self.model = m_type.split(" ")[1]
return self.model
except (KeyError, IndexError):
pass
async def get_model(self) -> Optional[str]:
return self.model + " (VNISH)"
async def restart_backend(self) -> bool:
data = await self.web.restart_vnish()
@@ -138,6 +151,8 @@ class VNish(BMMiner):
if web_settings:
try:
wattage_limit = web_settings["miner"]["overclock"]["preset"]
if wattage_limit == "disabled":
return None
return int(wattage_limit)
except (KeyError, TypeError):
pass

View File

@@ -0,0 +1,32 @@
# ------------------------------------------------------------------------------
# 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.btminer import BTMiner
class M5X(BTMiner):
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.supports_autotuning = True
class M3X(BTMiner):
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.supports_autotuning = True
class M2X(BTMiner):
pass

View File

@@ -29,23 +29,32 @@ from pyasic.errors import APIError
class BaseMiner(ABC):
def __init__(self, *args, **kwargs) -> None:
self.ip = None
def __init__(self, ip: str, *args, **kwargs) -> None:
# interfaces
self.api = None
self.web = None
self.uname = None
self.pwd = None
# static data
self.ip = ip
self.api_type = None
self.api_ver = None
self.fw_ver = None
self.model = None
# type
self.make = None
self.light = None
self.hostname = None
self.model = None
# physical attributes
self.ideal_hashboards = 3
self.nominal_chips = 1
self.fan_count = 2
# data gathering locations
self.data_locations = None
# autotuning/shutdown support
self.supports_autotuning = False
self.supports_shutdown = False
# data storage
self.api_ver = None
self.fw_ver = None
self.light = None
self.config = None
self.ideal_hashboards = 3
def __new__(cls, *args, **kwargs):
if cls is BaseMiner:
@@ -70,8 +79,8 @@ class BaseMiner(ABC):
conn = await asyncssh.connect(
str(self.ip),
known_hosts=None,
username=self.uname,
password=self.pwd,
username="root",
password="root",
server_host_key_algs=["ssh-rsa"],
)
return conn
@@ -195,14 +204,13 @@ class BaseMiner(ABC):
"""
pass
@abstractmethod
async def get_model(self) -> Optional[str]:
"""Get the model of the miner and return it as a string.
Returns:
A string representing the model of the miner.
"""
pass
return self.model
@abstractmethod
async def get_api_ver(self, *args, **kwargs) -> Optional[str]:
@@ -360,76 +368,75 @@ class BaseMiner(ABC):
"fault_light",
"pools",
]
api_params = []
web_params = []
gql = False
api_multicommand = []
web_multicommand = []
for data_name in data_to_get:
function = getattr(self, "get_" + data_name)
sig = inspect.signature(function)
for item in sig.parameters:
if item.startswith("api_"):
command = item.replace("api_", "")
api_params.append(command)
elif item.startswith("graphql_"):
gql = True
elif item.startswith("web_"):
web_params.append(item.replace("web_", ""))
api_params = list(set(api_params))
web_params = list(set(web_params))
miner_data = {}
command_data = await self.api.multicommand(
*api_params, allow_warning=allow_warning
)
if gql:
try:
gql_data = await self.send_graphql_query( # noqa: bosminer only anyway
"{bos {hostname}, bosminer{config{... on BosminerConfig{groups{pools{url, user}, strategy{... on QuotaStrategy {quota}}}}}, info{fans{name, rpm}, workSolver{realHashrate{mhs1M}, temperatures{degreesC}, power{limitW, approxConsumptionW}, childSolvers{name, realHashrate{mhs1M}, hwDetails{chips}, tuner{statusMessages}, temperatures{degreesC}}}}}}"
)
except APIError:
# hostname hates me
try:
gql_data = await self.send_graphql_query( # noqa: bosminer only anyway
"{bosminer{config{... on BosminerConfig{groups{pools{url, user}, strategy{... on QuotaStrategy {quota}}}}}, info{fans{name, rpm}, workSolver{realHashrate{mhs1M}, temperatures{degreesC}, power{limitW, approxConsumptionW}, childSolvers{name, realHashrate{mhs1M}, hwDetails{chips}, tuner{statusMessages}, temperatures{degreesC}}}}}}"
)
except APIError:
# AGAIN???
gql_data = None
fn_args = self.data_locations[data_name]["kwargs"]
for arg_name in fn_args:
if fn_args[arg_name].get("api"):
api_multicommand.append(fn_args[arg_name]["api"])
if fn_args[arg_name].get("web"):
web_multicommand.append(fn_args[arg_name]["web"])
except KeyError as e:
print(e, data_name)
continue
api_multicommand = list(set(api_multicommand))
_web_multicommand = web_multicommand
for item in web_multicommand:
if item not in _web_multicommand:
_web_multicommand.append(item)
web_multicommand = _web_multicommand
if len(api_multicommand) > 0:
api_command_data = await self.api.multicommand(
*api_multicommand, allow_warning=allow_warning
)
else:
api_command_data = {}
if len(web_multicommand) > 0:
web_command_data = await self.web.multicommand(
*web_multicommand, allow_warning=allow_warning
)
else:
web_command_data = {}
miner_data = {}
web_data = {}
for command in web_params:
try:
cmd_func = getattr(self.web, command)
data = await cmd_func() # noqa: web only anyway
except (LookupError, APIError):
pass
else:
web_data[command] = data
for data_name in data_to_get:
function = getattr(self, "get_" + data_name)
sig = inspect.signature(function)
kwargs = {}
for arg_name in sig.parameters:
if arg_name.startswith("api_"):
try:
kwargs[arg_name] = command_data[arg_name.replace("api_", "")][0]
except (KeyError, IndexError):
kwargs[arg_name] = None
elif arg_name.startswith("graphql_"):
kwargs[
arg_name
] = gql_data # noqa: variable is not referenced before assignment
elif arg_name.startswith("web_"):
try:
kwargs[arg_name] = web_data[arg_name.replace("web_", "")]
except (KeyError, IndexError):
kwargs[arg_name] = None
try:
fn_args = self.data_locations[data_name]["kwargs"]
args_to_send = {k: None for k in fn_args}
for arg_name in fn_args:
if fn_args[arg_name].get("api"):
if api_command_data.get("multicommand"):
args_to_send[arg_name] = api_command_data[
fn_args[arg_name]["api"]
][0]
else:
args_to_send[arg_name] = api_command_data
if fn_args[arg_name].get("web"):
if web_command_data.get("multicommand"):
args_to_send[arg_name] = web_command_data[
fn_args[arg_name]["web"]
]
else:
if not web_command_data == {"multicommand": False}:
args_to_send[arg_name] = web_command_data
except (KeyError, IndexError) as e:
continue
function = getattr(self, self.data_locations[data_name]["cmd"])
if not data_name == "pools":
miner_data[data_name] = await function(**kwargs)
miner_data[data_name] = await function(**args_to_send)
else:
pools_data = await function(**kwargs)
pools_data = await function(**args_to_send)
if pools_data:
miner_data["pool_1_url"] = pools_data[0]["pool_1_url"]
miner_data["pool_1_user"] = pools_data[0]["pool_1_user"]
try:
miner_data["pool_1_url"] = pools_data[0]["pool_1_url"]
miner_data["pool_1_user"] = pools_data[0]["pool_1_user"]
except KeyError:
pass
if len(pools_data) > 1:
miner_data["pool_2_url"] = pools_data[1]["pool_2_url"]
miner_data["pool_2_user"] = pools_data[1]["pool_2_user"]

View File

@@ -1,194 +0,0 @@
# ------------------------------------------------------------------------------
# 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. -
# ------------------------------------------------------------------------------
import asyncio
from typing import List, Optional, Union
from pyasic.API import APIError
from pyasic.config import MinerConfig, X19PowerMode
from pyasic.data.error_codes import MinerErrorData, X19Error
from pyasic.miners.btc._backends import BMMiner # noqa - Ignore access to _module
from pyasic.web.X19 import X19WebAPI
class X19(BMMiner):
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
super().__init__(ip, api_ver=api_ver)
self.ip = ip
self.web = X19WebAPI(ip)
async def get_config(self) -> MinerConfig:
data = await self.web.get_miner_conf()
if data:
self.config = MinerConfig().from_raw(data)
return self.config
async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:
self.config = config
conf = config.as_x19(user_suffix=user_suffix)
await self.web.set_miner_conf(conf)
for i in range(7):
data = await self.get_config()
if data.as_x19() == conf:
break
await asyncio.sleep(1)
async def fault_light_on(self) -> bool:
data = await self.web.blink(blink=True)
if data:
if data.get("code") == "B000":
self.light = True
return self.light
async def fault_light_off(self) -> bool:
data = await self.web.blink(blink=False)
if data:
if data.get("code") == "B100":
self.light = True
return self.light
async def reboot(self) -> bool:
data = await self.web.reboot()
if data:
return True
return False
async def stop_mining(self) -> bool:
cfg = await self.get_config()
cfg.miner_mode = X19PowerMode.Sleep
await self.send_config(cfg)
return True
async def resume_mining(self) -> bool:
cfg = await self.get_config()
cfg.miner_mode = X19PowerMode.Normal
await self.send_config(cfg)
return True
async def get_hostname(self) -> Union[str, None]:
try:
data = await self.web.get_system_info()
if data:
return data["hostname"]
except KeyError:
pass
async def get_mac(self) -> Union[str, None]:
try:
data = await self.web.get_system_info()
if data:
return data["macaddr"]
except KeyError:
pass
try:
data = await self.web.get_network_info()
if data:
return data["macaddr"]
except KeyError:
pass
async def get_errors(self) -> List[MinerErrorData]:
errors = []
data = await self.web.summary()
if data:
try:
for item in data["SUMMARY"][0]["status"]:
try:
if not item["status"] == "s":
errors.append(X19Error(item["msg"]))
except KeyError:
continue
except (KeyError, IndexError):
pass
return errors
async def get_fault_light(self) -> bool:
if self.light:
return self.light
try:
data = await self.web.get_blink_status()
if data:
self.light = data["blink"]
except KeyError:
pass
return self.light
async def get_nominal_hashrate(self, api_stats: dict = None) -> Optional[float]:
if not api_stats:
try:
api_stats = await self.api.stats()
except APIError:
pass
if api_stats:
try:
ideal_rate = api_stats["STATS"][1]["total_rateideal"]
try:
rate_unit = api_stats["STATS"][1]["rate_unit"]
except KeyError:
rate_unit = "GH"
if rate_unit == "GH":
return round(ideal_rate / 1000, 2)
if rate_unit == "MH":
return round(ideal_rate / 1000000, 2)
else:
return round(ideal_rate, 2)
except (KeyError, IndexError):
pass
async def set_static_ip(
self,
ip: str,
dns: str,
gateway: str,
subnet_mask: str = "255.255.255.0",
hostname: str = None,
):
if not hostname:
hostname = await self.get_hostname()
await self.web.set_network_conf(
ip=ip,
dns=dns,
gateway=gateway,
subnet_mask=subnet_mask,
hostname=hostname,
protocol=2,
)
async def set_dhcp(self, hostname: str = None):
if not hostname:
hostname = await self.get_hostname()
await self.web.set_network_conf(
ip="", dns="", gateway="", subnet_mask="", hostname=hostname, protocol=1
)
async def set_hostname(self, hostname: str):
cfg = await self.web.get_network_info()
dns = cfg["conf_dnsservers"]
gateway = cfg["conf_gateway"]
ip = cfg["conf_ipaddress"]
subnet_mask = cfg["conf_netmask"]
protocol = 1 if cfg["conf_nettype"] == "DHCP" else 2
await self.web.set_network_conf(
ip=ip,
dns=dns,
gateway=gateway,
subnet_mask=subnet_mask,
hostname=hostname,
protocol=protocol,
)

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import AntMiner
class S17(AntMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "S17"
self.nominal_chips = 48

View File

@@ -18,9 +18,8 @@ from pyasic.miners.makes import AntMiner
class S17Plus(AntMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
self.ip = ip
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.model = "S17+"
self.nominal_chips = 65
self.fan_count = 4

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import AntMiner
class S17Pro(AntMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "S17 Pro"
self.nominal_chips = 48

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import AntMiner
class S17e(AntMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "S17e"
self.nominal_chips = 135

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import AntMiner
class T17(AntMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "T17"
self.nominal_chips = 30

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import AntMiner
class T17Plus(AntMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "T17+"
self.nominal_chips = 44

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import AntMiner
class T17e(AntMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "T17e"
self.nominal_chips = 78

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import AntMiner
class S19(AntMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "S19"
self.nominal_chips = 76

View File

@@ -0,0 +1,26 @@
# ------------------------------------------------------------------------------
# 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.makes import AntMiner
class S19L(AntMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "S19L"
self.nominal_chips = 76
self.fan_count = 4

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import AntMiner
class S19Pro(AntMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "S19 Pro"
self.nominal_chips = 114

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import AntMiner
class S19XP(AntMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "S19 XP"
self.nominal_chips = 110

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import AntMiner
class S19a(AntMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "S19a"
self.nominal_chips = 72

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import AntMiner
class S19aPro(AntMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "S19a Pro"
self.nominal_chips = 100

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import AntMiner
class S19j(AntMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "S19j"
self.nominal_chips = 114

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import AntMiner
class S19jPro(AntMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "S19j Pro"
self.nominal_chips = 126

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import AntMiner
class T19(AntMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "T19"
self.nominal_chips = 76

View File

@@ -21,4 +21,5 @@ from .S19a import S19a
from .S19a_Pro import S19aPro
from .S19j import S19j
from .S19j_Pro import S19jPro
from .S19L import S19L
from .T19 import T19

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import AntMiner
class S9(AntMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "S9"
self.nominal_chips = 63

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import AntMiner
class S9i(AntMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "S9i"
self.nominal_chips = 63

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import AntMiner
class T9(AntMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "T9"
self.nominal_chips = 54

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import AvalonMiner
class Avalon1026(AvalonMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "Avalon 1026"
self.nominal_chips = 80

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import AvalonMiner
class Avalon1047(AvalonMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "Avalon 1047"
self.nominal_chips = 80

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import AvalonMiner
class Avalon1066(AvalonMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "Avalon 1066"
self.nominal_chips = 114

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import AvalonMiner
class Avalon721(AvalonMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "Avalon 721"
self.ideal_hashboards = 4

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import AvalonMiner
class Avalon741(AvalonMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "Avalon 741"
self.ideal_hashboards = 4

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import AvalonMiner
class Avalon761(AvalonMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "Avalon 761"
self.ideal_hashboards = 4

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import AvalonMiner
class Avalon821(AvalonMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "Avalon 821"
self.ideal_hashboards = 4

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import AvalonMiner
class Avalon841(AvalonMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "Avalon 841"
self.ideal_hashboards = 4

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import AvalonMiner
class Avalon851(AvalonMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "Avalon 851"
self.ideal_hashboards = 4

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import AvalonMiner
class Avalon921(AvalonMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "Avalon 921"
self.ideal_hashboards = 4

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import InnosiliconMiner
class InnosiliconT3HPlus(InnosiliconMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str) -> None:
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
super().__init__(ip, api_ver)
self.ip = ip
self.model = "T3H+"
self.nominal_chips = 114

View File

@@ -18,8 +18,8 @@ from pyasic.miners.makes import WhatsMiner
class M20V10(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M20 V10"
self.nominal_chips = 70

View File

@@ -20,8 +20,8 @@ from pyasic.miners.makes import WhatsMiner
class M20SV10(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M20S V10"
self.nominal_chips = 105
@@ -29,8 +29,8 @@ class M20SV10(WhatsMiner): # noqa - ignore ABC method implementation
class M20SV20(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M20S V20"
self.nominal_chips = 111
@@ -38,8 +38,8 @@ class M20SV20(WhatsMiner): # noqa - ignore ABC method implementation
class M20SV30(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M20S V30"
self.nominal_chips = 0

View File

@@ -20,8 +20,8 @@ from pyasic.miners.makes import WhatsMiner
class M20SPlusV30(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M20S+ V30"
self.nominal_chips = 0

View File

@@ -20,8 +20,8 @@ from pyasic.miners.makes import WhatsMiner
class M21V10(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M21 V10"
self.nominal_chips = 0

View File

@@ -20,8 +20,8 @@ from pyasic.miners.makes import WhatsMiner
class M21SV20(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M21S V20"
self.nominal_chips = 66
@@ -29,8 +29,8 @@ class M21SV20(WhatsMiner): # noqa - ignore ABC method implementation
class M21SV60(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M21S V60"
self.nominal_chips = 105
@@ -38,8 +38,8 @@ class M21SV60(WhatsMiner): # noqa - ignore ABC method implementation
class M21SV70(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M21S V70"
self.nominal_chips = 0

View File

@@ -20,8 +20,8 @@ from pyasic.miners.makes import WhatsMiner
class M21SPlusV20(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M21S+ V20"
self.nominal_chips = 0

View File

@@ -20,8 +20,8 @@ from pyasic.miners.makes import WhatsMiner
class M29V10(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M29 V10"
self.nominal_chips = 0

View File

@@ -20,8 +20,8 @@ from pyasic.miners.makes import WhatsMiner
class M30V10(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30 V10"
self.nominal_chips = 0
@@ -32,8 +32,8 @@ class M30V10(WhatsMiner): # noqa - ignore ABC method implementation
class M30V20(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30 V20"
self.nominal_chips = 0

View File

@@ -20,8 +20,8 @@ from pyasic.miners.makes import WhatsMiner
class M30SV10(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S V10"
self.nominal_chips = 0
@@ -32,8 +32,8 @@ class M30SV10(WhatsMiner): # noqa - ignore ABC method implementation
class M30SV20(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S V20"
self.nominal_chips = 0
@@ -44,8 +44,8 @@ class M30SV20(WhatsMiner): # noqa - ignore ABC method implementation
class M30SV30(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S V30"
self.nominal_chips = 0
@@ -56,8 +56,8 @@ class M30SV30(WhatsMiner): # noqa - ignore ABC method implementation
class M30SV40(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S V40"
self.nominal_chips = 0
@@ -68,8 +68,8 @@ class M30SV40(WhatsMiner): # noqa - ignore ABC method implementation
class M30SV50(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S V50"
self.nominal_chips = 156
@@ -77,8 +77,8 @@ class M30SV50(WhatsMiner): # noqa - ignore ABC method implementation
class M30SV60(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S V60"
self.nominal_chips = 0
@@ -89,8 +89,8 @@ class M30SV60(WhatsMiner): # noqa - ignore ABC method implementation
class M30SV70(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S V70"
self.nominal_chips = 0
@@ -101,8 +101,8 @@ class M30SV70(WhatsMiner): # noqa - ignore ABC method implementation
class M30SV80(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S V80"
self.nominal_chips = 0
@@ -113,8 +113,8 @@ class M30SV80(WhatsMiner): # noqa - ignore ABC method implementation
class M30SVE10(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S VE10"
self.nominal_chips = 105
@@ -122,8 +122,8 @@ class M30SVE10(WhatsMiner): # noqa - ignore ABC method implementation
class M30SVE20(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S VE20"
self.nominal_chips = 111
@@ -131,8 +131,8 @@ class M30SVE20(WhatsMiner): # noqa - ignore ABC method implementation
class M30SVE30(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S VE30"
self.nominal_chips = 0
@@ -143,8 +143,8 @@ class M30SVE30(WhatsMiner): # noqa - ignore ABC method implementation
class M30SVE40(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S VE40"
self.nominal_chips = 0
@@ -155,8 +155,8 @@ class M30SVE40(WhatsMiner): # noqa - ignore ABC method implementation
class M30SVE50(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S VE50"
self.nominal_chips = 0
@@ -167,8 +167,8 @@ class M30SVE50(WhatsMiner): # noqa - ignore ABC method implementation
class M30SVE60(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S VE60"
self.nominal_chips = 0
@@ -179,8 +179,8 @@ class M30SVE60(WhatsMiner): # noqa - ignore ABC method implementation
class M30SVE70(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S VE70"
self.nominal_chips = 0
@@ -191,8 +191,8 @@ class M30SVE70(WhatsMiner): # noqa - ignore ABC method implementation
class M30SVF10(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S VF10"
self.nominal_chips = 0
@@ -203,8 +203,8 @@ class M30SVF10(WhatsMiner): # noqa - ignore ABC method implementation
class M30SVF20(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S VF20"
self.nominal_chips = 0
@@ -215,8 +215,8 @@ class M30SVF20(WhatsMiner): # noqa - ignore ABC method implementation
class M30SVF30(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S VF30"
self.nominal_chips = 0
@@ -227,8 +227,8 @@ class M30SVF30(WhatsMiner): # noqa - ignore ABC method implementation
class M30SVG10(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S VG10"
self.nominal_chips = 66
@@ -236,8 +236,8 @@ class M30SVG10(WhatsMiner): # noqa - ignore ABC method implementation
class M30SVG20(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S VG20"
self.nominal_chips = 70
@@ -245,8 +245,8 @@ class M30SVG20(WhatsMiner): # noqa - ignore ABC method implementation
class M30SVG30(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S VG30"
self.nominal_chips = 0
@@ -257,8 +257,8 @@ class M30SVG30(WhatsMiner): # noqa - ignore ABC method implementation
class M30SVG40(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S VG40"
self.nominal_chips = 0
@@ -269,8 +269,8 @@ class M30SVG40(WhatsMiner): # noqa - ignore ABC method implementation
class M30SVH10(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S VH10"
self.nominal_chips = 0
@@ -281,8 +281,8 @@ class M30SVH10(WhatsMiner): # noqa - ignore ABC method implementation
class M30SVH20(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S VH20"
self.nominal_chips = 0
@@ -293,8 +293,8 @@ class M30SVH20(WhatsMiner): # noqa - ignore ABC method implementation
class M30SVH30(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S VH30"
self.nominal_chips = 0
@@ -305,8 +305,8 @@ class M30SVH30(WhatsMiner): # noqa - ignore ABC method implementation
class M30SVH40(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S VH40"
self.nominal_chips = 0
@@ -317,8 +317,8 @@ class M30SVH40(WhatsMiner): # noqa - ignore ABC method implementation
class M30SVH50(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S VH50"
self.nominal_chips = 0
@@ -329,8 +329,8 @@ class M30SVH50(WhatsMiner): # noqa - ignore ABC method implementation
class M30SVH60(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S VH60"
self.nominal_chips = 0
@@ -341,8 +341,8 @@ class M30SVH60(WhatsMiner): # noqa - ignore ABC method implementation
class M30SVI20(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S VI20"
self.nominal_chips = 0

View File

@@ -20,8 +20,8 @@ from pyasic.miners.makes import WhatsMiner
class M30SPlusV10(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ V10"
self.nominal_chips = 0
@@ -32,8 +32,8 @@ class M30SPlusV10(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusV20(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ V20"
self.nominal_chips = 0
@@ -44,8 +44,8 @@ class M30SPlusV20(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusV30(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ V30"
self.nominal_chips = 0
@@ -56,8 +56,8 @@ class M30SPlusV30(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusV40(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ V40"
self.nominal_chips = 0
@@ -68,8 +68,8 @@ class M30SPlusV40(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusV50(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ V50"
self.nominal_chips = 0
@@ -80,8 +80,8 @@ class M30SPlusV50(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusV60(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ V60"
self.nominal_chips = 0
@@ -92,8 +92,8 @@ class M30SPlusV60(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusV70(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ V70"
self.nominal_chips = 0
@@ -104,8 +104,8 @@ class M30SPlusV70(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusV80(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ V80"
self.nominal_chips = 0
@@ -116,8 +116,8 @@ class M30SPlusV80(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusV90(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ V90"
self.nominal_chips = 0
@@ -128,8 +128,8 @@ class M30SPlusV90(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusV100(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ V100"
self.nominal_chips = 0
@@ -140,8 +140,8 @@ class M30SPlusV100(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusVE30(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ VE30"
self.nominal_chips = 0
@@ -152,8 +152,8 @@ class M30SPlusVE30(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusVE40(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ VE40"
self.nominal_chips = 156
@@ -161,8 +161,8 @@ class M30SPlusVE40(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusVE50(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ VE50"
self.nominal_chips = 0
@@ -173,8 +173,8 @@ class M30SPlusVE50(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusVE60(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ VE60"
self.nominal_chips = 0
@@ -185,8 +185,8 @@ class M30SPlusVE60(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusVE70(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ VE70"
self.nominal_chips = 0
@@ -197,8 +197,8 @@ class M30SPlusVE70(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusVE80(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ VE80"
self.nominal_chips = 0
@@ -209,8 +209,8 @@ class M30SPlusVE80(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusVE90(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ VE90"
self.nominal_chips = 0
@@ -221,8 +221,8 @@ class M30SPlusVE90(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusVE100(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ VE100"
self.nominal_chips = 0
@@ -233,8 +233,8 @@ class M30SPlusVE100(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusVF20(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ VF20"
self.nominal_chips = 111
@@ -242,8 +242,8 @@ class M30SPlusVF20(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusVF30(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ VF30"
self.nominal_chips = 0
@@ -254,8 +254,8 @@ class M30SPlusVF30(WhatsMiner): # noqa - ignore ABC method implementation
class M36SPlusVG30(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M36S+ VG30"
self.nominal_chips = 0
@@ -266,8 +266,8 @@ class M36SPlusVG30(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusVG30(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ VG30"
self.nominal_chips = 0
@@ -278,8 +278,8 @@ class M30SPlusVG30(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusVG40(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ VG40"
self.nominal_chips = 105
@@ -287,8 +287,8 @@ class M30SPlusVG40(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusVG50(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ VG50"
self.nominal_chips = 0
@@ -299,8 +299,8 @@ class M30SPlusVG50(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusVG60(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ VG60"
self.nominal_chips = 86
@@ -308,8 +308,8 @@ class M30SPlusVG60(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusVH10(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ VH10"
self.nominal_chips = 0
@@ -320,8 +320,8 @@ class M30SPlusVH10(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusVH20(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ VH20"
self.nominal_chips = 0
@@ -332,8 +332,8 @@ class M30SPlusVH20(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusVH30(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ VH30"
self.nominal_chips = 70
@@ -341,8 +341,8 @@ class M30SPlusVH30(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusVH40(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ VH40"
self.nominal_chips = 0
@@ -353,8 +353,8 @@ class M30SPlusVH40(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusVH50(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ VH50"
self.nominal_chips = 0
@@ -365,8 +365,8 @@ class M30SPlusVH50(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusVH60(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S+ VH60"
self.nominal_chips = 66

View File

@@ -20,8 +20,8 @@ from pyasic.miners.makes import WhatsMiner
class M30SPlusPlusV10(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S++ V10"
self.nominal_chips = 0
@@ -32,8 +32,8 @@ class M30SPlusPlusV10(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusPlusV20(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S++ V20"
self.nominal_chips = 0
@@ -44,8 +44,8 @@ class M30SPlusPlusV20(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusPlusVE30(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S++ VE30"
self.nominal_chips = 0
@@ -56,8 +56,8 @@ class M30SPlusPlusVE30(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusPlusVE40(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S++ VE40"
self.nominal_chips = 0
@@ -68,8 +68,8 @@ class M30SPlusPlusVE40(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusPlusVE50(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S++ VE50"
self.nominal_chips = 0
@@ -80,8 +80,8 @@ class M30SPlusPlusVE50(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusPlusVF40(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S++ VF40"
self.nominal_chips = 0
@@ -92,8 +92,8 @@ class M30SPlusPlusVF40(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusPlusVG30(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S++ VG30"
self.nominal_chips = 111
@@ -101,8 +101,8 @@ class M30SPlusPlusVG30(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusPlusVG40(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S++ VG40"
self.nominal_chips = 117
@@ -110,8 +110,8 @@ class M30SPlusPlusVG40(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusPlusVG50(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S++ VG50"
self.nominal_chips = 0
@@ -122,8 +122,8 @@ class M30SPlusPlusVG50(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusPlusVH10(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S++ VH10"
self.nominal_chips = 0
@@ -134,8 +134,8 @@ class M30SPlusPlusVH10(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusPlusVH20(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S++ VH20"
self.nominal_chips = 0
@@ -146,8 +146,8 @@ class M30SPlusPlusVH20(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusPlusVH30(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S++ VH30"
self.nominal_chips = 0
@@ -158,8 +158,8 @@ class M30SPlusPlusVH30(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusPlusVH40(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S++ VH40"
self.nominal_chips = 0
@@ -170,8 +170,8 @@ class M30SPlusPlusVH40(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusPlusVH50(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S++ VH50"
self.nominal_chips = 74
@@ -179,8 +179,8 @@ class M30SPlusPlusVH50(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusPlusVH60(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S++ VH60"
self.nominal_chips = 78
@@ -188,8 +188,8 @@ class M30SPlusPlusVH60(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusPlusVH70(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S++ VH70"
self.nominal_chips = 70
@@ -197,8 +197,8 @@ class M30SPlusPlusVH70(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusPlusVH80(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S++ VH80"
self.nominal_chips = 0
@@ -209,8 +209,8 @@ class M30SPlusPlusVH80(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusPlusVH90(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S++ VH90"
self.nominal_chips = 0
@@ -221,20 +221,17 @@ class M30SPlusPlusVH90(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusPlusVH100(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S++ VH100"
self.nominal_chips = 0
warnings.warn(
"Unknown chip count for miner type M30S++ VH100, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
)
self.nominal_chips = 82
self.fan_count = 2
class M30SPlusPlusVJ20(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S++ VJ20"
self.nominal_chips = 0
@@ -245,8 +242,8 @@ class M30SPlusPlusVJ20(WhatsMiner): # noqa - ignore ABC method implementation
class M30SPlusPlusVJ30(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M30S++ VJ30"
self.nominal_chips = 0

View File

@@ -20,8 +20,8 @@ from pyasic.miners.makes import WhatsMiner
class M31V10(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M31 V10"
self.nominal_chips = 0
@@ -32,8 +32,8 @@ class M31V10(WhatsMiner): # noqa - ignore ABC method implementation
class M31V20(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M31 V20"
self.nominal_chips = 0

View File

@@ -20,8 +20,8 @@ from pyasic.miners.makes import WhatsMiner
class M31HV40(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M31H V40"
self.nominal_chips = 0

View File

@@ -20,8 +20,8 @@ from pyasic.miners.makes import WhatsMiner
class M31SV10(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M31S V10"
self.nominal_chips = 105
@@ -29,8 +29,8 @@ class M31SV10(WhatsMiner): # noqa - ignore ABC method implementation
class M31SV20(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M31S V20"
self.nominal_chips = 111
@@ -38,8 +38,8 @@ class M31SV20(WhatsMiner): # noqa - ignore ABC method implementation
class M31SV30(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M31S V30"
self.nominal_chips = 0
@@ -50,8 +50,8 @@ class M31SV30(WhatsMiner): # noqa - ignore ABC method implementation
class M31SV40(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M31S V40"
self.nominal_chips = 0
@@ -62,8 +62,8 @@ class M31SV40(WhatsMiner): # noqa - ignore ABC method implementation
class M31SV50(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M31S V50"
self.nominal_chips = 0
@@ -74,8 +74,8 @@ class M31SV50(WhatsMiner): # noqa - ignore ABC method implementation
class M31SV60(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M31S V60"
self.nominal_chips = 105
@@ -83,8 +83,8 @@ class M31SV60(WhatsMiner): # noqa - ignore ABC method implementation
class M31SV70(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M31S V70"
self.nominal_chips = 111
@@ -92,8 +92,8 @@ class M31SV70(WhatsMiner): # noqa - ignore ABC method implementation
class M31SV80(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M31S V80"
self.nominal_chips = 0
@@ -104,8 +104,8 @@ class M31SV80(WhatsMiner): # noqa - ignore ABC method implementation
class M31SV90(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M31S V90"
self.nominal_chips = 0
@@ -116,8 +116,8 @@ class M31SV90(WhatsMiner): # noqa - ignore ABC method implementation
class M31SVE10(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M31S VE10"
self.nominal_chips = 0
@@ -128,8 +128,8 @@ class M31SVE10(WhatsMiner): # noqa - ignore ABC method implementation
class M31SVE20(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M31S VE20"
self.nominal_chips = 0
@@ -140,8 +140,8 @@ class M31SVE20(WhatsMiner): # noqa - ignore ABC method implementation
class M31SVE30(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M31S VE30"
self.nominal_chips = 0

View File

@@ -20,8 +20,8 @@ from pyasic.miners.makes import WhatsMiner
class M31SEV10(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M31SE V10"
self.nominal_chips = 0
@@ -32,8 +32,8 @@ class M31SEV10(WhatsMiner): # noqa - ignore ABC method implementation
class M31SEV20(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M31SE V20"
self.nominal_chips = 0
@@ -44,8 +44,8 @@ class M31SEV20(WhatsMiner): # noqa - ignore ABC method implementation
class M31SEV30(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str):
super().__init__()
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M31SE V30"
self.nominal_chips = 0

Some files were not shown because too many files have changed in this diff Show More