Compare commits
571 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
61fbc132ed | ||
|
|
3f9f232990 | ||
|
|
29c2398846 | ||
|
|
ecc161820d | ||
|
|
5fec3052f6 | ||
|
|
437ee774ab | ||
|
|
aed9e0e406 | ||
|
|
be96428823 | ||
|
|
446881b237 | ||
|
|
ceab8e55b5 | ||
|
|
e12f85c94d | ||
|
|
0c85f53177 | ||
|
|
0b524f9bd0 | ||
|
|
95db852636 | ||
|
|
93fa02412a | ||
|
|
edb77e9cd8 | ||
|
|
cbf7eeb08d | ||
|
|
d34b35a82d | ||
|
|
5d57f35475 | ||
|
|
c95491ea45 | ||
|
|
e9ec43fac9 | ||
|
|
42bde081c4 | ||
|
|
bfb72aec1b | ||
|
|
b2f36b2f0b | ||
|
|
f75c07401b | ||
|
|
01b96227e0 | ||
|
|
82552390c8 | ||
|
|
b0651e26b8 | ||
|
|
c00802e311 | ||
|
|
d66739e2c9 | ||
|
|
65ed565220 | ||
|
|
db6499800b | ||
|
|
cc97ceee61 | ||
|
|
3fa1cb18d9 | ||
|
|
cb3c50d007 | ||
|
|
2523ef8484 | ||
|
|
01342738b0 | ||
|
|
a9dee4a911 | ||
|
|
883ffe20b4 | ||
|
|
261527a380 | ||
|
|
924b62e0d5 | ||
|
|
76a870c2ed | ||
|
|
309356243b | ||
|
|
e9b4cc9bd6 | ||
|
|
648c54de93 | ||
|
|
e1ce96ab1b | ||
|
|
86860a8dc4 | ||
|
|
5212641f45 | ||
|
|
52432e6043 | ||
|
|
727e484860 | ||
|
|
6c091756d2 | ||
|
|
14533ce4fe | ||
|
|
82d1840039 | ||
|
|
8e6240cdba | ||
|
|
5749e173d1 | ||
|
|
7d682b62ac | ||
|
|
6739a1001f | ||
|
|
56e4a5307f | ||
|
|
88de27c9e7 | ||
|
|
a77113c4db | ||
|
|
c19945bb82 | ||
|
|
1756937d20 | ||
|
|
c7b7fe864b | ||
|
|
e7ebefd1bf | ||
|
|
4677efbc46 | ||
|
|
4b7a1a0495 | ||
|
|
cc4e7da4e5 | ||
|
|
a3d2d7d35e | ||
|
|
d67de98bd0 | ||
|
|
fd1a3e459b | ||
|
|
adcab694b5 | ||
|
|
2bb097272f | ||
|
|
896968dded | ||
|
|
56b8f7c5b3 | ||
|
|
0ed7559aef | ||
|
|
275d87e4fe | ||
|
|
c3ab814d77 | ||
|
|
05a8569205 | ||
|
|
b098cb8136 | ||
|
|
75fe7857e4 | ||
|
|
66797aced1 | ||
|
|
4a71e38078 | ||
|
|
9fb07e4fa3 | ||
|
|
74792771ec | ||
|
|
fa6e8a976d | ||
|
|
f20531cff5 | ||
|
|
8b1cbed9ce | ||
|
|
0194e13427 | ||
|
|
82d71abf54 | ||
|
|
e71cfadf6e | ||
|
|
18931c4e98 | ||
|
|
8622c080aa | ||
|
|
cb71b2a593 | ||
|
|
ff5956da41 | ||
|
|
acdafc2efd | ||
|
|
b8874092ad | ||
|
|
ad28ba0b3e | ||
|
|
0d90b60eef | ||
|
|
7c18c9f69c | ||
|
|
975560f46f | ||
|
|
bfe9cbf7d9 | ||
|
|
ccb5eb73db | ||
|
|
d143667bd6 | ||
|
|
87d809abc0 | ||
|
|
4dc5b1a541 | ||
|
|
ddd3e867f9 | ||
|
|
77480d3d69 | ||
|
|
0767c93002 | ||
|
|
e690e6dd3b | ||
|
|
d4665ed768 | ||
|
|
b90a92c0df | ||
|
|
50cfcf9796 | ||
|
|
5d204f09da | ||
|
|
4c0410322f | ||
|
|
fbb2b3f6e7 | ||
|
|
0f09fb49fc | ||
|
|
b0d063d6ed | ||
|
|
a68fe70af4 | ||
|
|
43c7ac281b | ||
|
|
a97ae55a06 | ||
|
|
4a3a6f4186 | ||
|
|
f976724ada | ||
|
|
2632bdaa30 | ||
|
|
91016d7b8c | ||
|
|
2b00e741ca | ||
|
|
d496c11d67 | ||
|
|
5880223517 | ||
|
|
394a5dcd0d | ||
|
|
7365275f46 | ||
|
|
0ecab5fdd4 | ||
|
|
ed0d9f73e4 | ||
|
|
28f4e16662 | ||
|
|
b9b0bff946 | ||
|
|
790718a5df | ||
|
|
96a0301f5e | ||
|
|
c57b019b7d | ||
|
|
af920c4dda | ||
|
|
f3d11788ed | ||
|
|
fd0e02af59 | ||
|
|
2a6c51d52c | ||
|
|
2d62e2070b | ||
|
|
b143bd70f0 | ||
|
|
605509c57c | ||
|
|
7036137b23 | ||
|
|
7a9ff535b4 | ||
|
|
f185bafe2a | ||
|
|
ab81d5d020 | ||
|
|
0965e6489b | ||
|
|
792e1c9cad | ||
|
|
a6721f971a | ||
|
|
8113d0e4e0 | ||
|
|
e3c7d3f8a2 | ||
|
|
6415de8c73 | ||
|
|
f2838cf31d | ||
|
|
fbd49b370d | ||
|
|
79f7296576 | ||
|
|
76f4ca5f89 | ||
|
|
477acda1c1 | ||
|
|
a57f343dcc | ||
|
|
36e9201ed4 | ||
|
|
c1525501d4 | ||
|
|
e4bb90a569 | ||
|
|
28642cc521 | ||
|
|
beae79ddec | ||
|
|
f02e10ab3d | ||
|
|
d0b9dff476 | ||
|
|
501e290839 | ||
|
|
a0daf37f80 | ||
|
|
8111b1ff4b | ||
|
|
754087afd6 | ||
|
|
5e16b6092c | ||
|
|
21636a75fa | ||
|
|
f124f5422a | ||
|
|
1e5d1a2528 | ||
|
|
1fcef07902 | ||
|
|
41e7dd8056 | ||
|
|
dccc35db5f | ||
|
|
0cfe59aa34 | ||
|
|
6fdd156fa3 | ||
|
|
e9fcf25ad3 | ||
|
|
a9422165ca | ||
|
|
0ea5ee8239 | ||
|
|
fba25cba61 | ||
|
|
343b5a1c50 | ||
|
|
63522aad81 | ||
|
|
b957aa7fba | ||
|
|
a71aa6868a | ||
|
|
6b50bf0cf7 | ||
|
|
d00444ec56 | ||
|
|
e7ed39fe39 | ||
|
|
168d68d0b2 | ||
|
|
63cddfdde3 | ||
|
|
4a642fd3da | ||
|
|
13c0407b2d | ||
|
|
794ed6d103 | ||
|
|
d0aeb5a6ce | ||
|
|
030f8c6079 | ||
|
|
7195e204ce | ||
|
|
962a328219 | ||
|
|
1cec2ca7f3 | ||
|
|
a3c4187411 | ||
|
|
18a2df5d9b | ||
|
|
6d66c793cb | ||
|
|
b434c8df1a | ||
|
|
2b8fa2fc2b | ||
|
|
1497d2abea | ||
|
|
a2ca79843d | ||
|
|
f6500e7d66 | ||
|
|
ea2fd0fc9a | ||
|
|
e2cbd30a99 | ||
|
|
151ea44b10 | ||
|
|
6487a0b08e | ||
|
|
552fdf9ec0 | ||
|
|
00cf1449f9 | ||
|
|
8ec88e385a | ||
|
|
cc29b2960a | ||
|
|
568ffd67c4 | ||
|
|
4b4670201a | ||
|
|
92f70c9a76 | ||
|
|
1d2dc3fddf | ||
|
|
c44150fd15 | ||
|
|
8664b53991 | ||
|
|
31aeca2340 | ||
|
|
34eec3ff2e | ||
|
|
e1416b5a4b | ||
|
|
3ca75729b9 | ||
|
|
73031eea65 | ||
|
|
1643c5b7ee | ||
|
|
ca5db726bd | ||
|
|
4bb4d32b48 | ||
|
|
fec7a89807 | ||
|
|
db2615a4eb | ||
|
|
eea5d5ba2a | ||
|
|
f405bbff4d | ||
|
|
dd8d895b50 | ||
|
|
dff4e98523 | ||
|
|
846bbb9033 | ||
|
|
e6f9a33b3c | ||
|
|
092126bded | ||
|
|
e5d5cb4dab | ||
|
|
bd76966d3a | ||
|
|
d46908a298 | ||
|
|
e4cec021b0 | ||
|
|
42d2d975db | ||
|
|
427f91d677 | ||
|
|
7a9c9237a3 | ||
|
|
9b431b020f | ||
|
|
ee1eece181 | ||
|
|
3627194f34 | ||
|
|
65cfb57605 | ||
|
|
8e4a547c77 | ||
|
|
a751efe7d5 | ||
|
|
e859895261 | ||
|
|
ae3d38603a | ||
|
|
fca72eb747 | ||
|
|
923e963369 | ||
|
|
7a3c9a3460 | ||
|
|
e649348af2 | ||
|
|
ba58e80ec3 | ||
|
|
45e2c9a403 | ||
|
|
bd9592c19c | ||
|
|
1bb597999d | ||
|
|
7803fa60f2 | ||
|
|
4adb7dc92c | ||
|
|
ba69a1de2c | ||
|
|
64265206c2 | ||
|
|
eec8f66b81 | ||
|
|
999e8ef318 | ||
|
|
30f385c2d9 | ||
|
|
87377fbe4c | ||
|
|
2a66602c2c | ||
|
|
8cc18ca272 | ||
|
|
677db8fd0d | ||
|
|
a458adc45f | ||
|
|
5a09ddcb04 | ||
|
|
4d9fde572e | ||
|
|
3e4b347506 | ||
|
|
927bbae0c1 | ||
|
|
7e3e1f19aa | ||
|
|
5a4b1b6ee1 | ||
|
|
25767aab8e | ||
|
|
b3a0949395 | ||
|
|
18e6fc2a3c | ||
|
|
4d45b6e50f | ||
|
|
eefb055a3f | ||
|
|
9c41a6b28f | ||
|
|
bf0e2e6cfe | ||
|
|
4a2adabe95 | ||
|
|
4031a42350 | ||
|
|
4698a806f0 | ||
|
|
aec53aa5f0 | ||
|
|
e15ddd020c | ||
|
|
6f4aead0d4 | ||
|
|
6b3bf31597 | ||
|
|
2ac118a008 | ||
|
|
c87880529c | ||
|
|
b12766321d | ||
|
|
3d6bee2d85 | ||
|
|
c8a8315ad0 | ||
|
|
dac9bcc3de | ||
|
|
7688288d05 | ||
|
|
46621d6b93 | ||
|
|
35700f7e57 | ||
|
|
08e6744595 | ||
|
|
2de3e5e328 | ||
|
|
51f2eb1b1d | ||
|
|
b4faf7c49e | ||
|
|
26d9562c18 | ||
|
|
d40d92c1ca | ||
|
|
7ea63643a9 | ||
|
|
0bd5c22681 | ||
|
|
8f0cf5b3a3 | ||
|
|
6458a71b5d | ||
|
|
dbdd23e37d | ||
|
|
313c324771 | ||
|
|
a9fd9343d8 | ||
|
|
8f41d4d0bc | ||
|
|
521853863b | ||
|
|
b7a5a647b3 | ||
|
|
4434f9ccad | ||
|
|
82a1cc3cfe | ||
|
|
2d92c2c0e2 | ||
|
|
6f10c91482 | ||
|
|
f2d6bce165 | ||
|
|
1ab05c7a5e | ||
|
|
61623cc44d | ||
|
|
a30a726324 | ||
|
|
0e90ad64cd | ||
|
|
53572c6236 | ||
|
|
67da56a03b | ||
|
|
be8633185d | ||
|
|
1d656da2a2 | ||
|
|
189deae3d1 | ||
|
|
46188ad52b | ||
|
|
19e232ddb9 | ||
|
|
5d90b7e938 | ||
|
|
3f90799544 | ||
|
|
1f70ec0d28 | ||
|
|
c26b78aa01 | ||
|
|
0debf16f7c | ||
|
|
d7f48d8f9f | ||
|
|
58c95559dd | ||
|
|
03caa9fe94 | ||
|
|
afd8697f07 | ||
|
|
fc77aded28 | ||
|
|
a5cafd1fb8 | ||
|
|
91d504fc1c | ||
|
|
db0444a8eb | ||
|
|
0cab872baf | ||
|
|
7f191eb2fd | ||
|
|
52adc2553b | ||
|
|
de49fd7e95 | ||
|
|
7eb61473a8 | ||
|
|
f6a134342a | ||
|
|
1d67e5ed68 | ||
|
|
7d4aa80966 | ||
|
|
742dde622b | ||
|
|
497aa6a42c | ||
|
|
40ebf42da1 | ||
|
|
2f8aea5285 | ||
|
|
53f545ba13 | ||
|
|
689b34611e | ||
|
|
d55c3f45ef | ||
|
|
5ac533616f | ||
|
|
96ea5f5d16 | ||
|
|
87526f5efc | ||
|
|
d31bafbc0e | ||
|
|
66bae47bb9 | ||
|
|
7a09b66d4e | ||
|
|
de5932184f | ||
|
|
2cba62e050 | ||
|
|
c7520d98e0 | ||
|
|
92e9f7bc08 | ||
|
|
e0becce349 | ||
|
|
a65c4ba215 | ||
|
|
4cd0c3357b | ||
|
|
d5cabf8af5 | ||
|
|
3120de757d | ||
|
|
0b69fe591e | ||
|
|
032288d062 | ||
|
|
1d6618c1c0 | ||
|
|
7126e03f0d | ||
|
|
c27556c809 | ||
|
|
99ff28d3e1 | ||
|
|
8ad6f60757 | ||
|
|
5f67b987a0 | ||
|
|
5842b3c4aa | ||
|
|
e2e1d2f2fd | ||
|
|
dd205c0f06 | ||
|
|
79e247c0cf | ||
|
|
836d045b65 | ||
|
|
2d029b65e6 | ||
|
|
993b7efeef | ||
|
|
7e02a6b932 | ||
|
|
60e38fb8bc | ||
|
|
4fc2757ffa | ||
|
|
c89b25d7c9 | ||
|
|
f2fc354f8c | ||
|
|
0e7eca339c | ||
|
|
5f76cb9f0a | ||
|
|
ed3a4bd32a | ||
|
|
a0a1b68f68 | ||
|
|
b7a81097a4 | ||
|
|
651bef8203 | ||
|
|
a9e5c99ab2 | ||
|
|
30216fdd5b | ||
|
|
341cc13d83 | ||
|
|
05a4ae6f04 | ||
|
|
5971d9fd83 | ||
|
|
3968f2275c | ||
|
|
84344ca883 | ||
|
|
59b80254eb | ||
|
|
06fdb19e0b | ||
|
|
75222e8cd2 | ||
|
|
5a067d60e7 | ||
|
|
2fbc4fcb4a | ||
|
|
13fe60504a | ||
|
|
cdc52c3605 | ||
|
|
a9db097355 | ||
|
|
ec5557cf88 | ||
|
|
a8ea84d2f3 | ||
|
|
58d369eedf | ||
|
|
f8f9dd7070 | ||
|
|
01b72e1ee6 | ||
|
|
e367e630b8 | ||
|
|
385cca6fc0 | ||
|
|
75a3a466a3 | ||
|
|
4bf08dbfe6 | ||
|
|
833d061315 | ||
|
|
a85558278d | ||
|
|
bf5087b06d | ||
|
|
ec58d13bae | ||
|
|
75993564ab | ||
|
|
f3ea169dec | ||
|
|
39b3fe5c25 | ||
|
|
3b2b586420 | ||
|
|
5c79c6cb0c | ||
|
|
bab4261bed | ||
|
|
e1d5c89388 | ||
|
|
5f6c8cca18 | ||
|
|
39db14b002 | ||
|
|
3be04c678b | ||
|
|
099ec35a8f | ||
|
|
113dfb9170 | ||
|
|
8d19e0ebbb | ||
|
|
ec064eba65 | ||
|
|
3451127761 | ||
|
|
b3be52ca77 | ||
|
|
b6ec6caa72 | ||
|
|
8e81e18622 | ||
|
|
6ea26e0e19 | ||
|
|
be446f94c1 | ||
|
|
3d94e30f22 | ||
|
|
d5a7ff3a46 | ||
|
|
bbfa97632d | ||
|
|
ecf0ce22d6 | ||
|
|
d56da007a5 | ||
|
|
2c86b2da7e | ||
|
|
c73b1ceb07 | ||
|
|
a320c8967d | ||
|
|
e21e340f60 | ||
|
|
f63d8f4b91 | ||
|
|
ba6a1606b6 | ||
|
|
51b0c0456f | ||
|
|
04bd03b496 | ||
|
|
bc5764c8ff | ||
|
|
1f2e066f4c | ||
|
|
74c457a694 | ||
|
|
4a1c53dfd7 | ||
|
|
81b77f8768 | ||
|
|
3b127b6862 | ||
|
|
2815d2ba11 | ||
|
|
1ff20fc6f0 | ||
|
|
797c847055 | ||
|
|
65c7f2f66f | ||
|
|
445d621590 | ||
|
|
d39ecfd6b4 | ||
|
|
36663471fb | ||
|
|
80293ac52f | ||
|
|
70b45f40f5 | ||
|
|
a511fabd9c | ||
|
|
8bc8f6f178 | ||
|
|
b790ad58a7 | ||
|
|
354ab793a2 | ||
|
|
59346d641f | ||
|
|
11d770771b | ||
|
|
1b6db7ed45 | ||
|
|
55c4e10fae | ||
|
|
77c06dad61 | ||
|
|
68d250d2f2 | ||
|
|
094a17ac68 | ||
|
|
dbcdeaa3de | ||
|
|
872cac811a | ||
|
|
d324c2fee9 | ||
|
|
577e8df612 | ||
|
|
4b54cf67ba | ||
|
|
0e00fe3114 | ||
|
|
15d1dc5bb6 | ||
|
|
2af0003843 | ||
|
|
3c227be170 | ||
|
|
e889780bad | ||
|
|
cc3d4fa805 | ||
|
|
743823f66e | ||
|
|
227e1e2d2d | ||
|
|
d6c8ff0910 | ||
|
|
bd20e051b0 | ||
|
|
2eb6697e9a | ||
|
|
c5817fcc36 | ||
|
|
f2391bcb2d | ||
|
|
bc3bd9e5da | ||
|
|
3f0959d75e | ||
|
|
31f7b56724 | ||
|
|
072954d755 | ||
|
|
d271e0f9c8 | ||
|
|
8f1408ce17 | ||
|
|
825d1f4cfb | ||
|
|
c6bcd7e05a | ||
|
|
5d80051f3b | ||
|
|
b71c448199 | ||
|
|
c82148412c | ||
|
|
a582ee63a0 | ||
|
|
db7c19c486 | ||
|
|
599f71da19 | ||
|
|
0995744d90 | ||
|
|
4073a27aba | ||
|
|
bec9c31c97 | ||
|
|
acdd615c53 | ||
|
|
8091617ee2 | ||
|
|
c25ff6fcef | ||
|
|
ab0dcd607b | ||
|
|
ce288e472f | ||
|
|
02d8f25daf | ||
|
|
a76d1c6149 | ||
|
|
17f5eade19 | ||
|
|
b6a2a5054b | ||
|
|
5984338c64 | ||
|
|
07d1c48e33 | ||
|
|
d2abae947c | ||
|
|
e4a0f2451a | ||
|
|
880c598b1a | ||
|
|
3632c2c4d8 | ||
|
|
09bc9686ae | ||
|
|
34584ab098 | ||
|
|
554d99ca08 | ||
|
|
5c5d688ffa | ||
|
|
c50d55e87c | ||
|
|
5e5516bfb3 | ||
|
|
4b068c57c5 | ||
|
|
203f199aec | ||
|
|
895f17aaf9 | ||
|
|
8a64ff3559 | ||
|
|
4c45d356c4 | ||
|
|
4dec329f11 | ||
|
|
b563ed118e | ||
|
|
75b2ec40b1 | ||
|
|
d9adaf6667 | ||
|
|
9343308f41 | ||
|
|
88769e40ae | ||
|
|
be45eb7400 | ||
|
|
2f719a03a4 | ||
|
|
64196f9754 | ||
|
|
49a77f1b79 | ||
|
|
3838c4f2f9 | ||
|
|
80d89c95b5 | ||
|
|
30cd8b5cfe | ||
|
|
c443170f78 | ||
|
|
a2c2aa2377 | ||
|
|
4f0eb49a02 | ||
|
|
a821357b4f | ||
|
|
3c7679a22d | ||
|
|
a52737e236 |
@@ -1,16 +1,19 @@
|
|||||||
|
ci:
|
||||||
|
skip:
|
||||||
|
- unittest
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v4.3.0
|
rev: v5.0.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
- id: check-yaml
|
- id: check-yaml
|
||||||
- id: check-added-large-files
|
- id: check-added-large-files
|
||||||
- repo: https://github.com/psf/black
|
- repo: https://github.com/psf/black
|
||||||
rev: 22.6.0
|
rev: 24.10.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: black
|
||||||
- repo: https://github.com/pycqa/isort
|
- repo: https://github.com/pycqa/isort
|
||||||
rev: 5.10.1
|
rev: 5.13.2
|
||||||
hooks:
|
hooks:
|
||||||
- id: isort
|
- id: isort
|
||||||
name: isort (python)
|
name: isort (python)
|
||||||
@@ -24,4 +27,3 @@ repos:
|
|||||||
'types': [python]
|
'types': [python]
|
||||||
args: ["-p '*test.py'"] # Probably this option is absolutely not needed.
|
args: ["-p '*test.py'"] # Probably this option is absolutely not needed.
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
stages: [commit]
|
|
||||||
|
|||||||
57
README.md
57
README.md
@@ -9,7 +9,7 @@
|
|||||||
[](https://github.com/UpstreamData/pyasic/commits/master/)
|
[](https://github.com/UpstreamData/pyasic/commits/master/)
|
||||||
|
|
||||||
[](https://github.com/psf/black)
|
[](https://github.com/psf/black)
|
||||||
[](https://pyasic.readthedocs.io/en/latest/)
|
[](https://docs.pyasic.org)
|
||||||
[](https://github.com/UpstreamData/pyasic/blob/master/LICENSE.txt)
|
[](https://github.com/UpstreamData/pyasic/blob/master/LICENSE.txt)
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -17,7 +17,38 @@
|
|||||||
|
|
||||||
Welcome to `pyasic`! `pyasic` uses an asynchronous method of communicating with ASIC miners on your network, which makes it super fast.
|
Welcome to `pyasic`! `pyasic` uses an asynchronous method of communicating with ASIC miners on your network, which makes it super fast.
|
||||||
|
|
||||||
[Click here to view supported miner types](miners/supported_types.md)
|
[Click here to view supported miner types](https://docs.pyasic.org/en/latest/miners/supported_types/)
|
||||||
|
|
||||||
|
---
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
It is recommended to install `pyasic` in a [virtual environment](https://realpython.com/python-virtual-environments-a-primer/#what-other-popular-options-exist-aside-from-venv) to isolate it from the rest of your system. Options include:
|
||||||
|
- [pypoetry](https://python-poetry.org/): the reccommended way, since pyasic already uses it by default
|
||||||
|
|
||||||
|
```
|
||||||
|
poetry install
|
||||||
|
```
|
||||||
|
|
||||||
|
- [venv](https://docs.python.org/3/library/venv.html): included in Python standard library but has fewer features than other options
|
||||||
|
- [pyenv-virtualenv](https://github.com/pyenv/pyenv-virtualenv): [pyenv](https://github.com/pyenv/pyenv) plugin for managing virtualenvs
|
||||||
|
|
||||||
|
```
|
||||||
|
pyenv install <python version number>
|
||||||
|
pyenv virtualenv <python version number> <env name>
|
||||||
|
pyenv activate <env name>
|
||||||
|
```
|
||||||
|
|
||||||
|
- [conda](https://docs.conda.io/en/latest/)
|
||||||
|
|
||||||
|
##### Installing `pyasic`
|
||||||
|
|
||||||
|
`python -m pip install pyasic` or `poetry install`
|
||||||
|
|
||||||
|
##### Additional Developer Setup
|
||||||
|
```
|
||||||
|
poetry install --with dev
|
||||||
|
pre-commit install
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
## Getting started
|
## Getting started
|
||||||
@@ -224,24 +255,30 @@ if __name__ == "__main__":
|
|||||||
```python
|
```python
|
||||||
from pyasic import settings
|
from pyasic import settings
|
||||||
|
|
||||||
settings.update("default_antminer_password", "my_pwd")
|
settings.update("default_antminer_web_password", "my_pwd")
|
||||||
```
|
```
|
||||||
|
|
||||||
##### Default values:
|
##### Default values:
|
||||||
```
|
```
|
||||||
"network_ping_retries": 1,
|
"network_ping_retries": 1,
|
||||||
"network_ping_timeout": 3,
|
"network_ping_timeout": 3,
|
||||||
"network_scan_threads": 300,
|
"network_scan_semaphore": None,
|
||||||
"factory_get_retries": 1,
|
"factory_get_retries": 1,
|
||||||
"factory_get_timeout": 3,
|
"factory_get_timeout": 3,
|
||||||
"get_data_retries": 1,
|
"get_data_retries": 1,
|
||||||
"api_function_timeout": 5,
|
"api_function_timeout": 5,
|
||||||
"default_whatsminer_password": "admin",
|
"antminer_mining_mode_as_str": False,
|
||||||
"default_innosilicon_password": "admin",
|
"default_whatsminer_rpc_password": "admin",
|
||||||
"default_antminer_password": "root",
|
"default_innosilicon_web_password": "admin",
|
||||||
"default_bosminer_password": "root",
|
"default_antminer_web_password": "root",
|
||||||
"default_vnish_password": "admin",
|
"default_bosminer_web_password": "root",
|
||||||
"default_goldshell_password": "123456789",
|
"default_vnish_web_password": "admin",
|
||||||
|
"default_goldshell_web_password": "123456789",
|
||||||
|
"default_auradine_web_password": "admin",
|
||||||
|
"default_epic_web_password": "letmein",
|
||||||
|
"default_hive_web_password": "admin",
|
||||||
|
"default_antminer_ssh_password": "miner",
|
||||||
|
"default_bosminer_ssh_password": "root",
|
||||||
|
|
||||||
# ADVANCED
|
# ADVANCED
|
||||||
# Only use this if you know what you are doing
|
# Only use this if you know what you are doing
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ def backend_str(backend: MinerTypes) -> str:
|
|||||||
match backend:
|
match backend:
|
||||||
case MinerTypes.ANTMINER:
|
case MinerTypes.ANTMINER:
|
||||||
return "Stock Firmware Antminers"
|
return "Stock Firmware Antminers"
|
||||||
|
case MinerTypes.AURADINE:
|
||||||
|
return "Stock Firmware Auradine Miners"
|
||||||
case MinerTypes.AVALONMINER:
|
case MinerTypes.AVALONMINER:
|
||||||
return "Stock Firmware Avalonminers"
|
return "Stock Firmware Avalonminers"
|
||||||
case MinerTypes.VNISH:
|
case MinerTypes.VNISH:
|
||||||
@@ -45,6 +47,14 @@ def backend_str(backend: MinerTypes) -> str:
|
|||||||
return "Stock Firmware Goldshells"
|
return "Stock Firmware Goldshells"
|
||||||
case MinerTypes.LUX_OS:
|
case MinerTypes.LUX_OS:
|
||||||
return "LuxOS Firmware Miners"
|
return "LuxOS Firmware Miners"
|
||||||
|
case MinerTypes.MARATHON:
|
||||||
|
return "Mara Firmware Miners"
|
||||||
|
case MinerTypes.BITAXE:
|
||||||
|
return "Stock Firmware BitAxe Miners"
|
||||||
|
case MinerTypes.ICERIVER:
|
||||||
|
return "Stock Firmware IceRiver Miners"
|
||||||
|
case MinerTypes.HAMMER:
|
||||||
|
return "Stock Firmware Hammer Miners"
|
||||||
|
|
||||||
|
|
||||||
def create_url_str(mtype: str):
|
def create_url_str(mtype: str):
|
||||||
|
|||||||
@@ -18,6 +18,31 @@ Welcome to `pyasic`! `pyasic` uses an asynchronous method of communicating with
|
|||||||
|
|
||||||
[Click here to view supported miner types](miners/supported_types.md)
|
[Click here to view supported miner types](miners/supported_types.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
It is recommended to install `pyasic` in a [virtual environment](https://realpython.com/python-virtual-environments-a-primer/#what-other-popular-options-exist-aside-from-venv) to isolate it from the rest of your system. Options include:
|
||||||
|
- [pypoetry](https://python-poetry.org/): the reccommended way, since pyasic already uses it by default
|
||||||
|
|
||||||
|
```
|
||||||
|
poetry install
|
||||||
|
```
|
||||||
|
|
||||||
|
- [venv](https://docs.python.org/3/library/venv.html): included in Python standard library but has fewer features than other options
|
||||||
|
- [pyenv-virtualenv](https://github.com/pyenv/pyenv-virtualenv): [pyenv](https://github.com/pyenv/pyenv) plugin for managing virtualenvs
|
||||||
|
|
||||||
|
```
|
||||||
|
pyenv install <python version number>
|
||||||
|
pyenv virtualenv <python version number> <env name>
|
||||||
|
pyenv activate <env name>
|
||||||
|
```
|
||||||
|
|
||||||
|
- [conda](https://docs.conda.io/en/latest/)
|
||||||
|
|
||||||
|
##### Installing `pyasic`
|
||||||
|
|
||||||
|
`python -m pip install pyasic` or `poetry install`
|
||||||
|
|
||||||
---
|
---
|
||||||
## Getting started
|
## Getting started
|
||||||
---
|
---
|
||||||
@@ -224,24 +249,30 @@ if __name__ == "__main__":
|
|||||||
```python
|
```python
|
||||||
from pyasic import settings
|
from pyasic import settings
|
||||||
|
|
||||||
settings.update("default_antminer_password", "my_pwd")
|
settings.update("default_antminer_web_password", "my_pwd")
|
||||||
```
|
```
|
||||||
|
|
||||||
##### Default values:
|
##### Default values:
|
||||||
```
|
```
|
||||||
"network_ping_retries": 1,
|
"network_ping_retries": 1,
|
||||||
"network_ping_timeout": 3,
|
"network_ping_timeout": 3,
|
||||||
"network_scan_threads": 300,
|
"network_scan_semaphore": None,
|
||||||
"factory_get_retries": 1,
|
"factory_get_retries": 1,
|
||||||
"factory_get_timeout": 3,
|
"factory_get_timeout": 3,
|
||||||
"get_data_retries": 1,
|
"get_data_retries": 1,
|
||||||
"api_function_timeout": 5,
|
"api_function_timeout": 5,
|
||||||
"default_whatsminer_password": "admin",
|
"antminer_mining_mode_as_str": False,
|
||||||
"default_innosilicon_password": "admin",
|
"default_whatsminer_rpc_password": "admin",
|
||||||
"default_antminer_password": "root",
|
"default_innosilicon_web_password": "admin",
|
||||||
"default_bosminer_password": "root",
|
"default_antminer_web_password": "root",
|
||||||
"default_vnish_password": "admin",
|
"default_bosminer_web_password": "root",
|
||||||
"default_goldshell_password": "123456789",
|
"default_vnish_web_password": "admin",
|
||||||
|
"default_goldshell_web_password": "123456789",
|
||||||
|
"default_auradine_web_password": "admin",
|
||||||
|
"default_epic_web_password": "letmein",
|
||||||
|
"default_hive_web_password": "admin",
|
||||||
|
"default_antminer_ssh_password": "miner",
|
||||||
|
"default_bosminer_ssh_password": "root",
|
||||||
|
|
||||||
# ADVANCED
|
# ADVANCED
|
||||||
# Only use this if you know what you are doing
|
# Only use this if you know what you are doing
|
||||||
|
|||||||
@@ -1,10 +1,17 @@
|
|||||||
# pyasic
|
# pyasic
|
||||||
## X15 Models
|
## X15 Models
|
||||||
|
|
||||||
## Z15
|
## Z15 (Stock)
|
||||||
::: pyasic.miners.antminer.cgminer.X15.Z15.CGMinerZ15
|
::: pyasic.miners.antminer.cgminer.X15.Z15.CGMinerZ15
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
|
## Z15 Pro (Stock)
|
||||||
|
::: pyasic.miners.antminer.bmminer.X15.Z15.BMMinerZ15Pro
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
|||||||
@@ -1,98 +1,98 @@
|
|||||||
# pyasic
|
# pyasic
|
||||||
## X17 Models
|
## X17 Models
|
||||||
|
|
||||||
## S17
|
## S17 (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X17.S17.BMMinerS17
|
::: pyasic.miners.antminer.bmminer.X17.S17.BMMinerS17
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S17+
|
## S17+ (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X17.S17.BMMinerS17Plus
|
::: pyasic.miners.antminer.bmminer.X17.S17.BMMinerS17Plus
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S17 Pro
|
## S17 Pro (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X17.S17.BMMinerS17Pro
|
::: pyasic.miners.antminer.bmminer.X17.S17.BMMinerS17Pro
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S17e
|
## S17e (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X17.S17.BMMinerS17e
|
::: pyasic.miners.antminer.bmminer.X17.S17.BMMinerS17e
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## T17
|
## T17 (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X17.T17.BMMinerT17
|
::: pyasic.miners.antminer.bmminer.X17.T17.BMMinerT17
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## T17+
|
## T17+ (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X17.T17.BMMinerT17Plus
|
::: pyasic.miners.antminer.bmminer.X17.T17.BMMinerT17Plus
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## T17e
|
## T17e (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X17.T17.BMMinerT17e
|
::: pyasic.miners.antminer.bmminer.X17.T17.BMMinerT17e
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S17 (BOS)
|
## S17 (BOS+)
|
||||||
::: pyasic.miners.antminer.bosminer.X17.S17.BOSMinerS17
|
::: pyasic.miners.antminer.bosminer.X17.S17.BOSMinerS17
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S17+ (BOS)
|
## S17+ (BOS+)
|
||||||
::: pyasic.miners.antminer.bosminer.X17.S17.BOSMinerS17Plus
|
::: pyasic.miners.antminer.bosminer.X17.S17.BOSMinerS17Plus
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S17 Pro (BOS)
|
## S17 Pro (BOS+)
|
||||||
::: pyasic.miners.antminer.bosminer.X17.S17.BOSMinerS17Pro
|
::: pyasic.miners.antminer.bosminer.X17.S17.BOSMinerS17Pro
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S17e (BOS)
|
## S17e (BOS+)
|
||||||
::: pyasic.miners.antminer.bosminer.X17.S17.BOSMinerS17e
|
::: pyasic.miners.antminer.bosminer.X17.S17.BOSMinerS17e
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## T17 (BOS)
|
## T17 (BOS+)
|
||||||
::: pyasic.miners.antminer.bosminer.X17.T17.BOSMinerT17
|
::: pyasic.miners.antminer.bosminer.X17.T17.BOSMinerT17
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## T17+ (BOS)
|
## T17+ (BOS+)
|
||||||
::: pyasic.miners.antminer.bosminer.X17.T17.BOSMinerT17Plus
|
::: pyasic.miners.antminer.bosminer.X17.T17.BOSMinerT17Plus
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## T17e (BOS)
|
## T17e (BOS+)
|
||||||
::: pyasic.miners.antminer.bosminer.X17.T17.BOSMinerT17e
|
::: pyasic.miners.antminer.bosminer.X17.T17.BOSMinerT17e
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
|
|||||||
@@ -1,140 +1,238 @@
|
|||||||
# pyasic
|
# pyasic
|
||||||
## X19 Models
|
## X19 Models
|
||||||
|
|
||||||
## S19
|
## S19 (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19
|
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S19L
|
## S19L (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19L
|
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19L
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S19 Pro
|
## S19 Pro (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19Pro
|
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19Pro
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S19j
|
## S19j (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19j
|
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19j
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S19i
|
## S19i (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19i
|
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19i
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S19+
|
## S19+ (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19Plus
|
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19Plus
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S19j No PIC
|
## S19j No PIC (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19jNoPIC
|
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19jNoPIC
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S19 Pro+
|
## S19 Pro+ (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19ProPlus
|
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19ProPlus
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S19j Pro
|
## S19j Pro (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19jPro
|
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19jPro
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S19 XP
|
## S19 XP (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19XP
|
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19XP
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S19a
|
## S19a (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19a
|
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19a
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S19a Pro
|
## S19a Pro (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19aPro
|
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19aPro
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## T19
|
## S19 Hydro (Stock)
|
||||||
|
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19Hydro
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19 Pro Hydro (Stock)
|
||||||
|
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19ProHydro
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19 Pro+ Hydro (Stock)
|
||||||
|
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19ProPlusHydro
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19K Pro (Stock)
|
||||||
|
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19KPro
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## T19 (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X19.T19.BMMinerT19
|
::: pyasic.miners.antminer.bmminer.X19.T19.BMMinerT19
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S19 (BOS)
|
## S19 (BOS+)
|
||||||
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19
|
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S19 Pro (BOS)
|
## S19+ (BOS+)
|
||||||
|
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19Plus
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19 Pro (BOS+)
|
||||||
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19Pro
|
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19Pro
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S19j (BOS)
|
## S19a (BOS+)
|
||||||
|
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19a
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19a Pro (BOS+)
|
||||||
|
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19aPro
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19j (BOS+)
|
||||||
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19j
|
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19j
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S19j No PIC (BOS)
|
## S19j No PIC (BOS+)
|
||||||
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19jNoPIC
|
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19jNoPIC
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S19j Pro (BOS)
|
## S19j Pro (BOS+)
|
||||||
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19jPro
|
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19jPro
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S19j Pro (BOS)
|
## S19j Pro No PIC (BOS+)
|
||||||
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19jPro
|
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19jProNoPIC
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## T19 (BOS)
|
## S19j Pro+ (BOS+)
|
||||||
|
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19jProPlus
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19j Pro+ (BOS+)
|
||||||
|
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19jProPlus
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19j Pro+ No PIC (BOS+)
|
||||||
|
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19jProPlusNoPIC
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19k Pro No PIC (BOS+)
|
||||||
|
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19kProNoPIC
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19k Pro No PIC (BOS+)
|
||||||
|
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19kProNoPIC
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19 XP (BOS+)
|
||||||
|
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19XP
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19 Pro+ Hydro (BOS+)
|
||||||
|
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19ProPlusHydro
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## T19 (BOS+)
|
||||||
::: pyasic.miners.antminer.bosminer.X19.T19.BOSMinerT19
|
::: pyasic.miners.antminer.bosminer.X19.T19.BOSMinerT19
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
@@ -176,6 +274,13 @@
|
|||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19j Pro (VNish)
|
||||||
|
::: pyasic.miners.antminer.vnish.X19.S19.VNishS19jPro
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
## S19a (VNish)
|
## S19a (VNish)
|
||||||
::: pyasic.miners.antminer.vnish.X19.S19.VNishS19a
|
::: pyasic.miners.antminer.vnish.X19.S19.VNishS19a
|
||||||
handler: python
|
handler: python
|
||||||
@@ -190,6 +295,13 @@
|
|||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19 Pro Hydro (VNish)
|
||||||
|
::: pyasic.miners.antminer.vnish.X19.S19.VNishS19ProHydro
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
## T19 (VNish)
|
## T19 (VNish)
|
||||||
::: pyasic.miners.antminer.vnish.X19.T19.VNishT19
|
::: pyasic.miners.antminer.vnish.X19.T19.VNishT19
|
||||||
handler: python
|
handler: python
|
||||||
@@ -225,6 +337,20 @@
|
|||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19j Pro+ (ePIC)
|
||||||
|
::: pyasic.miners.antminer.epic.X19.S19.ePICS19jProPlus
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19k Pro (ePIC)
|
||||||
|
::: pyasic.miners.antminer.epic.X19.S19.ePICS19kPro
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
## S19 XP (ePIC)
|
## S19 XP (ePIC)
|
||||||
::: pyasic.miners.antminer.epic.X19.S19.ePICS19XP
|
::: pyasic.miners.antminer.epic.X19.S19.ePICS19XP
|
||||||
handler: python
|
handler: python
|
||||||
@@ -232,3 +358,108 @@
|
|||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19j Pro (Stock)
|
||||||
|
::: pyasic.miners.antminer.hiveon.X19.S19.HiveonS19jPro
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19 (LuxOS)
|
||||||
|
::: pyasic.miners.antminer.luxos.X19.S19.LUXMinerS19
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19 Pro (LuxOS)
|
||||||
|
::: pyasic.miners.antminer.luxos.X19.S19.LUXMinerS19Pro
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19j Pro (LuxOS)
|
||||||
|
::: pyasic.miners.antminer.luxos.X19.S19.LUXMinerS19jPro
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19j Pro+ (LuxOS)
|
||||||
|
::: pyasic.miners.antminer.luxos.X19.S19.LUXMinerS19jProPlus
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19k Pro (LuxOS)
|
||||||
|
::: pyasic.miners.antminer.luxos.X19.S19.LUXMinerS19kPro
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19 XP (LuxOS)
|
||||||
|
::: pyasic.miners.antminer.luxos.X19.S19.LUXMinerS19XP
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## T19 (LuxOS)
|
||||||
|
::: pyasic.miners.antminer.luxos.X19.T19.LUXMinerT19
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19 (MaraFW)
|
||||||
|
::: pyasic.miners.antminer.marathon.X19.S19.MaraS19
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19 Pro (MaraFW)
|
||||||
|
::: pyasic.miners.antminer.marathon.X19.S19.MaraS19Pro
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19j (MaraFW)
|
||||||
|
::: pyasic.miners.antminer.marathon.X19.S19.MaraS19j
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19j No PIC (MaraFW)
|
||||||
|
::: pyasic.miners.antminer.marathon.X19.S19.MaraS19jNoPIC
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19j Pro (MaraFW)
|
||||||
|
::: pyasic.miners.antminer.marathon.X19.S19.MaraS19jPro
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19 XP (MaraFW)
|
||||||
|
::: pyasic.miners.antminer.marathon.X19.S19.MaraS19XP
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S19K Pro (MaraFW)
|
||||||
|
::: pyasic.miners.antminer.marathon.X19.S19.MaraS19KPro
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
|||||||
87
docs/miners/antminer/X21.md
Normal file
87
docs/miners/antminer/X21.md
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
# pyasic
|
||||||
|
## X21 Models
|
||||||
|
|
||||||
|
## S21 (Stock)
|
||||||
|
::: pyasic.miners.antminer.bmminer.X21.S21.BMMinerS21
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S21 Pro (Stock)
|
||||||
|
::: pyasic.miners.antminer.bmminer.X21.S21.BMMinerS21Pro
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## T21 (Stock)
|
||||||
|
::: pyasic.miners.antminer.bmminer.X21.T21.BMMinerT21
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S21 (BOS+)
|
||||||
|
::: pyasic.miners.antminer.bosminer.X21.S21.BOSMinerS21
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## T21 (BOS+)
|
||||||
|
::: pyasic.miners.antminer.bosminer.X21.T21.BOSMinerT21
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S21 (VNish)
|
||||||
|
::: pyasic.miners.antminer.vnish.X21.S21.VNishS21
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S21 (ePIC)
|
||||||
|
::: pyasic.miners.antminer.epic.X21.S21.ePICS21
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S21 Pro (ePIC)
|
||||||
|
::: pyasic.miners.antminer.epic.X21.S21.ePICS21Pro
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## T21 (ePIC)
|
||||||
|
::: pyasic.miners.antminer.epic.X21.T21.ePICT21
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S21 (LuxOS)
|
||||||
|
::: pyasic.miners.antminer.luxos.X21.S21.LUXMinerS21
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S21 (MaraFW)
|
||||||
|
::: pyasic.miners.antminer.marathon.X21.S21.MaraS21
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## T21 (MaraFW)
|
||||||
|
::: pyasic.miners.antminer.marathon.X21.T21.MaraT21
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
@@ -1,27 +1,48 @@
|
|||||||
# pyasic
|
# pyasic
|
||||||
## X3 Models
|
## X3 Models
|
||||||
|
|
||||||
## D3
|
## D3 (Stock)
|
||||||
::: pyasic.miners.antminer.cgminer.X3.D3.CGMinerD3
|
::: pyasic.miners.antminer.cgminer.X3.D3.CGMinerD3
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## HS3
|
## HS3 (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X3.HS3.BMMinerHS3
|
::: pyasic.miners.antminer.bmminer.X3.HS3.BMMinerHS3
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## L3+
|
## L3+ (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X3.L3.BMMinerL3Plus
|
::: pyasic.miners.antminer.bmminer.X3.L3.BMMinerL3Plus
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
|
## KA3 (Stock)
|
||||||
|
::: pyasic.miners.antminer.bmminer.X3.KA3.BMMinerKA3
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## KS3 (Stock)
|
||||||
|
::: pyasic.miners.antminer.bmminer.X3.KS3.BMMinerKS3
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## L3+ (VNish)
|
||||||
|
::: pyasic.miners.antminer.vnish.X3.L3.VnishL3Plus
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
## L3+ (VNish)
|
## L3+ (VNish)
|
||||||
::: pyasic.miners.antminer.vnish.X3.L3.VnishL3Plus
|
::: pyasic.miners.antminer.vnish.X3.L3.VnishL3Plus
|
||||||
handler: python
|
handler: python
|
||||||
|
|||||||
@@ -1,10 +1,17 @@
|
|||||||
# pyasic
|
# pyasic
|
||||||
## X5 Models
|
## X5 Models
|
||||||
|
|
||||||
## DR5
|
## DR5 (Stock)
|
||||||
::: pyasic.miners.antminer.cgminer.X5.DR5.CGMinerDR5
|
::: pyasic.miners.antminer.cgminer.X5.DR5.CGMinerDR5
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
|
## KS5 (Stock)
|
||||||
|
::: pyasic.miners.antminer.bmminer.X5.KS5.BMMinerKS5
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,31 @@
|
|||||||
# pyasic
|
# pyasic
|
||||||
## X7 Models
|
## X7 Models
|
||||||
|
|
||||||
## L7
|
## L7 (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X7.L7.BMMinerL7
|
::: pyasic.miners.antminer.bmminer.X7.L7.BMMinerL7
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
|
## K7 (Stock)
|
||||||
|
::: pyasic.miners.antminer.bmminer.X7.K7.BMMinerK7
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## D7 (Stock)
|
||||||
|
::: pyasic.miners.antminer.bmminer.X7.D7.BMMinerD7
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## L7 (VNish)
|
||||||
|
::: pyasic.miners.antminer.vnish.X7.L7.VnishL7
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
|||||||
@@ -1,49 +1,56 @@
|
|||||||
# pyasic
|
# pyasic
|
||||||
## X9 Models
|
## X9 Models
|
||||||
|
|
||||||
## E9Pro
|
## E9Pro (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X9.E9.BMMinerE9Pro
|
::: pyasic.miners.antminer.bmminer.X9.E9.BMMinerE9Pro
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S9
|
## D9 (Stock)
|
||||||
|
::: pyasic.miners.antminer.bmminer.X9.D9.BMMinerD9
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## S9 (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X9.S9.BMMinerS9
|
::: pyasic.miners.antminer.bmminer.X9.S9.BMMinerS9
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S9i
|
## S9i (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X9.S9.BMMinerS9i
|
::: pyasic.miners.antminer.bmminer.X9.S9.BMMinerS9i
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S9j
|
## S9j (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X9.S9.BMMinerS9j
|
::: pyasic.miners.antminer.bmminer.X9.S9.BMMinerS9j
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## T9
|
## T9 (Stock)
|
||||||
::: pyasic.miners.antminer.bmminer.X9.T9.BMMinerT9
|
::: pyasic.miners.antminer.bmminer.X9.T9.BMMinerT9
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## S9 (BOS)
|
## S9 (BOS+)
|
||||||
::: pyasic.miners.antminer.bosminer.X9.S9.BOSMinerS9
|
::: pyasic.miners.antminer.bosminer.X9.S9.BOSMinerS9
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## T9 (Hiveon)
|
## T9 (Stock)
|
||||||
::: pyasic.miners.antminer.hiveon.X9.T9.HiveonT9
|
::: pyasic.miners.antminer.hiveon.X9.T9.HiveonT9
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
|
|||||||
24
docs/miners/auradine/AD.md
Normal file
24
docs/miners/auradine/AD.md
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# pyasic
|
||||||
|
## AD Models
|
||||||
|
|
||||||
|
## AT1500 (Stock)
|
||||||
|
::: pyasic.miners.auradine.flux.AD.AT1.AuradineFluxAT1500
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## AT2860 (Stock)
|
||||||
|
::: pyasic.miners.auradine.flux.AD.AT2.AuradineFluxAT2860
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## AT2880 (Stock)
|
||||||
|
::: pyasic.miners.auradine.flux.AD.AT2.AuradineFluxAT2880
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
17
docs/miners/auradine/AI.md
Normal file
17
docs/miners/auradine/AI.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# pyasic
|
||||||
|
## AI Models
|
||||||
|
|
||||||
|
## AI2500 (Stock)
|
||||||
|
::: pyasic.miners.auradine.flux.AI.AI2.AuradineFluxAI2500
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## AI3680 (Stock)
|
||||||
|
::: pyasic.miners.auradine.flux.AI.AI3.AuradineFluxAI3680
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
17
docs/miners/auradine/AT.md
Normal file
17
docs/miners/auradine/AT.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# pyasic
|
||||||
|
## AT Models
|
||||||
|
|
||||||
|
## AD2500 (Stock)
|
||||||
|
::: pyasic.miners.auradine.flux.AT.AD2.AuradineFluxAD2500
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## AD3500 (Stock)
|
||||||
|
::: pyasic.miners.auradine.flux.AT.AD3.AuradineFluxAD3500
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
@@ -1,21 +1,21 @@
|
|||||||
# pyasic
|
# pyasic
|
||||||
## A10X Models
|
## A10X Models
|
||||||
|
|
||||||
## Avalon 1026
|
## Avalon 1026 (Stock)
|
||||||
::: pyasic.miners.avalonminer.cgminer.A10X.A1026.CGMinerAvalon1026
|
::: pyasic.miners.avalonminer.cgminer.A10X.A1026.CGMinerAvalon1026
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## Avalon 1047
|
## Avalon 1047 (Stock)
|
||||||
::: pyasic.miners.avalonminer.cgminer.A10X.A1047.CGMinerAvalon1047
|
::: pyasic.miners.avalonminer.cgminer.A10X.A1047.CGMinerAvalon1047
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## Avalon 1066
|
## Avalon 1066 (Stock)
|
||||||
::: pyasic.miners.avalonminer.cgminer.A10X.A1066.CGMinerAvalon1066
|
::: pyasic.miners.avalonminer.cgminer.A10X.A1066.CGMinerAvalon1066
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# pyasic
|
# pyasic
|
||||||
## A11X Models
|
## A11X Models
|
||||||
|
|
||||||
## Avalon 1166 Pro
|
## Avalon 1166 Pro (Stock)
|
||||||
::: pyasic.miners.avalonminer.cgminer.A11X.A1166.CGMinerAvalon1166Pro
|
::: pyasic.miners.avalonminer.cgminer.A11X.A1166.CGMinerAvalon1166Pro
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# pyasic
|
# pyasic
|
||||||
## A12X Models
|
## A12X Models
|
||||||
|
|
||||||
## Avalon 1246
|
## Avalon 1246 (Stock)
|
||||||
::: pyasic.miners.avalonminer.cgminer.A12X.A1246.CGMinerAvalon1246
|
::: pyasic.miners.avalonminer.cgminer.A12X.A1246.CGMinerAvalon1246
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
# pyasic
|
# pyasic
|
||||||
## A7X Models
|
## A7X Models
|
||||||
|
|
||||||
## Avalon 721
|
## Avalon 721 (Stock)
|
||||||
::: pyasic.miners.avalonminer.cgminer.A7X.A721.CGMinerAvalon721
|
::: pyasic.miners.avalonminer.cgminer.A7X.A721.CGMinerAvalon721
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## Avalon 741
|
## Avalon 741 (Stock)
|
||||||
::: pyasic.miners.avalonminer.cgminer.A7X.A741.CGMinerAvalon741
|
::: pyasic.miners.avalonminer.cgminer.A7X.A741.CGMinerAvalon741
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## Avalon 761
|
## Avalon 761 (Stock)
|
||||||
::: pyasic.miners.avalonminer.cgminer.A7X.A761.CGMinerAvalon761
|
::: pyasic.miners.avalonminer.cgminer.A7X.A761.CGMinerAvalon761
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
# pyasic
|
# pyasic
|
||||||
## A8X Models
|
## A8X Models
|
||||||
|
|
||||||
## Avalon 821
|
## Avalon 821 (Stock)
|
||||||
::: pyasic.miners.avalonminer.cgminer.A8X.A821.CGMinerAvalon821
|
::: pyasic.miners.avalonminer.cgminer.A8X.A821.CGMinerAvalon821
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## Avalon 841
|
## Avalon 841 (Stock)
|
||||||
::: pyasic.miners.avalonminer.cgminer.A8X.A841.CGMinerAvalon841
|
::: pyasic.miners.avalonminer.cgminer.A8X.A841.CGMinerAvalon841
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## Avalon 851
|
## Avalon 851 (Stock)
|
||||||
::: pyasic.miners.avalonminer.cgminer.A8X.A851.CGMinerAvalon851
|
::: pyasic.miners.avalonminer.cgminer.A8X.A851.CGMinerAvalon851
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# pyasic
|
# pyasic
|
||||||
## A9X Models
|
## A9X Models
|
||||||
|
|
||||||
## Avalon 921
|
## Avalon 921 (Stock)
|
||||||
::: pyasic.miners.avalonminer.cgminer.A9X.A921.CGMinerAvalon921
|
::: pyasic.miners.avalonminer.cgminer.A9X.A921.CGMinerAvalon921
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
|
|||||||
10
docs/miners/avalonminer/nano.md
Normal file
10
docs/miners/avalonminer/nano.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# pyasic
|
||||||
|
## nano Models
|
||||||
|
|
||||||
|
## Avalon Nano 3 (Stock)
|
||||||
|
::: pyasic.miners.avalonminer.cgminer.nano.nano3.CGMinerAvalonNano3
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
31
docs/miners/bitaxe/BM.md
Normal file
31
docs/miners/bitaxe/BM.md
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# pyasic
|
||||||
|
## BM Models
|
||||||
|
|
||||||
|
## Supra (Stock)
|
||||||
|
::: pyasic.miners.bitaxe.espminer.BM.BM1368.BitAxeSupra
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## Ultra (Stock)
|
||||||
|
::: pyasic.miners.bitaxe.espminer.BM.BM1366.BitAxeUltra
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## Max (Stock)
|
||||||
|
::: pyasic.miners.bitaxe.espminer.BM.BM1397.BitAxeMax
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## Gamma (Stock)
|
||||||
|
::: pyasic.miners.bitaxe.espminer.BM.BM1370.BitAxeGamma
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
17
docs/miners/blockminer/blockminer.md
Normal file
17
docs/miners/blockminer/blockminer.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# pyasic
|
||||||
|
## blockminer Models
|
||||||
|
|
||||||
|
## BlockMiner 520i (ePIC)
|
||||||
|
::: pyasic.miners.blockminer.epic.blockminer.blockminer.ePICBlockMiner520i
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## BlockMiner 720i (ePIC)
|
||||||
|
::: pyasic.miners.blockminer.epic.blockminer.blockminer.ePICBlockMiner720i
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
@@ -1,23 +1,24 @@
|
|||||||
# pyasic
|
# pyasic
|
||||||
## X5 Models
|
## X5 Models
|
||||||
|
|
||||||
## CK5
|
## CK5 (Stock)
|
||||||
::: pyasic.miners.goldshell.bfgminer.X5.CK5.GoldshellCK5
|
::: pyasic.miners.goldshell.bfgminer.X5.CK5.GoldshellCK5
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## HS5
|
## HS5 (Stock)
|
||||||
::: pyasic.miners.goldshell.bfgminer.X5.HS5.GoldshellHS5
|
::: pyasic.miners.goldshell.bfgminer.X5.HS5.GoldshellHS5
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## KD5
|
## KD5 (Stock)
|
||||||
::: pyasic.miners.goldshell.bfgminer.X5.KD5.GoldshellKD5
|
::: pyasic.miners.goldshell.bfgminer.X5.KD5.GoldshellKD5
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
|
|||||||
17
docs/miners/goldshell/XBox.md
Normal file
17
docs/miners/goldshell/XBox.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# pyasic
|
||||||
|
## XBox Models
|
||||||
|
|
||||||
|
## KD Box II (Stock)
|
||||||
|
::: pyasic.miners.goldshell.bfgminer.XBox.KDBox.GoldshellKDBoxII
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## KD Box Pro (Stock)
|
||||||
|
::: pyasic.miners.goldshell.bfgminer.XBox.KDBox.GoldshellKDBoxPro
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
# pyasic
|
# pyasic
|
||||||
## XMax Models
|
## XMax Models
|
||||||
|
|
||||||
## KD Max
|
## KD Max (Stock)
|
||||||
::: pyasic.miners.goldshell.bfgminer.XMax.KDMax.KDMax
|
::: pyasic.miners.goldshell.bfgminer.XMax.KDMax.GoldshellKDMax
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
|
|||||||
10
docs/miners/hammer/DX.md
Normal file
10
docs/miners/hammer/DX.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# pyasic
|
||||||
|
## DX Models
|
||||||
|
|
||||||
|
## D10 (Stock)
|
||||||
|
::: pyasic.miners.hammer.blackminer.DX.D10.HammerD10
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
66
docs/miners/iceriver/KSX.md
Normal file
66
docs/miners/iceriver/KSX.md
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
# pyasic
|
||||||
|
## KSX Models
|
||||||
|
|
||||||
|
## KS0 (Stock)
|
||||||
|
::: pyasic.miners.iceriver.iceminer.KSX.KS0.IceRiverKS0
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## KS1 (Stock)
|
||||||
|
::: pyasic.miners.iceriver.iceminer.KSX.KS1.IceRiverKS1
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## KS2 (Stock)
|
||||||
|
::: pyasic.miners.iceriver.iceminer.KSX.KS2.IceRiverKS2
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## KS3 (Stock)
|
||||||
|
::: pyasic.miners.iceriver.iceminer.KSX.KS3.IceRiverKS3
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## KS3L (Stock)
|
||||||
|
::: pyasic.miners.iceriver.iceminer.KSX.KS3.IceRiverKS3L
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## KS3M (Stock)
|
||||||
|
::: pyasic.miners.iceriver.iceminer.KSX.KS3.IceRiverKS3M
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## KS5 (Stock)
|
||||||
|
::: pyasic.miners.iceriver.iceminer.KSX.KS5.IceRiverKS5
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## KS5L (Stock)
|
||||||
|
::: pyasic.miners.iceriver.iceminer.KSX.KS5.IceRiverKS5L
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## KS5M (Stock)
|
||||||
|
::: pyasic.miners.iceriver.iceminer.KSX.KS5.IceRiverKS5M
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
# pyasic
|
# pyasic
|
||||||
## A10X Models
|
## A10X Models
|
||||||
|
|
||||||
## A10X
|
## A10X (Stock)
|
||||||
::: pyasic.miners.innosilicon.cgminer.A10X.A10X.InnosiliconA10X
|
::: pyasic.miners.innosilicon.cgminer.A10X.A10X.InnosiliconA10X
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
|
|||||||
17
docs/miners/innosilicon/A11X.md
Normal file
17
docs/miners/innosilicon/A11X.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# pyasic
|
||||||
|
## A11X Models
|
||||||
|
|
||||||
|
## A11 (Stock)
|
||||||
|
::: pyasic.miners.innosilicon.cgminer.A11X.A11.InnosiliconA11
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## A11MX (Stock)
|
||||||
|
::: pyasic.miners.innosilicon.cgminer.A11X.A11M.InnosiliconA11MX
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
# pyasic
|
# pyasic
|
||||||
## T3X Models
|
## T3X Models
|
||||||
|
|
||||||
## T3H+
|
## T3H+ (Stock)
|
||||||
::: pyasic.miners.innosilicon.cgminer.T3X.T3H.InnosiliconT3HPlus
|
::: pyasic.miners.innosilicon.cgminer.T3X.T3H.InnosiliconT3HPlus
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
# pyasic
|
# pyasic
|
||||||
## Miner Factory
|
## Miner Factory
|
||||||
|
|
||||||
[`MinerFactory`][pyasic.MinerFactory] is the way to create miner types in `pyasic`. The most important method is [`get_miner()`][pyasic.get_miner], which is mapped to [`pyasic.get_miner()`][pyasic.get_miner], and should be used from there.
|
[`MinerFactory`][pyasic.miners.factory.MinerFactory] is the way to create miner types in `pyasic`. The most important method is [`get_miner()`][pyasic.get_miner], which is mapped to [`pyasic.get_miner()`][pyasic.get_miner], and should be used from there.
|
||||||
|
|
||||||
The instance used for [`pyasic.get_miner()`][pyasic.get_miner] is `pyasic.miner_factory`.
|
The instance used for [`pyasic.get_miner()`][pyasic.get_miner] is `pyasic.miner_factory`.
|
||||||
|
|
||||||
[`MinerFactory`][pyasic.MinerFactory] also keeps a cache, which can be cleared if needed with `pyasic.miner_factory.clear_cached_miners()`.
|
[`MinerFactory`][pyasic.miners.factory.MinerFactory] also keeps a cache, which can be cleared if needed with `pyasic.miner_factory.clear_cached_miners()`.
|
||||||
|
|
||||||
Finally, there is functionality to get multiple miners without using `asyncio.gather()` explicitly. Use `pyasic.miner_factory.get_multiple_miners()` with a list of IPs as strings to get a list of miner instances. You can also get multiple miners with an `AsyncGenerator` by using `pyasic.miner_factory.get_miner_generator()`.
|
Finally, there is functionality to get multiple miners without using `asyncio.gather()` explicitly. Use `pyasic.miner_factory.get_multiple_miners()` with a list of IPs as strings to get a list of miner instances. You can also get multiple miners with an `AsyncGenerator` by using `pyasic.miner_factory.get_miner_generator()`.
|
||||||
|
|
||||||
@@ -32,5 +32,5 @@ Finally, there is functionality to get multiple miners without using `asyncio.ga
|
|||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
[`AnyMiner`][pyasic.miners.base.AnyMiner] is a placeholder type variable used for typing returns of functions.
|
[`AnyMiner`][pyasic.miners.base.AnyMiner] is a placeholder type variable used for typing returns of functions.
|
||||||
A function returning [`AnyMiner`][pyasic.miners.base.AnyMiner] will always return a subclass of [`BaseMiner`][pyasic.miners.BaseMiner],
|
A function returning [`AnyMiner`][pyasic.miners.base.AnyMiner] will always return a subclass of [`BaseMiner`][pyasic.miners.base.BaseMiner],
|
||||||
and is used to specify a function returning some arbitrary type of miner class instance.
|
and is used to specify a function returning some arbitrary type of miner class instance.
|
||||||
|
|||||||
@@ -18,67 +18,86 @@ details {
|
|||||||
<details>
|
<details>
|
||||||
<summary>X3 Series:</summary>
|
<summary>X3 Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="../antminer/X3#d3">D3</a></li>
|
<li><a href="../antminer/X3#d3-stock">D3 (Stock)</a></li>
|
||||||
<li><a href="../antminer/X3#hs3">HS3</a></li>
|
<li><a href="../antminer/X3#hs3-stock">HS3 (Stock)</a></li>
|
||||||
<li><a href="../antminer/X3#l3_1">L3+</a></li>
|
<li><a href="../antminer/X3#l3_1-stock">L3+ (Stock)</a></li>
|
||||||
|
<li><a href="../antminer/X3#ka3-stock">KA3 (Stock)</a></li>
|
||||||
|
<li><a href="../antminer/X3#ks3-stock">KS3 (Stock)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>X5 Series:</summary>
|
<summary>X5 Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="../antminer/X5#dr5">DR5</a></li>
|
<li><a href="../antminer/X5#dr5-stock">DR5 (Stock)</a></li>
|
||||||
|
<li><a href="../antminer/X5#ks5-stock">KS5 (Stock)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>X7 Series:</summary>
|
<summary>X7 Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="../antminer/X7#l7">L7</a></li>
|
<li><a href="../antminer/X7#l7-stock">L7 (Stock)</a></li>
|
||||||
|
<li><a href="../antminer/X7#k7-stock">K7 (Stock)</a></li>
|
||||||
|
<li><a href="../antminer/X7#d7-stock">D7 (Stock)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>X9 Series:</summary>
|
<summary>X9 Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="../antminer/X9#e9pro">E9Pro</a></li>
|
<li><a href="../antminer/X9#e9pro-stock">E9Pro (Stock)</a></li>
|
||||||
<li><a href="../antminer/X9#s9">S9</a></li>
|
<li><a href="../antminer/X9#d9-stock">D9 (Stock)</a></li>
|
||||||
<li><a href="../antminer/X9#s9i">S9i</a></li>
|
<li><a href="../antminer/X9#s9-stock">S9 (Stock)</a></li>
|
||||||
<li><a href="../antminer/X9#s9j">S9j</a></li>
|
<li><a href="../antminer/X9#s9i-stock">S9i (Stock)</a></li>
|
||||||
<li><a href="../antminer/X9#t9">T9</a></li>
|
<li><a href="../antminer/X9#s9j-stock">S9j (Stock)</a></li>
|
||||||
|
<li><a href="../antminer/X9#t9-stock">T9 (Stock)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>X15 Series:</summary>
|
<summary>X15 Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="../antminer/X15#z15">Z15</a></li>
|
<li><a href="../antminer/X15#z15-stock">Z15 (Stock)</a></li>
|
||||||
|
<li><a href="../antminer/X15#z15-pro-stock">Z15 Pro (Stock)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>X17 Series:</summary>
|
<summary>X17 Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="../antminer/X17#s17">S17</a></li>
|
<li><a href="../antminer/X17#s17-stock">S17 (Stock)</a></li>
|
||||||
<li><a href="../antminer/X17#s17_1">S17+</a></li>
|
<li><a href="../antminer/X17#s17_1-stock">S17+ (Stock)</a></li>
|
||||||
<li><a href="../antminer/X17#s17-pro">S17 Pro</a></li>
|
<li><a href="../antminer/X17#s17-pro-stock">S17 Pro (Stock)</a></li>
|
||||||
<li><a href="../antminer/X17#s17e">S17e</a></li>
|
<li><a href="../antminer/X17#s17e-stock">S17e (Stock)</a></li>
|
||||||
<li><a href="../antminer/X17#t17">T17</a></li>
|
<li><a href="../antminer/X17#t17-stock">T17 (Stock)</a></li>
|
||||||
<li><a href="../antminer/X17#t17_1">T17+</a></li>
|
<li><a href="../antminer/X17#t17_1-stock">T17+ (Stock)</a></li>
|
||||||
<li><a href="../antminer/X17#t17e">T17e</a></li>
|
<li><a href="../antminer/X17#t17e-stock">T17e (Stock)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>X19 Series:</summary>
|
<summary>X19 Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="../antminer/X19#s19">S19</a></li>
|
<li><a href="../antminer/X19#s19-stock">S19 (Stock)</a></li>
|
||||||
<li><a href="../antminer/X19#s19l">S19L</a></li>
|
<li><a href="../antminer/X19#s19l-stock">S19L (Stock)</a></li>
|
||||||
<li><a href="../antminer/X19#s19-pro">S19 Pro</a></li>
|
<li><a href="../antminer/X19#s19-pro-stock">S19 Pro (Stock)</a></li>
|
||||||
<li><a href="../antminer/X19#s19j">S19j</a></li>
|
<li><a href="../antminer/X19#s19j-stock">S19j (Stock)</a></li>
|
||||||
<li><a href="../antminer/X19#s19i">S19i</a></li>
|
<li><a href="../antminer/X19#s19i-stock">S19i (Stock)</a></li>
|
||||||
<li><a href="../antminer/X19#s19_1">S19+</a></li>
|
<li><a href="../antminer/X19#s19_1-stock">S19+ (Stock)</a></li>
|
||||||
<li><a href="../antminer/X19#s19j-no-pic">S19j No PIC</a></li>
|
<li><a href="../antminer/X19#s19j-no-pic-stock">S19j No PIC (Stock)</a></li>
|
||||||
<li><a href="../antminer/X19#s19-pro_1">S19 Pro+</a></li>
|
<li><a href="../antminer/X19#s19-pro_1-stock">S19 Pro+ (Stock)</a></li>
|
||||||
<li><a href="../antminer/X19#s19j-pro">S19j Pro</a></li>
|
<li><a href="../antminer/X19#s19j-pro-stock">S19j Pro (Stock)</a></li>
|
||||||
<li><a href="../antminer/X19#s19-xp">S19 XP</a></li>
|
<li><a href="../antminer/X19#s19-xp-stock">S19 XP (Stock)</a></li>
|
||||||
<li><a href="../antminer/X19#s19a">S19a</a></li>
|
<li><a href="../antminer/X19#s19a-stock">S19a (Stock)</a></li>
|
||||||
<li><a href="../antminer/X19#s19a-pro">S19a Pro</a></li>
|
<li><a href="../antminer/X19#s19a-pro-stock">S19a Pro (Stock)</a></li>
|
||||||
<li><a href="../antminer/X19#t19">T19</a></li>
|
<li><a href="../antminer/X19#s19-hydro-stock">S19 Hydro (Stock)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19-pro-hydro-stock">S19 Pro Hydro (Stock)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19-pro_1-hydro-stock">S19 Pro+ Hydro (Stock)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19k-pro-stock">S19K Pro (Stock)</a></li>
|
||||||
|
<li><a href="../antminer/X19#t19-stock">T19 (Stock)</a></li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>X21 Series:</summary>
|
||||||
|
<ul>
|
||||||
|
<li><a href="../antminer/X21#s21-stock">S21 (Stock)</a></li>
|
||||||
|
<li><a href="../antminer/X21#s21-pro-stock">S21 Pro (Stock)</a></li>
|
||||||
|
<li><a href="../antminer/X21#t21-stock">T21 (Stock)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -89,208 +108,235 @@ details {
|
|||||||
<details>
|
<details>
|
||||||
<summary>M2X Series:</summary>
|
<summary>M2X Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="../whatsminer/M2X#m20-v10">M20 V10</a></li>
|
<li><a href="../whatsminer/M2X#m20-v10-stock">M20 V10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M2X#m20s-v10">M20S V10</a></li>
|
<li><a href="../whatsminer/M2X#m20s-v10-stock">M20S V10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M2X#m20s-v20">M20S V20</a></li>
|
<li><a href="../whatsminer/M2X#m20s-v20-stock">M20S V20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M2X#m20s-v30">M20S V30</a></li>
|
<li><a href="../whatsminer/M2X#m20s-v30-stock">M20S V30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M2X#m20p-v10">M20P V10</a></li>
|
<li><a href="../whatsminer/M2X#m20p-v10-stock">M20P V10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M2X#m20p-v30">M20P V30</a></li>
|
<li><a href="../whatsminer/M2X#m20p-v30-stock">M20P V30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M2X#m20s_1-v30">M20S+ V30</a></li>
|
<li><a href="../whatsminer/M2X#m20s_1-v30-stock">M20S+ V30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M2X#m21-v10">M21 V10</a></li>
|
<li><a href="../whatsminer/M2X#m21-v10-stock">M21 V10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M2X#m21s-v20">M21S V20</a></li>
|
<li><a href="../whatsminer/M2X#m21s-v20-stock">M21S V20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M2X#m21s-v60">M21S V60</a></li>
|
<li><a href="../whatsminer/M2X#m21s-v60-stock">M21S V60 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M2X#m21s-v70">M21S V70</a></li>
|
<li><a href="../whatsminer/M2X#m21s-v70-stock">M21S V70 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M2X#m21s_1-v20">M21S+ V20</a></li>
|
<li><a href="../whatsminer/M2X#m21s_1-v20-stock">M21S+ V20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M2X#m29-v10">M29 V10</a></li>
|
<li><a href="../whatsminer/M2X#m29-v10-stock">M29 V10 (Stock)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>M3X Series:</summary>
|
<summary>M3X Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="../whatsminer/M3X#m30-v10">M30 V10</a></li>
|
<li><a href="../whatsminer/M3X#m30-v10-stock">M30 V10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30-v20">M30 V20</a></li>
|
<li><a href="../whatsminer/M3X#m30-v20-stock">M30 V20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30k-v10">M30K V10</a></li>
|
<li><a href="../whatsminer/M3X#m30k-v10-stock">M30K V10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30l-v10">M30L V10</a></li>
|
<li><a href="../whatsminer/M3X#m30l-v10-stock">M30L V10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-v10">M30S V10</a></li>
|
<li><a href="../whatsminer/M3X#m30s-v10-stock">M30S V10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-v20">M30S V20</a></li>
|
<li><a href="../whatsminer/M3X#m30s-v20-stock">M30S V20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-v30">M30S V30</a></li>
|
<li><a href="../whatsminer/M3X#m30s-v30-stock">M30S V30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-v40">M30S V40</a></li>
|
<li><a href="../whatsminer/M3X#m30s-v40-stock">M30S V40 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-v50">M30S V50</a></li>
|
<li><a href="../whatsminer/M3X#m30s-v50-stock">M30S V50 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-v60">M30S V60</a></li>
|
<li><a href="../whatsminer/M3X#m30s-v60-stock">M30S V60 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-v70">M30S V70</a></li>
|
<li><a href="../whatsminer/M3X#m30s-v70-stock">M30S V70 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-v80">M30S V80</a></li>
|
<li><a href="../whatsminer/M3X#m30s-v80-stock">M30S V80 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-ve10">M30S VE10</a></li>
|
<li><a href="../whatsminer/M3X#m30s-ve10-stock">M30S VE10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-ve20">M30S VE20</a></li>
|
<li><a href="../whatsminer/M3X#m30s-ve20-stock">M30S VE20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-ve30">M30S VE30</a></li>
|
<li><a href="../whatsminer/M3X#m30s-ve30-stock">M30S VE30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-ve40">M30S VE40</a></li>
|
<li><a href="../whatsminer/M3X#m30s-ve40-stock">M30S VE40 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-ve50">M30S VE50</a></li>
|
<li><a href="../whatsminer/M3X#m30s-ve50-stock">M30S VE50 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-ve60">M30S VE60</a></li>
|
<li><a href="../whatsminer/M3X#m30s-ve60-stock">M30S VE60 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-ve70">M30S VE70</a></li>
|
<li><a href="../whatsminer/M3X#m30s-ve70-stock">M30S VE70 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-vf10">M30S VF10</a></li>
|
<li><a href="../whatsminer/M3X#m30s-vf10-stock">M30S VF10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-vf20">M30S VF20</a></li>
|
<li><a href="../whatsminer/M3X#m30s-vf20-stock">M30S VF20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-vf30">M30S VF30</a></li>
|
<li><a href="../whatsminer/M3X#m30s-vf30-stock">M30S VF30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-vg10">M30S VG10</a></li>
|
<li><a href="../whatsminer/M3X#m30s-vg10-stock">M30S VG10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-vg20">M30S VG20</a></li>
|
<li><a href="../whatsminer/M3X#m30s-vg20-stock">M30S VG20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-vg30">M30S VG30</a></li>
|
<li><a href="../whatsminer/M3X#m30s-vg30-stock">M30S VG30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-vg40">M30S VG40</a></li>
|
<li><a href="../whatsminer/M3X#m30s-vg40-stock">M30S VG40 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-vh10">M30S VH10</a></li>
|
<li><a href="../whatsminer/M3X#m30s-vh10-stock">M30S VH10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-vh20">M30S VH20</a></li>
|
<li><a href="../whatsminer/M3X#m30s-vh20-stock">M30S VH20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-vh30">M30S VH30</a></li>
|
<li><a href="../whatsminer/M3X#m30s-vh30-stock">M30S VH30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-vh40">M30S VH40</a></li>
|
<li><a href="../whatsminer/M3X#m30s-vh40-stock">M30S VH40 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-vh50">M30S VH50</a></li>
|
<li><a href="../whatsminer/M3X#m30s-vh50-stock">M30S VH50 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-vh60">M30S VH60</a></li>
|
<li><a href="../whatsminer/M3X#m30s-vh60-stock">M30S VH60 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s-vi20">M30S VI20</a></li>
|
<li><a href="../whatsminer/M3X#m30s-vi20-stock">M30S VI20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-v10">M30S+ V10</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-v10-stock">M30S+ V10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-v20">M30S+ V20</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-v20-stock">M30S+ V20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-v30">M30S+ V30</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-v30-stock">M30S+ V30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-v40">M30S+ V40</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-v40-stock">M30S+ V40 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-v50">M30S+ V50</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-v50-stock">M30S+ V50 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-v60">M30S+ V60</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-v60-stock">M30S+ V60 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-v70">M30S+ V70</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-v70-stock">M30S+ V70 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-v80">M30S+ V80</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-v80-stock">M30S+ V80 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-v90">M30S+ V90</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-v90-stock">M30S+ V90 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-v100">M30S+ V100</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-v100-stock">M30S+ V100 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-ve30">M30S+ VE30</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-ve30-stock">M30S+ VE30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-ve40">M30S+ VE40</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-ve40-stock">M30S+ VE40 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-ve50">M30S+ VE50</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-ve50-stock">M30S+ VE50 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-ve60">M30S+ VE60</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-ve60-stock">M30S+ VE60 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-ve70">M30S+ VE70</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-ve70-stock">M30S+ VE70 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-ve80">M30S+ VE80</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-ve80-stock">M30S+ VE80 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-ve90">M30S+ VE90</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-ve90-stock">M30S+ VE90 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-ve100">M30S+ VE100</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-ve100-stock">M30S+ VE100 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-vf20">M30S+ VF20</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-vf20-stock">M30S+ VF20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-vf30">M30S+ VF30</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-vf30-stock">M30S+ VF30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-vg20">M30S+ VG20</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-vg20-stock">M30S+ VG20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-vg30">M30S+ VG30</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-vg30-stock">M30S+ VG30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-vg40">M30S+ VG40</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-vg40-stock">M30S+ VG40 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-vg50">M30S+ VG50</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-vg50-stock">M30S+ VG50 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-vg60">M30S+ VG60</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-vg60-stock">M30S+ VG60 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-vh10">M30S+ VH10</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-vh10-stock">M30S+ VH10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-vh20">M30S+ VH20</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-vh20-stock">M30S+ VH20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-vh30">M30S+ VH30</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-vh30-stock">M30S+ VH30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-vh40">M30S+ VH40</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-vh40-stock">M30S+ VH40 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-vh50">M30S+ VH50</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-vh50-stock">M30S+ VH50 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1-vh60">M30S+ VH60</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1-vh60-stock">M30S+ VH60 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1_1-v10">M30S++ V10</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1_1-v10-stock">M30S++ V10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1_1-v20">M30S++ V20</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1_1-v20-stock">M30S++ V20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1_1-ve30">M30S++ VE30</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1_1-ve30-stock">M30S++ VE30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1_1-ve40">M30S++ VE40</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1_1-ve40-stock">M30S++ VE40 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1_1-ve50">M30S++ VE50</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1_1-ve50-stock">M30S++ VE50 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1_1-vf40">M30S++ VF40</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1_1-vf40-stock">M30S++ VF40 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1_1-vg30">M30S++ VG30</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1_1-vg30-stock">M30S++ VG30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1_1-vg40">M30S++ VG40</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1_1-vg40-stock">M30S++ VG40 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1_1-vg50">M30S++ VG50</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1_1-vg50-stock">M30S++ VG50 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1_1-vh10">M30S++ VH10</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1_1-vh10-stock">M30S++ VH10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1_1-vh20">M30S++ VH20</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1_1-vh20-stock">M30S++ VH20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1_1-vh30">M30S++ VH30</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1_1-vh30-stock">M30S++ VH30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1_1-vh40">M30S++ VH40</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1_1-vh40-stock">M30S++ VH40 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1_1-vh50">M30S++ VH50</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1_1-vh50-stock">M30S++ VH50 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1_1-vh60">M30S++ VH60</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1_1-vh60-stock">M30S++ VH60 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1_1-vh70">M30S++ VH70</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1_1-vh70-stock">M30S++ VH70 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1_1-vh80">M30S++ VH80</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1_1-vh80-stock">M30S++ VH80 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1_1-vh90">M30S++ VH90</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1_1-vh90-stock">M30S++ VH90 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1_1-vh100">M30S++ VH100</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1_1-vh100-stock">M30S++ VH100 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1_1-vj20">M30S++ VJ20</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1_1-vj20-stock">M30S++ VJ20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30s_1_1-vj30">M30S++ VJ30</a></li>
|
<li><a href="../whatsminer/M3X#m30s_1_1-vj30-stock">M30S++ VJ30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31-v10">M31 V10</a></li>
|
<li><a href="../whatsminer/M3X#m31-v10-stock">M31 V10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31-v20">M31 V20</a></li>
|
<li><a href="../whatsminer/M3X#m31-v20-stock">M31 V20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31h-v10">M31H V10</a></li>
|
<li><a href="../whatsminer/M3X#m31h-v10-stock">M31H V10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31h-v40">M31H V40</a></li>
|
<li><a href="../whatsminer/M3X#m31h-v40-stock">M31H V40 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m30l-v10">M30L V10</a></li>
|
<li><a href="../whatsminer/M3X#m30l-v10-stock">M30L V10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s-v10">M31S V10</a></li>
|
<li><a href="../whatsminer/M3X#m31s-v10-stock">M31S V10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s-v20">M31S V20</a></li>
|
<li><a href="../whatsminer/M3X#m31s-v20-stock">M31S V20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s-v30">M31S V30</a></li>
|
<li><a href="../whatsminer/M3X#m31s-v30-stock">M31S V30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s-v40">M31S V40</a></li>
|
<li><a href="../whatsminer/M3X#m31s-v40-stock">M31S V40 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s-v50">M31S V50</a></li>
|
<li><a href="../whatsminer/M3X#m31s-v50-stock">M31S V50 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s-v60">M31S V60</a></li>
|
<li><a href="../whatsminer/M3X#m31s-v60-stock">M31S V60 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s-v70">M31S V70</a></li>
|
<li><a href="../whatsminer/M3X#m31s-v70-stock">M31S V70 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s-v80">M31S V80</a></li>
|
<li><a href="../whatsminer/M3X#m31s-v80-stock">M31S V80 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s-v90">M31S V90</a></li>
|
<li><a href="../whatsminer/M3X#m31s-v90-stock">M31S V90 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s-ve10">M31S VE10</a></li>
|
<li><a href="../whatsminer/M3X#m31s-ve10-stock">M31S VE10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s-ve20">M31S VE20</a></li>
|
<li><a href="../whatsminer/M3X#m31s-ve20-stock">M31S VE20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s-ve30">M31S VE30</a></li>
|
<li><a href="../whatsminer/M3X#m31s-ve30-stock">M31S VE30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31se-v10">M31SE V10</a></li>
|
<li><a href="../whatsminer/M3X#m31se-v10-stock">M31SE V10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31se-v20">M31SE V20</a></li>
|
<li><a href="../whatsminer/M3X#m31se-v20-stock">M31SE V20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31se-v30">M31SE V30</a></li>
|
<li><a href="../whatsminer/M3X#m31se-v30-stock">M31SE V30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s_1-v10">M31S+ V10</a></li>
|
<li><a href="../whatsminer/M3X#m31s_1-v10-stock">M31S+ V10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s_1-v20">M31S+ V20</a></li>
|
<li><a href="../whatsminer/M3X#m31s_1-v20-stock">M31S+ V20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s_1-v30">M31S+ V30</a></li>
|
<li><a href="../whatsminer/M3X#m31s_1-v30-stock">M31S+ V30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s_1-v40">M31S+ V40</a></li>
|
<li><a href="../whatsminer/M3X#m31s_1-v40-stock">M31S+ V40 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s_1-v50">M31S+ V50</a></li>
|
<li><a href="../whatsminer/M3X#m31s_1-v50-stock">M31S+ V50 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s_1-v60">M31S+ V60</a></li>
|
<li><a href="../whatsminer/M3X#m31s_1-v60-stock">M31S+ V60 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s_1-v80">M31S+ V80</a></li>
|
<li><a href="../whatsminer/M3X#m31s_1-v80-stock">M31S+ V80 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s_1-v90">M31S+ V90</a></li>
|
<li><a href="../whatsminer/M3X#m31s_1-v90-stock">M31S+ V90 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s_1-v100">M31S+ V100</a></li>
|
<li><a href="../whatsminer/M3X#m31s_1-v100-stock">M31S+ V100 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s_1-ve10">M31S+ VE10</a></li>
|
<li><a href="../whatsminer/M3X#m31s_1-ve10-stock">M31S+ VE10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s_1-ve20">M31S+ VE20</a></li>
|
<li><a href="../whatsminer/M3X#m31s_1-ve20-stock">M31S+ VE20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s_1-ve30">M31S+ VE30</a></li>
|
<li><a href="../whatsminer/M3X#m31s_1-ve30-stock">M31S+ VE30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s_1-ve40">M31S+ VE40</a></li>
|
<li><a href="../whatsminer/M3X#m31s_1-ve40-stock">M31S+ VE40 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s_1-ve50">M31S+ VE50</a></li>
|
<li><a href="../whatsminer/M3X#m31s_1-ve50-stock">M31S+ VE50 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s_1-ve60">M31S+ VE60</a></li>
|
<li><a href="../whatsminer/M3X#m31s_1-ve60-stock">M31S+ VE60 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s_1-ve80">M31S+ VE80</a></li>
|
<li><a href="../whatsminer/M3X#m31s_1-ve80-stock">M31S+ VE80 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s_1-vf20">M31S+ VF20</a></li>
|
<li><a href="../whatsminer/M3X#m31s_1-vf20-stock">M31S+ VF20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s_1-vf30">M31S+ VF30</a></li>
|
<li><a href="../whatsminer/M3X#m31s_1-vf30-stock">M31S+ VF30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s_1-vg20">M31S+ VG20</a></li>
|
<li><a href="../whatsminer/M3X#m31s_1-vg20-stock">M31S+ VG20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m31s_1-vg30">M31S+ VG30</a></li>
|
<li><a href="../whatsminer/M3X#m31s_1-vg30-stock">M31S+ VG30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m32-v10">M32 V10</a></li>
|
<li><a href="../whatsminer/M3X#m32-v10-stock">M32 V10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m32-v20">M32 V20</a></li>
|
<li><a href="../whatsminer/M3X#m32-v20-stock">M32 V20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m33-v10">M33 V10</a></li>
|
<li><a href="../whatsminer/M3X#m33-v10-stock">M33 V10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m33-v20">M33 V20</a></li>
|
<li><a href="../whatsminer/M3X#m33-v20-stock">M33 V20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m33-v30">M33 V30</a></li>
|
<li><a href="../whatsminer/M3X#m33-v30-stock">M33 V30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m33s-vg30">M33S VG30</a></li>
|
<li><a href="../whatsminer/M3X#m33s-vg30-stock">M33S VG30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m33s_1-vg20">M33S+ VG20</a></li>
|
<li><a href="../whatsminer/M3X#m33s_1-vg20-stock">M33S+ VG20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m33s_1-vh20">M33S+ VH20</a></li>
|
<li><a href="../whatsminer/M3X#m33s_1-vh20-stock">M33S+ VH20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m33s_1-vh30">M33S+ VH30</a></li>
|
<li><a href="../whatsminer/M3X#m33s_1-vh30-stock">M33S+ VH30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m33s_1_1-vh20">M33S++ VH20</a></li>
|
<li><a href="../whatsminer/M3X#m33s_1_1-vh20-stock">M33S++ VH20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m33s_1_1-vh30">M33S++ VH30</a></li>
|
<li><a href="../whatsminer/M3X#m33s_1_1-vh30-stock">M33S++ VH30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m33s_1_1-vg40">M33S++ VG40</a></li>
|
<li><a href="../whatsminer/M3X#m33s_1_1-vg40-stock">M33S++ VG40 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m34s_1-ve10">M34S+ VE10</a></li>
|
<li><a href="../whatsminer/M3X#m34s_1-ve10-stock">M34S+ VE10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m36s-ve10">M36S VE10</a></li>
|
<li><a href="../whatsminer/M3X#m36s-ve10-stock">M36S VE10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m36s_1-vg30">M36S+ VG30</a></li>
|
<li><a href="../whatsminer/M3X#m36s_1-vg30-stock">M36S+ VG30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m36s_1_1-vh30">M36S++ VH30</a></li>
|
<li><a href="../whatsminer/M3X#m36s_1_1-vh30-stock">M36S++ VH30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m39-v10">M39 V10</a></li>
|
<li><a href="../whatsminer/M3X#m39-v10-stock">M39 V10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m39-v20">M39 V20</a></li>
|
<li><a href="../whatsminer/M3X#m39-v20-stock">M39 V20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M3X#m39-v30">M39 V30</a></li>
|
<li><a href="../whatsminer/M3X#m39-v30-stock">M39 V30 (Stock)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>M5X Series:</summary>
|
<summary>M5X Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="../whatsminer/M5X#m50-ve30">M50 VE30</a></li>
|
<li><a href="../whatsminer/M5X#m50-ve30-stock">M50 VE30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m50-vg30">M50 VG30</a></li>
|
<li><a href="../whatsminer/M5X#m50-vg30-stock">M50 VG30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m50-vh10">M50 VH10</a></li>
|
<li><a href="../whatsminer/M5X#m50-vh10-stock">M50 VH10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m50-vh20">M50 VH20</a></li>
|
<li><a href="../whatsminer/M5X#m50-vh20-stock">M50 VH20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m50-vh30">M50 VH30</a></li>
|
<li><a href="../whatsminer/M5X#m50-vh30-stock">M50 VH30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m50-vh40">M50 VH40</a></li>
|
<li><a href="../whatsminer/M5X#m50-vh40-stock">M50 VH40 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m50-vh50">M50 VH50</a></li>
|
<li><a href="../whatsminer/M5X#m50-vh50-stock">M50 VH50 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m50-vh60">M50 VH60</a></li>
|
<li><a href="../whatsminer/M5X#m50-vh60-stock">M50 VH60 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m50-vh70">M50 VH70</a></li>
|
<li><a href="../whatsminer/M5X#m50-vh70-stock">M50 VH70 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m50-vh80">M50 VH80</a></li>
|
<li><a href="../whatsminer/M5X#m50-vh80-stock">M50 VH80 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m50-vj10">M50 VJ10</a></li>
|
<li><a href="../whatsminer/M5X#m50-vh90-stock">M50 VH90 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m50-vj20">M50 VJ20</a></li>
|
<li><a href="../whatsminer/M5X#m50-vj10-stock">M50 VJ10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m50-vj30">M50 VJ30</a></li>
|
<li><a href="../whatsminer/M5X#m50-vj20-stock">M50 VJ20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m50s-vj10">M50S VJ10</a></li>
|
<li><a href="../whatsminer/M5X#m50-vj30-stock">M50 VJ30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m50s-vj20">M50S VJ20</a></li>
|
<li><a href="../whatsminer/M5X#m50s-vj10-stock">M50S VJ10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m50s-vj30">M50S VJ30</a></li>
|
<li><a href="../whatsminer/M5X#m50s-vj20-stock">M50S VJ20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m50s-vh10">M50S VH10</a></li>
|
<li><a href="../whatsminer/M5X#m50s-vj30-stock">M50S VJ30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m50s-vh20">M50S VH20</a></li>
|
<li><a href="../whatsminer/M5X#m50s-vh10-stock">M50S VH10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m50s-vh30">M50S VH30</a></li>
|
<li><a href="../whatsminer/M5X#m50s-vh20-stock">M50S VH20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m50s-vh40">M50S VH40</a></li>
|
<li><a href="../whatsminer/M5X#m50s-vh30-stock">M50S VH30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m50s-vh50">M50S VH50</a></li>
|
<li><a href="../whatsminer/M5X#m50s-vh40-stock">M50S VH40 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m50s_1-vh30">M50S+ VH30</a></li>
|
<li><a href="../whatsminer/M5X#m50s-vh50-stock">M50S VH50 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m50s_1-vh40">M50S+ VH40</a></li>
|
<li><a href="../whatsminer/M5X#m50s_1-vh30-stock">M50S+ VH30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m50s_1-vj30">M50S+ VJ30</a></li>
|
<li><a href="../whatsminer/M5X#m50s_1-vh40-stock">M50S+ VH40 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m50s_1-vk20">M50S+ VK20</a></li>
|
<li><a href="../whatsminer/M5X#m50s_1-vj30-stock">M50S+ VJ30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m50s_1_1-vk10">M50S++ VK10</a></li>
|
<li><a href="../whatsminer/M5X#m50s_1-vk20-stock">M50S+ VK20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m50s_1_1-vk20">M50S++ VK20</a></li>
|
<li><a href="../whatsminer/M5X#m50s_1_1-vk10-stock">M50S++ VK10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m50s_1_1-vk30">M50S++ VK30</a></li>
|
<li><a href="../whatsminer/M5X#m50s_1_1-vk20-stock">M50S++ VK20 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m53-vh30">M53 VH30</a></li>
|
<li><a href="../whatsminer/M5X#m50s_1_1-vk30-stock">M50S++ VK30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m53s-vh30">M53S VH30</a></li>
|
<li><a href="../whatsminer/M5X#m53-vh30-stock">M53 VH30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m53s_1-vj30">M53S+ VJ30</a></li>
|
<li><a href="../whatsminer/M5X#m53s-vh30-stock">M53S VH30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m56-vh30">M56 VH30</a></li>
|
<li><a href="../whatsminer/M5X#m53s-vj40-stock">M53S VJ40 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m56s-vh30">M56S VH30</a></li>
|
<li><a href="../whatsminer/M5X#m53s_1-vj30-stock">M53S+ VJ30 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m56s_1-vj30">M56S+ VJ30</a></li>
|
<li><a href="../whatsminer/M5X#m53s_1_1-vk10-stock">M53S++ VK10 (Stock)</a></li>
|
||||||
<li><a href="../whatsminer/M5X#m59-vh30">M59 VH30</a></li>
|
<li><a href="../whatsminer/M5X#m56-vh30-stock">M56 VH30 (Stock)</a></li>
|
||||||
|
<li><a href="../whatsminer/M5X#m56s-vh30-stock">M56S VH30 (Stock)</a></li>
|
||||||
|
<li><a href="../whatsminer/M5X#m56s_1-vj30-stock">M56S+ VJ30 (Stock)</a></li>
|
||||||
|
<li><a href="../whatsminer/M5X#m59-vh30-stock">M59 VH30 (Stock)</a></li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>M6X Series:</summary>
|
||||||
|
<ul>
|
||||||
|
<li><a href="../whatsminer/M6X#m60-vk10-stock">M60 VK10 (Stock)</a></li>
|
||||||
|
<li><a href="../whatsminer/M6X#m60-vk20-stock">M60 VK20 (Stock)</a></li>
|
||||||
|
<li><a href="../whatsminer/M6X#m60-vk30-stock">M60 VK30 (Stock)</a></li>
|
||||||
|
<li><a href="../whatsminer/M6X#m60-vk40-stock">M60 VK40 (Stock)</a></li>
|
||||||
|
<li><a href="../whatsminer/M6X#m60s-vk10-stock">M60S VK10 (Stock)</a></li>
|
||||||
|
<li><a href="../whatsminer/M6X#m60s-vk20-stock">M60S VK20 (Stock)</a></li>
|
||||||
|
<li><a href="../whatsminer/M6X#m60s-vk30-stock">M60S VK30 (Stock)</a></li>
|
||||||
|
<li><a href="../whatsminer/M6X#m60s-vk40-stock">M60S VK40 (Stock)</a></li>
|
||||||
|
<li><a href="../whatsminer/M6X#m63-vk10-stock">M63 VK10 (Stock)</a></li>
|
||||||
|
<li><a href="../whatsminer/M6X#m63-vk20-stock">M63 VK20 (Stock)</a></li>
|
||||||
|
<li><a href="../whatsminer/M6X#m63-vk30-stock">M63 VK30 (Stock)</a></li>
|
||||||
|
<li><a href="../whatsminer/M6X#m63s-vk10-stock">M63S VK10 (Stock)</a></li>
|
||||||
|
<li><a href="../whatsminer/M6X#m63s-vk20-stock">M63S VK20 (Stock)</a></li>
|
||||||
|
<li><a href="../whatsminer/M6X#m63s-vk30-stock">M63S VK30 (Stock)</a></li>
|
||||||
|
<li><a href="../whatsminer/M6X#m66-vk20-stock">M66 VK20 (Stock)</a></li>
|
||||||
|
<li><a href="../whatsminer/M6X#m66-vk30-stock">M66 VK30 (Stock)</a></li>
|
||||||
|
<li><a href="../whatsminer/M6X#m66s-vk20-stock">M66S VK20 (Stock)</a></li>
|
||||||
|
<li><a href="../whatsminer/M6X#m66s-vk30-stock">M66S VK30 (Stock)</a></li>
|
||||||
|
<li><a href="../whatsminer/M6X#m66s-vk40-stock">M66S VK40 (Stock)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -301,43 +347,49 @@ details {
|
|||||||
<details>
|
<details>
|
||||||
<summary>A7X Series:</summary>
|
<summary>A7X Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="../avalonminer/A7X#avalon-721">Avalon 721</a></li>
|
<li><a href="../avalonminer/A7X#avalon-721-stock">Avalon 721 (Stock)</a></li>
|
||||||
<li><a href="../avalonminer/A7X#avalon-741">Avalon 741</a></li>
|
<li><a href="../avalonminer/A7X#avalon-741-stock">Avalon 741 (Stock)</a></li>
|
||||||
<li><a href="../avalonminer/A7X#avalon-761">Avalon 761</a></li>
|
<li><a href="../avalonminer/A7X#avalon-761-stock">Avalon 761 (Stock)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>A8X Series:</summary>
|
<summary>A8X Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="../avalonminer/A8X#avalon-821">Avalon 821</a></li>
|
<li><a href="../avalonminer/A8X#avalon-821-stock">Avalon 821 (Stock)</a></li>
|
||||||
<li><a href="../avalonminer/A8X#avalon-841">Avalon 841</a></li>
|
<li><a href="../avalonminer/A8X#avalon-841-stock">Avalon 841 (Stock)</a></li>
|
||||||
<li><a href="../avalonminer/A8X#avalon-851">Avalon 851</a></li>
|
<li><a href="../avalonminer/A8X#avalon-851-stock">Avalon 851 (Stock)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>A9X Series:</summary>
|
<summary>A9X Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="../avalonminer/A9X#avalon-921">Avalon 921</a></li>
|
<li><a href="../avalonminer/A9X#avalon-921-stock">Avalon 921 (Stock)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>A10X Series:</summary>
|
<summary>A10X Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="../avalonminer/A10X#avalon-1026">Avalon 1026</a></li>
|
<li><a href="../avalonminer/A10X#avalon-1026-stock">Avalon 1026 (Stock)</a></li>
|
||||||
<li><a href="../avalonminer/A10X#avalon-1047">Avalon 1047</a></li>
|
<li><a href="../avalonminer/A10X#avalon-1047-stock">Avalon 1047 (Stock)</a></li>
|
||||||
<li><a href="../avalonminer/A10X#avalon-1066">Avalon 1066</a></li>
|
<li><a href="../avalonminer/A10X#avalon-1066-stock">Avalon 1066 (Stock)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>A11X Series:</summary>
|
<summary>A11X Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="../avalonminer/A11X#avalon-1166-pro">Avalon 1166 Pro</a></li>
|
<li><a href="../avalonminer/A11X#avalon-1166-pro-stock">Avalon 1166 Pro (Stock)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>A12X Series:</summary>
|
<summary>A12X Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="../avalonminer/A12X#avalon-1246">Avalon 1246</a></li>
|
<li><a href="../avalonminer/A12X#avalon-1246-stock">Avalon 1246 (Stock)</a></li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>nano Series:</summary>
|
||||||
|
<ul>
|
||||||
|
<li><a href="../avalonminer/nano#avalon-nano-3-stock">Avalon Nano 3 (Stock)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -348,13 +400,20 @@ details {
|
|||||||
<details>
|
<details>
|
||||||
<summary>T3X Series:</summary>
|
<summary>T3X Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="../innosilicon/T3X#t3h_1">T3H+</a></li>
|
<li><a href="../innosilicon/T3X#t3h_1-stock">T3H+ (Stock)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>A10X Series:</summary>
|
<summary>A10X Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="../innosilicon/A10X#a10x">A10X</a></li>
|
<li><a href="../innosilicon/A10X#a10x-stock">A10X (Stock)</a></li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>A11X Series:</summary>
|
||||||
|
<ul>
|
||||||
|
<li><a href="../innosilicon/A11X#a11-stock">A11 (Stock)</a></li>
|
||||||
|
<li><a href="../innosilicon/A11X#a11mx-stock">A11MX (Stock)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -365,15 +424,22 @@ details {
|
|||||||
<details>
|
<details>
|
||||||
<summary>X5 Series:</summary>
|
<summary>X5 Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="../goldshell/X5#ck5">CK5</a></li>
|
<li><a href="../goldshell/X5#ck5-stock">CK5 (Stock)</a></li>
|
||||||
<li><a href="../goldshell/X5#hs5">HS5</a></li>
|
<li><a href="../goldshell/X5#hs5-stock">HS5 (Stock)</a></li>
|
||||||
<li><a href="../goldshell/X5#kd5">KD5</a></li>
|
<li><a href="../goldshell/X5#kd5-stock">KD5 (Stock)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>XMax Series:</summary>
|
<summary>XMax Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="../goldshell/XMax#kd-max">KD Max</a></li>
|
<li><a href="../goldshell/XMax#kd-max-stock">KD Max (Stock)</a></li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>XBox Series:</summary>
|
||||||
|
<ul>
|
||||||
|
<li><a href="../goldshell/XBox#kd-box-ii-stock">KD Box II (Stock)</a></li>
|
||||||
|
<li><a href="../goldshell/XBox#kd-box-pro-stock">KD Box Pro (Stock)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -384,31 +450,48 @@ details {
|
|||||||
<details>
|
<details>
|
||||||
<summary>X9 Series:</summary>
|
<summary>X9 Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="../antminer/X9#s9-bos">S9 (BOS)</a></li>
|
<li><a href="../antminer/X9#s9-bos_1">S9 (BOS+)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>X17 Series:</summary>
|
<summary>X17 Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="../antminer/X17#s17-bos">S17 (BOS)</a></li>
|
<li><a href="../antminer/X17#s17-bos_1">S17 (BOS+)</a></li>
|
||||||
<li><a href="../antminer/X17#s17_1-bos">S17+ (BOS)</a></li>
|
<li><a href="../antminer/X17#s17_1-bos_1">S17+ (BOS+)</a></li>
|
||||||
<li><a href="../antminer/X17#s17-pro-bos">S17 Pro (BOS)</a></li>
|
<li><a href="../antminer/X17#s17-pro-bos_1">S17 Pro (BOS+)</a></li>
|
||||||
<li><a href="../antminer/X17#s17e-bos">S17e (BOS)</a></li>
|
<li><a href="../antminer/X17#s17e-bos_1">S17e (BOS+)</a></li>
|
||||||
<li><a href="../antminer/X17#t17-bos">T17 (BOS)</a></li>
|
<li><a href="../antminer/X17#t17-bos_1">T17 (BOS+)</a></li>
|
||||||
<li><a href="../antminer/X17#t17_1-bos">T17+ (BOS)</a></li>
|
<li><a href="../antminer/X17#t17_1-bos_1">T17+ (BOS+)</a></li>
|
||||||
<li><a href="../antminer/X17#t17e-bos">T17e (BOS)</a></li>
|
<li><a href="../antminer/X17#t17e-bos_1">T17e (BOS+)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>X19 Series:</summary>
|
<summary>X19 Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="../antminer/X19#s19-bos">S19 (BOS)</a></li>
|
<li><a href="../antminer/X19#s19-bos_1">S19 (BOS+)</a></li>
|
||||||
<li><a href="../antminer/X19#s19-pro-bos">S19 Pro (BOS)</a></li>
|
<li><a href="../antminer/X19#s19_1-bos_1">S19+ (BOS+)</a></li>
|
||||||
<li><a href="../antminer/X19#s19j-bos">S19j (BOS)</a></li>
|
<li><a href="../antminer/X19#s19-pro-bos_1">S19 Pro (BOS+)</a></li>
|
||||||
<li><a href="../antminer/X19#s19j-no-pic-bos">S19j No PIC (BOS)</a></li>
|
<li><a href="../antminer/X19#s19a-bos_1">S19a (BOS+)</a></li>
|
||||||
<li><a href="../antminer/X19#s19j-pro-bos">S19j Pro (BOS)</a></li>
|
<li><a href="../antminer/X19#s19a-pro-bos_1">S19a Pro (BOS+)</a></li>
|
||||||
<li><a href="../antminer/X19#s19j-pro-bos">S19j Pro (BOS)</a></li>
|
<li><a href="../antminer/X19#s19j-bos_1">S19j (BOS+)</a></li>
|
||||||
<li><a href="../antminer/X19#t19-bos">T19 (BOS)</a></li>
|
<li><a href="../antminer/X19#s19j-no-pic-bos_1">S19j No PIC (BOS+)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19j-pro-bos_1">S19j Pro (BOS+)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19j-pro-no-pic-bos_1">S19j Pro No PIC (BOS+)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19j-pro_1-bos_1">S19j Pro+ (BOS+)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19j-pro_1-bos_1">S19j Pro+ (BOS+)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19j-pro_1-no-pic-bos_1">S19j Pro+ No PIC (BOS+)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19k-pro-no-pic-bos_1">S19k Pro No PIC (BOS+)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19k-pro-no-pic-bos_1">S19k Pro No PIC (BOS+)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19-xp-bos_1">S19 XP (BOS+)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19-pro_1-hydro-bos_1">S19 Pro+ Hydro (BOS+)</a></li>
|
||||||
|
<li><a href="../antminer/X19#t19-bos_1">T19 (BOS+)</a></li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>X21 Series:</summary>
|
||||||
|
<ul>
|
||||||
|
<li><a href="../antminer/X21#s21-bos_1">S21 (BOS+)</a></li>
|
||||||
|
<li><a href="../antminer/X21#t21-bos_1">T21 (BOS+)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -420,6 +503,13 @@ details {
|
|||||||
<summary>X3 Series:</summary>
|
<summary>X3 Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="../antminer/X3#l3_1-vnish">L3+ (VNish)</a></li>
|
<li><a href="../antminer/X3#l3_1-vnish">L3+ (VNish)</a></li>
|
||||||
|
<li><a href="../antminer/X3#l3_1-vnish">L3+ (VNish)</a></li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>X7 Series:</summary>
|
||||||
|
<ul>
|
||||||
|
<li><a href="../antminer/X7#l7-vnish">L7 (VNish)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
@@ -437,11 +527,19 @@ details {
|
|||||||
<li><a href="../antminer/X19#s19-pro-vnish">S19 Pro (VNish)</a></li>
|
<li><a href="../antminer/X19#s19-pro-vnish">S19 Pro (VNish)</a></li>
|
||||||
<li><a href="../antminer/X19#s19j-vnish">S19j (VNish)</a></li>
|
<li><a href="../antminer/X19#s19j-vnish">S19j (VNish)</a></li>
|
||||||
<li><a href="../antminer/X19#s19j-pro-vnish">S19j Pro (VNish)</a></li>
|
<li><a href="../antminer/X19#s19j-pro-vnish">S19j Pro (VNish)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19j-pro-vnish">S19j Pro (VNish)</a></li>
|
||||||
<li><a href="../antminer/X19#s19a-vnish">S19a (VNish)</a></li>
|
<li><a href="../antminer/X19#s19a-vnish">S19a (VNish)</a></li>
|
||||||
<li><a href="../antminer/X19#s19a-pro-vnish">S19a Pro (VNish)</a></li>
|
<li><a href="../antminer/X19#s19a-pro-vnish">S19a Pro (VNish)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19-pro-hydro-vnish">S19 Pro Hydro (VNish)</a></li>
|
||||||
<li><a href="../antminer/X19#t19-vnish">T19 (VNish)</a></li>
|
<li><a href="../antminer/X19#t19-vnish">T19 (VNish)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>X21 Series:</summary>
|
||||||
|
<ul>
|
||||||
|
<li><a href="../antminer/X21#s21-vnish">S21 (VNish)</a></li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
@@ -454,9 +552,26 @@ details {
|
|||||||
<li><a href="../antminer/X19#s19-pro-epic">S19 Pro (ePIC)</a></li>
|
<li><a href="../antminer/X19#s19-pro-epic">S19 Pro (ePIC)</a></li>
|
||||||
<li><a href="../antminer/X19#s19j-epic">S19j (ePIC)</a></li>
|
<li><a href="../antminer/X19#s19j-epic">S19j (ePIC)</a></li>
|
||||||
<li><a href="../antminer/X19#s19j-pro-epic">S19j Pro (ePIC)</a></li>
|
<li><a href="../antminer/X19#s19j-pro-epic">S19j Pro (ePIC)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19j-pro_1-epic">S19j Pro+ (ePIC)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19k-pro-epic">S19k Pro (ePIC)</a></li>
|
||||||
<li><a href="../antminer/X19#s19-xp-epic">S19 XP (ePIC)</a></li>
|
<li><a href="../antminer/X19#s19-xp-epic">S19 XP (ePIC)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>X21 Series:</summary>
|
||||||
|
<ul>
|
||||||
|
<li><a href="../antminer/X21#s21-epic">S21 (ePIC)</a></li>
|
||||||
|
<li><a href="../antminer/X21#s21-pro-epic">S21 Pro (ePIC)</a></li>
|
||||||
|
<li><a href="../antminer/X21#t21-epic">T21 (ePIC)</a></li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>blockminer Series:</summary>
|
||||||
|
<ul>
|
||||||
|
<li><a href="../blockminer/blockminer#blockminer-520i-epic">BlockMiner 520i (ePIC)</a></li>
|
||||||
|
<li><a href="../blockminer/blockminer#blockminer-720i-epic">BlockMiner 720i (ePIC)</a></li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
@@ -465,7 +580,13 @@ details {
|
|||||||
<details>
|
<details>
|
||||||
<summary>X9 Series:</summary>
|
<summary>X9 Series:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="../antminer/X9#t9-hiveon">T9 (Hiveon)</a></li>
|
<li><a href="../antminer/X9#t9-stock">T9 (Stock)</a></li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>X19 Series:</summary>
|
||||||
|
<ul>
|
||||||
|
<li><a href="../antminer/X19#s19j-pro-stock">S19j Pro (Stock)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -479,5 +600,118 @@ details {
|
|||||||
<li><a href="../antminer/X9#s9-luxos">S9 (LuxOS)</a></li>
|
<li><a href="../antminer/X9#s9-luxos">S9 (LuxOS)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>X19 Series:</summary>
|
||||||
|
<ul>
|
||||||
|
<li><a href="../antminer/X19#s19-luxos">S19 (LuxOS)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19-pro-luxos">S19 Pro (LuxOS)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19j-pro-luxos">S19j Pro (LuxOS)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19j-pro_1-luxos">S19j Pro+ (LuxOS)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19k-pro-luxos">S19k Pro (LuxOS)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19-xp-luxos">S19 XP (LuxOS)</a></li>
|
||||||
|
<li><a href="../antminer/X19#t19-luxos">T19 (LuxOS)</a></li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>X21 Series:</summary>
|
||||||
|
<ul>
|
||||||
|
<li><a href="../antminer/X21#s21-luxos">S21 (LuxOS)</a></li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>Stock Firmware Auradine Miners:</summary>
|
||||||
|
<ul>
|
||||||
|
<details>
|
||||||
|
<summary>AD Series:</summary>
|
||||||
|
<ul>
|
||||||
|
<li><a href="../auradine/AD#at1500-stock">AT1500 (Stock)</a></li>
|
||||||
|
<li><a href="../auradine/AD#at2860-stock">AT2860 (Stock)</a></li>
|
||||||
|
<li><a href="../auradine/AD#at2880-stock">AT2880 (Stock)</a></li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>AI Series:</summary>
|
||||||
|
<ul>
|
||||||
|
<li><a href="../auradine/AI#ai2500-stock">AI2500 (Stock)</a></li>
|
||||||
|
<li><a href="../auradine/AI#ai3680-stock">AI3680 (Stock)</a></li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>AT Series:</summary>
|
||||||
|
<ul>
|
||||||
|
<li><a href="../auradine/AT#ad2500-stock">AD2500 (Stock)</a></li>
|
||||||
|
<li><a href="../auradine/AT#ad3500-stock">AD3500 (Stock)</a></li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>Mara Firmware Miners:</summary>
|
||||||
|
<ul>
|
||||||
|
<details>
|
||||||
|
<summary>X19 Series:</summary>
|
||||||
|
<ul>
|
||||||
|
<li><a href="../antminer/X19#s19-marafw">S19 (MaraFW)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19-pro-marafw">S19 Pro (MaraFW)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19j-marafw">S19j (MaraFW)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19j-no-pic-marafw">S19j No PIC (MaraFW)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19j-pro-marafw">S19j Pro (MaraFW)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19-xp-marafw">S19 XP (MaraFW)</a></li>
|
||||||
|
<li><a href="../antminer/X19#s19k-pro-marafw">S19K Pro (MaraFW)</a></li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>X21 Series:</summary>
|
||||||
|
<ul>
|
||||||
|
<li><a href="../antminer/X21#s21-marafw">S21 (MaraFW)</a></li>
|
||||||
|
<li><a href="../antminer/X21#t21-marafw">T21 (MaraFW)</a></li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>Stock Firmware BitAxe Miners:</summary>
|
||||||
|
<ul>
|
||||||
|
<details>
|
||||||
|
<summary>BM Series:</summary>
|
||||||
|
<ul>
|
||||||
|
<li><a href="../bitaxe/BM#supra-stock">Supra (Stock)</a></li>
|
||||||
|
<li><a href="../bitaxe/BM#ultra-stock">Ultra (Stock)</a></li>
|
||||||
|
<li><a href="../bitaxe/BM#max-stock">Max (Stock)</a></li>
|
||||||
|
<li><a href="../bitaxe/BM#gamma-stock">Gamma (Stock)</a></li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>Stock Firmware IceRiver Miners:</summary>
|
||||||
|
<ul>
|
||||||
|
<details>
|
||||||
|
<summary>KSX Series:</summary>
|
||||||
|
<ul>
|
||||||
|
<li><a href="../iceriver/KSX#ks0-stock">KS0 (Stock)</a></li>
|
||||||
|
<li><a href="../iceriver/KSX#ks1-stock">KS1 (Stock)</a></li>
|
||||||
|
<li><a href="../iceriver/KSX#ks2-stock">KS2 (Stock)</a></li>
|
||||||
|
<li><a href="../iceriver/KSX#ks3-stock">KS3 (Stock)</a></li>
|
||||||
|
<li><a href="../iceriver/KSX#ks3l-stock">KS3L (Stock)</a></li>
|
||||||
|
<li><a href="../iceriver/KSX#ks3m-stock">KS3M (Stock)</a></li>
|
||||||
|
<li><a href="../iceriver/KSX#ks5-stock">KS5 (Stock)</a></li>
|
||||||
|
<li><a href="../iceriver/KSX#ks5l-stock">KS5L (Stock)</a></li>
|
||||||
|
<li><a href="../iceriver/KSX#ks5m-stock">KS5M (Stock)</a></li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>Stock Firmware Hammer Miners:</summary>
|
||||||
|
<ul>
|
||||||
|
<details>
|
||||||
|
<summary>DX Series:</summary>
|
||||||
|
<ul>
|
||||||
|
<li><a href="../hammer/DX#d10-stock">D10 (Stock)</a></li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
@@ -1,91 +1,91 @@
|
|||||||
# pyasic
|
# pyasic
|
||||||
## M2X Models
|
## M2X Models
|
||||||
|
|
||||||
## M20 V10
|
## M20 V10 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M2X.M20.BTMinerM20V10
|
::: pyasic.miners.whatsminer.btminer.M2X.M20.BTMinerM20V10
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M20S V10
|
## M20S V10 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M2X.M20S.BTMinerM20SV10
|
::: pyasic.miners.whatsminer.btminer.M2X.M20S.BTMinerM20SV10
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M20S V20
|
## M20S V20 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M2X.M20S.BTMinerM20SV20
|
::: pyasic.miners.whatsminer.btminer.M2X.M20S.BTMinerM20SV20
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M20S V30
|
## M20S V30 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M2X.M20S.BTMinerM20SV30
|
::: pyasic.miners.whatsminer.btminer.M2X.M20S.BTMinerM20SV30
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M20P V10
|
## M20P V10 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M2X.M20P.BTMinerM20PV10
|
::: pyasic.miners.whatsminer.btminer.M2X.M20P.BTMinerM20PV10
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M20P V30
|
## M20P V30 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M2X.M20P.BTMinerM20PV30
|
::: pyasic.miners.whatsminer.btminer.M2X.M20P.BTMinerM20PV30
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M20S+ V30
|
## M20S+ V30 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M2X.M20S_Plus.BTMinerM20SPlusV30
|
::: pyasic.miners.whatsminer.btminer.M2X.M20S_Plus.BTMinerM20SPlusV30
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M21 V10
|
## M21 V10 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M2X.M21.BTMinerM21V10
|
::: pyasic.miners.whatsminer.btminer.M2X.M21.BTMinerM21V10
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M21S V20
|
## M21S V20 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M2X.M21S.BTMinerM21SV20
|
::: pyasic.miners.whatsminer.btminer.M2X.M21S.BTMinerM21SV20
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M21S V60
|
## M21S V60 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M2X.M21S.BTMinerM21SV60
|
::: pyasic.miners.whatsminer.btminer.M2X.M21S.BTMinerM21SV60
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M21S V70
|
## M21S V70 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M2X.M21S.BTMinerM21SV70
|
::: pyasic.miners.whatsminer.btminer.M2X.M21S.BTMinerM21SV70
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M21S+ V20
|
## M21S+ V20 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M2X.M21S_Plus.BTMinerM21SPlusV20
|
::: pyasic.miners.whatsminer.btminer.M2X.M21S_Plus.BTMinerM21SPlusV20
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M29 V10
|
## M29 V10 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M2X.M29.BTMinerM29V10
|
::: pyasic.miners.whatsminer.btminer.M2X.M29.BTMinerM29V10
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,245 +1,266 @@
|
|||||||
# pyasic
|
# pyasic
|
||||||
## M5X Models
|
## M5X Models
|
||||||
|
|
||||||
## M50 VE30
|
## M50 VE30 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VE30
|
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VE30
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M50 VG30
|
## M50 VG30 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VG30
|
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VG30
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M50 VH10
|
## M50 VH10 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH10
|
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH10
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M50 VH20
|
## M50 VH20 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH20
|
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH20
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M50 VH30
|
## M50 VH30 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH30
|
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH30
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M50 VH40
|
## M50 VH40 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH40
|
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH40
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M50 VH50
|
## M50 VH50 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH50
|
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH50
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M50 VH60
|
## M50 VH60 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH60
|
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH60
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M50 VH70
|
## M50 VH70 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH70
|
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH70
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M50 VH80
|
## M50 VH80 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH80
|
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH80
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M50 VJ10
|
## M50 VH90 (Stock)
|
||||||
|
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH90
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## M50 VJ10 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VJ10
|
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VJ10
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M50 VJ20
|
## M50 VJ20 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VJ20
|
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VJ20
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M50 VJ30
|
## M50 VJ30 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VJ30
|
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VJ30
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M50S VJ10
|
## M50S VJ10 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVJ10
|
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVJ10
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M50S VJ20
|
## M50S VJ20 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVJ20
|
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVJ20
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M50S VJ30
|
## M50S VJ30 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVJ30
|
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVJ30
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M50S VH10
|
## M50S VH10 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH10
|
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH10
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M50S VH20
|
## M50S VH20 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH20
|
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH20
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M50S VH30
|
## M50S VH30 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH30
|
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH30
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M50S VH40
|
## M50S VH40 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH40
|
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH40
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M50S VH50
|
## M50S VH50 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH50
|
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH50
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M50S+ VH30
|
## M50S+ VH30 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVH30
|
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVH30
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M50S+ VH40
|
## M50S+ VH40 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVH40
|
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVH40
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M50S+ VJ30
|
## M50S+ VJ30 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVJ30
|
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVJ30
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M50S+ VK20
|
## M50S+ VK20 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVK20
|
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVK20
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M50S++ VK10
|
## M50S++ VK10 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus_Plus.BTMinerM50SPlusPlusVK10
|
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus_Plus.BTMinerM50SPlusPlusVK10
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M50S++ VK20
|
## M50S++ VK20 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus_Plus.BTMinerM50SPlusPlusVK20
|
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus_Plus.BTMinerM50SPlusPlusVK20
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M50S++ VK30
|
## M50S++ VK30 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus_Plus.BTMinerM50SPlusPlusVK30
|
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus_Plus.BTMinerM50SPlusPlusVK30
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M53 VH30
|
## M53 VH30 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M53.BTMinerM53VH30
|
::: pyasic.miners.whatsminer.btminer.M5X.M53.BTMinerM53VH30
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M53S VH30
|
## M53S VH30 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M53S.BTMinerM53SVH30
|
::: pyasic.miners.whatsminer.btminer.M5X.M53S.BTMinerM53SVH30
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M53S+ VJ30
|
## M53S VJ40 (Stock)
|
||||||
|
::: pyasic.miners.whatsminer.btminer.M5X.M53S.BTMinerM53SVJ40
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## M53S+ VJ30 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M53S_Plus.BTMinerM53SPlusVJ30
|
::: pyasic.miners.whatsminer.btminer.M5X.M53S_Plus.BTMinerM53SPlusVJ30
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M56 VH30
|
## M53S++ VK10 (Stock)
|
||||||
|
::: pyasic.miners.whatsminer.btminer.M5X.M53S_Plus_Plus.BTMinerM53SPlusPlusVK10
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## M56 VH30 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M56.BTMinerM56VH30
|
::: pyasic.miners.whatsminer.btminer.M5X.M56.BTMinerM56VH30
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M56S VH30
|
## M56S VH30 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M56S.BTMinerM56SVH30
|
::: pyasic.miners.whatsminer.btminer.M5X.M56S.BTMinerM56SVH30
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M56S+ VJ30
|
## M56S+ VJ30 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M56S_Plus.BTMinerM56SPlusVJ30
|
::: pyasic.miners.whatsminer.btminer.M5X.M56S_Plus.BTMinerM56SPlusVJ30
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
show_root_heading: false
|
show_root_heading: false
|
||||||
heading_level: 4
|
heading_level: 4
|
||||||
|
|
||||||
## M59 VH30
|
## M59 VH30 (Stock)
|
||||||
::: pyasic.miners.whatsminer.btminer.M5X.M59.BTMinerM59VH30
|
::: pyasic.miners.whatsminer.btminer.M5X.M59.BTMinerM59VH30
|
||||||
handler: python
|
handler: python
|
||||||
options:
|
options:
|
||||||
|
|||||||
136
docs/miners/whatsminer/M6X.md
Normal file
136
docs/miners/whatsminer/M6X.md
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
# pyasic
|
||||||
|
## M6X Models
|
||||||
|
|
||||||
|
## M60 VK10 (Stock)
|
||||||
|
::: pyasic.miners.whatsminer.btminer.M6X.M60.BTMinerM60VK10
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## M60 VK20 (Stock)
|
||||||
|
::: pyasic.miners.whatsminer.btminer.M6X.M60.BTMinerM60VK20
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## M60 VK30 (Stock)
|
||||||
|
::: pyasic.miners.whatsminer.btminer.M6X.M60.BTMinerM60VK30
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## M60 VK40 (Stock)
|
||||||
|
::: pyasic.miners.whatsminer.btminer.M6X.M60.BTMinerM60VK40
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## M60S VK10 (Stock)
|
||||||
|
::: pyasic.miners.whatsminer.btminer.M6X.M60S.BTMinerM60SVK10
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## M60S VK20 (Stock)
|
||||||
|
::: pyasic.miners.whatsminer.btminer.M6X.M60S.BTMinerM60SVK20
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## M60S VK30 (Stock)
|
||||||
|
::: pyasic.miners.whatsminer.btminer.M6X.M60S.BTMinerM60SVK30
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## M60S VK40 (Stock)
|
||||||
|
::: pyasic.miners.whatsminer.btminer.M6X.M60S.BTMinerM60SVK40
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## M63 VK10 (Stock)
|
||||||
|
::: pyasic.miners.whatsminer.btminer.M6X.M63.BTMinerM63VK10
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## M63 VK20 (Stock)
|
||||||
|
::: pyasic.miners.whatsminer.btminer.M6X.M63.BTMinerM63VK20
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## M63 VK30 (Stock)
|
||||||
|
::: pyasic.miners.whatsminer.btminer.M6X.M63.BTMinerM63VK30
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## M63S VK10 (Stock)
|
||||||
|
::: pyasic.miners.whatsminer.btminer.M6X.M63S.BTMinerM63SVK10
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## M63S VK20 (Stock)
|
||||||
|
::: pyasic.miners.whatsminer.btminer.M6X.M63S.BTMinerM63SVK20
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## M63S VK30 (Stock)
|
||||||
|
::: pyasic.miners.whatsminer.btminer.M6X.M63S.BTMinerM63SVK30
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## M66 VK20 (Stock)
|
||||||
|
::: pyasic.miners.whatsminer.btminer.M6X.M66.BTMinerM66VK20
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## M66 VK30 (Stock)
|
||||||
|
::: pyasic.miners.whatsminer.btminer.M6X.M66.BTMinerM66VK30
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## M66S VK20 (Stock)
|
||||||
|
::: pyasic.miners.whatsminer.btminer.M6X.M66S.BTMinerM66SVK20
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## M66S VK30 (Stock)
|
||||||
|
::: pyasic.miners.whatsminer.btminer.M6X.M66S.BTMinerM66SVK30
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## M66S VK40 (Stock)
|
||||||
|
::: pyasic.miners.whatsminer.btminer.M6X.M66S.BTMinerM66SVK40
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
jinja2<3.1.3
|
jinja2<3.1.4
|
||||||
mkdocs
|
mkdocs
|
||||||
mkdocstrings[python]
|
mkdocstrings[python]
|
||||||
|
zipp>=3.19.1 # not directly required, pinned by Snyk to avoid a vulnerability
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
# pyasic
|
# pyasic
|
||||||
## Miner APIs
|
## Miner RPC APIs
|
||||||
Each miner has a unique API that is used to communicate with it.
|
Each miner has a unique RPC API that is used to communicate with it.
|
||||||
Each of these API types has commands that differ between them, and some commands have data that others do not.
|
Each of these API types has commands that differ between them, and some commands have data that others do not.
|
||||||
Each miner that is a subclass of [`BaseMiner`][pyasic.miners.BaseMiner] should have an API linked to it as `Miner.api`.
|
Each miner that is a subclass of [`BaseMiner`][pyasic.miners.base.BaseMiner] may have an API linked to it as `Miner.rpc`.
|
||||||
|
|
||||||
All API implementations inherit from [`BaseMinerRPCAPI`][pyasic.rpc.base.BaseMinerRPCAPI], which implements the basic communications protocols.
|
All RPC API implementations inherit from [`BaseMinerRPCAPI`][pyasic.rpc.base.BaseMinerRPCAPI], which implements the basic communications protocols.
|
||||||
|
|
||||||
[`BaseMinerRPCAPI`][pyasic.rpc.base.BaseMinerRPCAPI] should never be used unless inheriting to create a new miner API class for a new type of miner (which should be exceedingly rare).
|
[`BaseMinerRPCAPI`][pyasic.rpc.base.BaseMinerRPCAPI] should never be used unless inheriting to create a new miner API class for a new type of miner (which should be exceedingly rare).
|
||||||
[`BaseMinerRPCAPI`][pyasic.rpc.base.BaseMinerRPCAPI] cannot be instantiated directly, it will raise a `TypeError`.
|
[`BaseMinerRPCAPI`][pyasic.rpc.base.BaseMinerRPCAPI] cannot be instantiated directly, it will raise a `TypeError`.
|
||||||
|
|||||||
@@ -12,13 +12,18 @@ Settings options:
|
|||||||
- `factory_get_timeout`
|
- `factory_get_timeout`
|
||||||
- `get_data_retries`
|
- `get_data_retries`
|
||||||
- `api_function_timeout`
|
- `api_function_timeout`
|
||||||
- `default_whatsminer_password`
|
- `antminer_mining_mode_as_str`
|
||||||
- `default_innosilicon_password`
|
- `default_whatsminer_rpc_password`
|
||||||
- `default_antminer_password`
|
- `default_innosilicon_web_password`
|
||||||
- `default_bosminer_password`
|
- `default_antminer_web_password`
|
||||||
- `default_vnish_password`
|
- `default_bosminer_web_password`
|
||||||
- `default_goldshell_password`
|
- `default_vnish_web_password`
|
||||||
- `socket_linger_time`
|
- `default_goldshell_web_password`
|
||||||
|
- `default_auradine_web_password`
|
||||||
|
- `default_epic_web_password`
|
||||||
|
- `default_hive_web_password`
|
||||||
|
- `default_antminer_ssh_password`
|
||||||
|
- `default_bosminer_ssh_password`
|
||||||
|
|
||||||
|
|
||||||
### get
|
### get
|
||||||
|
|||||||
14
docs/web/antminer.md
Normal file
14
docs/web/antminer.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# pyasic
|
||||||
|
## AntminerModernWebAPI
|
||||||
|
::: pyasic.web.antminer.AntminerModernWebAPI
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
|
|
||||||
|
## AntminerOldWebAPI
|
||||||
|
::: pyasic.web.antminer.AntminerOldWebAPI
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
27
docs/web/api.md
Normal file
27
docs/web/api.md
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# pyasic
|
||||||
|
## Miner Web APIs
|
||||||
|
Each miner has a unique Web API that is used to communicate with it.
|
||||||
|
Each of these API types has commands that differ between them, and some commands have data that others do not.
|
||||||
|
Each miner that is a subclass of [`BaseMiner`][pyasic.miners.base.BaseMiner] may have an API linked to it as `Miner.web`.
|
||||||
|
|
||||||
|
All API implementations inherit from [`BaseWebAPI`][pyasic.web.BaseWebAPI], which implements the basic communications protocols.
|
||||||
|
|
||||||
|
[`BaseWebAPI`][pyasic.web.BaseWebAPI] should never be used unless inheriting to create a new miner API class for a new type of miner (which should be exceedingly rare).
|
||||||
|
Use these instead -
|
||||||
|
|
||||||
|
#### [AntminerModerNWebAPI][pyasic.web.antminer.AntminerModernWebAPI]
|
||||||
|
#### [AntminerOldWebAPI][pyasic.web.antminer.AntminerOldWebAPI]
|
||||||
|
#### [AuradineWebAPI][pyasic.web.auradine.AuradineWebAPI]
|
||||||
|
#### [ePICWebAPI][pyasic.web.epic.ePICWebAPI]
|
||||||
|
#### [GoldshellWebAPI][pyasic.web.goldshell.GoldshellWebAPI]
|
||||||
|
#### [InnosiliconWebAPI][pyasic.web.innosilicon.InnosiliconWebAPI]
|
||||||
|
#### [MaraWebAPI][pyasic.web.marathon.MaraWebAPI]
|
||||||
|
#### [VNishWebAPI][pyasic.web.vnish.VNishWebAPI]
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
## BaseWebAPI
|
||||||
|
::: pyasic.web.BaseWebAPI
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
heading_level: 4
|
||||||
7
docs/web/auradine.md
Normal file
7
docs/web/auradine.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# pyasic
|
||||||
|
## AuradineWebAPI
|
||||||
|
::: pyasic.web.auradine.AuradineWebAPI
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
7
docs/web/epic.md
Normal file
7
docs/web/epic.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# pyasic
|
||||||
|
## ePICWebAPI
|
||||||
|
::: pyasic.web.epic.ePICWebAPI
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
7
docs/web/goldshell.md
Normal file
7
docs/web/goldshell.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# pyasic
|
||||||
|
## GoldshellWebAPI
|
||||||
|
::: pyasic.web.goldshell.GoldshellWebAPI
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
7
docs/web/innosilicon.md
Normal file
7
docs/web/innosilicon.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# pyasic
|
||||||
|
## InnosiliconWebAPI
|
||||||
|
::: pyasic.web.innosilicon.InnosiliconWebAPI
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
7
docs/web/marathon.md
Normal file
7
docs/web/marathon.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# pyasic
|
||||||
|
## MaraWebAPI
|
||||||
|
::: pyasic.web.marathon.MaraWebAPI
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
7
docs/web/vnish.md
Normal file
7
docs/web/vnish.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# pyasic
|
||||||
|
## VNishWebAPI
|
||||||
|
::: pyasic.web.vnish.VNishWebAPI
|
||||||
|
handler: python
|
||||||
|
options:
|
||||||
|
show_root_heading: false
|
||||||
|
heading_level: 4
|
||||||
17
mkdocs.yml
17
mkdocs.yml
@@ -22,6 +22,15 @@ nav:
|
|||||||
- CGMiner: "rpc/cgminer.md"
|
- CGMiner: "rpc/cgminer.md"
|
||||||
- LUXMiner: "rpc/luxminer.md"
|
- LUXMiner: "rpc/luxminer.md"
|
||||||
- Unknown: "rpc/unknown.md"
|
- Unknown: "rpc/unknown.md"
|
||||||
|
- Web APIs:
|
||||||
|
- Intro: "web/api.md"
|
||||||
|
- Antminer: "web/antminer.md"
|
||||||
|
- Auradine: "web/auradine.md"
|
||||||
|
- ePIC: "web/epic.md"
|
||||||
|
- Goldshell: "web/goldshell.md"
|
||||||
|
- Innosilicon: "web/innosilicon.md"
|
||||||
|
- Marathon: "web/marathon.md"
|
||||||
|
- VNish: "web/vnish.md"
|
||||||
- Backends:
|
- Backends:
|
||||||
- BMMiner: "miners/backends/bmminer.md"
|
- BMMiner: "miners/backends/bmminer.md"
|
||||||
- BOSMiner: "miners/backends/bosminer.md"
|
- BOSMiner: "miners/backends/bosminer.md"
|
||||||
@@ -40,6 +49,7 @@ nav:
|
|||||||
- Antminer X15: "miners/antminer/X15.md"
|
- Antminer X15: "miners/antminer/X15.md"
|
||||||
- Antminer X17: "miners/antminer/X17.md"
|
- Antminer X17: "miners/antminer/X17.md"
|
||||||
- Antminer X19: "miners/antminer/X19.md"
|
- Antminer X19: "miners/antminer/X19.md"
|
||||||
|
- Antminer X21: "miners/antminer/X21.md"
|
||||||
- Avalon 7X: "miners/avalonminer/A7X.md"
|
- Avalon 7X: "miners/avalonminer/A7X.md"
|
||||||
- Avalon 8X: "miners/avalonminer/A8X.md"
|
- Avalon 8X: "miners/avalonminer/A8X.md"
|
||||||
- Avalon 9X: "miners/avalonminer/A9X.md"
|
- Avalon 9X: "miners/avalonminer/A9X.md"
|
||||||
@@ -49,10 +59,17 @@ nav:
|
|||||||
- Whatsminer M2X: "miners/whatsminer/M2X.md"
|
- Whatsminer M2X: "miners/whatsminer/M2X.md"
|
||||||
- Whatsminer M3X: "miners/whatsminer/M3X.md"
|
- Whatsminer M3X: "miners/whatsminer/M3X.md"
|
||||||
- Whatsminer M5X: "miners/whatsminer/M5X.md"
|
- Whatsminer M5X: "miners/whatsminer/M5X.md"
|
||||||
|
- Whatsminer M6X: "miners/whatsminer/M6X.md"
|
||||||
- Innosilicon T3X: "miners/innosilicon/T3X.md"
|
- Innosilicon T3X: "miners/innosilicon/T3X.md"
|
||||||
- Innosilicon A10X: "miners/innosilicon/A10X.md"
|
- Innosilicon A10X: "miners/innosilicon/A10X.md"
|
||||||
- Goldshell X5: "miners/goldshell/X5.md"
|
- Goldshell X5: "miners/goldshell/X5.md"
|
||||||
- Goldshell XMax: "miners/goldshell/XMax.md"
|
- Goldshell XMax: "miners/goldshell/XMax.md"
|
||||||
|
- Goldshell XBox: "miners/goldshell/XBox.md"
|
||||||
|
- Auradine AD: "miners/auradine/AD.md"
|
||||||
|
- Auradine AI: "miners/auradine/AI.md"
|
||||||
|
- Auradine AT: "miners/auradine/AT.md"
|
||||||
|
- Blockminer: "miners/blockminer/blockminer.md"
|
||||||
|
- BitAxe BM: "miners/bitaxe/BM.md"
|
||||||
- Base Miner: "miners/base_miner.md"
|
- Base Miner: "miners/base_miner.md"
|
||||||
- Settings:
|
- Settings:
|
||||||
- Settings: "settings/settings.md"
|
- Settings: "settings/settings.md"
|
||||||
|
|||||||
1321
poetry.lock
generated
Normal file
1321
poetry.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -13,134 +13,186 @@
|
|||||||
# See the License for the specific language governing permissions and -
|
# See the License for the specific language governing permissions and -
|
||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
from dataclasses import asdict, dataclass, field
|
|
||||||
|
|
||||||
from pyasic.config.fans import FanModeConfig
|
from pydantic import BaseModel, Field
|
||||||
from pyasic.config.mining import MiningModeConfig
|
|
||||||
|
from pyasic.config.fans import FanMode, FanModeConfig, FanModeNormal
|
||||||
|
from pyasic.config.mining import MiningMode, MiningModeConfig
|
||||||
|
from pyasic.config.mining.scaling import ScalingConfig
|
||||||
from pyasic.config.pools import PoolConfig
|
from pyasic.config.pools import PoolConfig
|
||||||
from pyasic.config.power_scaling import PowerScalingConfig
|
|
||||||
from pyasic.config.temperature import TemperatureConfig
|
from pyasic.config.temperature import TemperatureConfig
|
||||||
from pyasic.misc import merge_dicts
|
from pyasic.misc import merge_dicts
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
class MinerConfig(BaseModel):
|
||||||
class MinerConfig:
|
"""Represents the configuration for a miner including pool configuration,
|
||||||
pools: PoolConfig = field(default_factory=PoolConfig.default)
|
fan mode, temperature settings, mining mode, and power scaling."""
|
||||||
fan_mode: FanModeConfig = field(default_factory=FanModeConfig.default)
|
|
||||||
temperature: TemperatureConfig = field(default_factory=TemperatureConfig.default)
|
class Config:
|
||||||
mining_mode: MiningModeConfig = field(default_factory=MiningModeConfig.default)
|
arbitrary_types_allowed = True
|
||||||
power_scaling: PowerScalingConfig = field(
|
|
||||||
default_factory=PowerScalingConfig.default
|
pools: PoolConfig = Field(default_factory=PoolConfig.default)
|
||||||
)
|
fan_mode: FanMode = Field(default_factory=FanModeConfig.default)
|
||||||
|
temperature: TemperatureConfig = Field(default_factory=TemperatureConfig.default)
|
||||||
|
mining_mode: MiningMode = Field(default_factory=MiningModeConfig.default)
|
||||||
|
|
||||||
|
def __getitem__(self, item):
|
||||||
|
try:
|
||||||
|
return getattr(self, item)
|
||||||
|
except AttributeError:
|
||||||
|
raise KeyError
|
||||||
|
|
||||||
def as_dict(self) -> dict:
|
def as_dict(self) -> dict:
|
||||||
return asdict(self)
|
"""Converts the MinerConfig object to a dictionary."""
|
||||||
|
return self.model_dump()
|
||||||
|
|
||||||
def as_am_modern(self, user_suffix: str = None) -> dict:
|
def as_am_modern(self, user_suffix: str = None) -> dict:
|
||||||
|
"""Generates the configuration in the format suitable for modern Antminers."""
|
||||||
return {
|
return {
|
||||||
**self.fan_mode.as_am_modern(),
|
**self.fan_mode.as_am_modern(),
|
||||||
"freq-level": "100",
|
"freq-level": "100",
|
||||||
**self.mining_mode.as_am_modern(),
|
**self.mining_mode.as_am_modern(),
|
||||||
**self.pools.as_am_modern(user_suffix=user_suffix),
|
**self.pools.as_am_modern(user_suffix=user_suffix),
|
||||||
**self.temperature.as_am_modern(),
|
**self.temperature.as_am_modern(),
|
||||||
**self.power_scaling.as_am_modern(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def as_wm(self, user_suffix: str = None) -> dict:
|
def as_wm(self, user_suffix: str = None) -> dict:
|
||||||
|
"""Generates the configuration in the format suitable for Whatsminers."""
|
||||||
return {
|
return {
|
||||||
**self.fan_mode.as_wm(),
|
**self.fan_mode.as_wm(),
|
||||||
**self.mining_mode.as_wm(),
|
**self.mining_mode.as_wm(),
|
||||||
**self.pools.as_wm(user_suffix=user_suffix),
|
**self.pools.as_wm(user_suffix=user_suffix),
|
||||||
**self.temperature.as_wm(),
|
**self.temperature.as_wm(),
|
||||||
**self.power_scaling.as_wm(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def as_am_old(self, user_suffix: str = None) -> dict:
|
def as_am_old(self, user_suffix: str = None) -> dict:
|
||||||
|
"""Generates the configuration in the format suitable for old versions of Antminers."""
|
||||||
return {
|
return {
|
||||||
**self.fan_mode.as_am_old(),
|
**self.fan_mode.as_am_old(),
|
||||||
**self.mining_mode.as_am_old(),
|
**self.mining_mode.as_am_old(),
|
||||||
**self.pools.as_am_old(user_suffix=user_suffix),
|
**self.pools.as_am_old(user_suffix=user_suffix),
|
||||||
**self.temperature.as_am_old(),
|
**self.temperature.as_am_old(),
|
||||||
**self.power_scaling.as_am_old(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def as_goldshell(self, user_suffix: str = None) -> dict:
|
def as_goldshell(self, user_suffix: str = None) -> dict:
|
||||||
|
"""Generates the configuration in the format suitable for Goldshell miners."""
|
||||||
return {
|
return {
|
||||||
**self.fan_mode.as_goldshell(),
|
**self.fan_mode.as_goldshell(),
|
||||||
**self.mining_mode.as_goldshell(),
|
**self.mining_mode.as_goldshell(),
|
||||||
**self.pools.as_goldshell(user_suffix=user_suffix),
|
**self.pools.as_goldshell(user_suffix=user_suffix),
|
||||||
**self.temperature.as_goldshell(),
|
**self.temperature.as_goldshell(),
|
||||||
**self.power_scaling.as_goldshell(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def as_avalon(self, user_suffix: str = None) -> dict:
|
def as_avalon(self, user_suffix: str = None) -> dict:
|
||||||
|
"""Generates the configuration in the format suitable for Avalonminers."""
|
||||||
return {
|
return {
|
||||||
**self.fan_mode.as_avalon(),
|
**self.fan_mode.as_avalon(),
|
||||||
**self.mining_mode.as_avalon(),
|
**self.mining_mode.as_avalon(),
|
||||||
**self.pools.as_avalon(user_suffix=user_suffix),
|
**self.pools.as_avalon(user_suffix=user_suffix),
|
||||||
**self.temperature.as_avalon(),
|
**self.temperature.as_avalon(),
|
||||||
**self.power_scaling.as_avalon(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def as_inno(self, user_suffix: str = None) -> dict:
|
def as_inno(self, user_suffix: str = None) -> dict:
|
||||||
|
"""Generates the configuration in the format suitable for Innosilicon miners."""
|
||||||
return {
|
return {
|
||||||
**self.fan_mode.as_inno(),
|
**self.fan_mode.as_inno(),
|
||||||
**self.mining_mode.as_inno(),
|
**self.mining_mode.as_inno(),
|
||||||
**self.pools.as_inno(user_suffix=user_suffix),
|
**self.pools.as_inno(user_suffix=user_suffix),
|
||||||
**self.temperature.as_inno(),
|
**self.temperature.as_inno(),
|
||||||
**self.power_scaling.as_inno(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def as_bosminer(self, user_suffix: str = None) -> dict:
|
def as_bosminer(self, user_suffix: str = None) -> dict:
|
||||||
|
"""Generates the configuration in the bosminer.toml format."""
|
||||||
return {
|
return {
|
||||||
**merge_dicts(self.fan_mode.as_bosminer(), self.temperature.as_bosminer()),
|
**merge_dicts(self.fan_mode.as_bosminer(), self.temperature.as_bosminer()),
|
||||||
**self.mining_mode.as_bosminer(),
|
**self.mining_mode.as_bosminer(),
|
||||||
**self.pools.as_bosminer(user_suffix=user_suffix),
|
**self.pools.as_bosminer(user_suffix=user_suffix),
|
||||||
**self.power_scaling.as_bosminer(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def as_boser(self, user_suffix: str = None) -> dict:
|
def as_boser(self, user_suffix: str = None) -> dict:
|
||||||
|
"""Generates the configuration in the format suitable for BOSer."""
|
||||||
return {
|
return {
|
||||||
**self.fan_mode.as_boser(),
|
**self.fan_mode.as_boser(),
|
||||||
**self.temperature.as_boser(),
|
**self.temperature.as_boser(),
|
||||||
**self.mining_mode.as_boser(),
|
**self.mining_mode.as_boser(),
|
||||||
**self.pools.as_boser(user_suffix=user_suffix),
|
**self.pools.as_boser(user_suffix=user_suffix),
|
||||||
**self.power_scaling.as_boser(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def as_epic(self, user_suffix: str = None) -> dict:
|
def as_epic(self, user_suffix: str = None) -> dict:
|
||||||
|
"""Generates the configuration in the format suitable for ePIC miners."""
|
||||||
return {
|
return {
|
||||||
**merge_dicts(self.fan_mode.as_epic(), self.temperature.as_epic()),
|
**merge_dicts(self.fan_mode.as_epic(), self.temperature.as_epic()),
|
||||||
**self.mining_mode.as_epic(),
|
**self.mining_mode.as_epic(),
|
||||||
**self.pools.as_epic(user_suffix=user_suffix),
|
**self.pools.as_epic(user_suffix=user_suffix),
|
||||||
**self.power_scaling.as_epic(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def as_auradine(self, user_suffix: str = None) -> dict:
|
def as_auradine(self, user_suffix: str = None) -> dict:
|
||||||
|
"""Generates the configuration in the format suitable for Auradine miners."""
|
||||||
return {
|
return {
|
||||||
**self.fan_mode.as_auradine(),
|
**self.fan_mode.as_auradine(),
|
||||||
**self.temperature.as_auradine(),
|
**self.temperature.as_auradine(),
|
||||||
**self.mining_mode.as_auradine(),
|
**self.mining_mode.as_auradine(),
|
||||||
**self.pools.as_auradine(user_suffix=user_suffix),
|
**self.pools.as_auradine(user_suffix=user_suffix),
|
||||||
**self.power_scaling.as_auradine(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def as_mara(self, user_suffix: str = None) -> dict:
|
||||||
|
return {
|
||||||
|
**self.fan_mode.as_mara(),
|
||||||
|
**self.temperature.as_mara(),
|
||||||
|
**self.mining_mode.as_mara(),
|
||||||
|
**self.pools.as_mara(user_suffix=user_suffix),
|
||||||
|
}
|
||||||
|
|
||||||
|
def as_bitaxe(self, user_suffix: str = None) -> dict:
|
||||||
|
return {
|
||||||
|
**self.fan_mode.as_bitaxe(),
|
||||||
|
**self.temperature.as_bitaxe(),
|
||||||
|
**self.mining_mode.as_bitaxe(),
|
||||||
|
**self.pools.as_bitaxe(user_suffix=user_suffix),
|
||||||
|
}
|
||||||
|
|
||||||
|
def as_luxos(self, user_suffix: str = None) -> dict:
|
||||||
|
return {
|
||||||
|
**self.fan_mode.as_luxos(),
|
||||||
|
**self.temperature.as_luxos(),
|
||||||
|
**self.mining_mode.as_luxos(),
|
||||||
|
**self.pools.as_luxos(user_suffix=user_suffix),
|
||||||
|
}
|
||||||
|
|
||||||
|
def as_vnish(self, user_suffix: str = None) -> dict:
|
||||||
|
main_cfg = {
|
||||||
|
"miner": {
|
||||||
|
**self.fan_mode.as_vnish(),
|
||||||
|
**self.temperature.as_vnish(),
|
||||||
|
**self.mining_mode.as_vnish(),
|
||||||
|
**self.pools.as_vnish(user_suffix=user_suffix),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isinstance(self.fan_mode, FanModeNormal):
|
||||||
|
main_cfg["miner"]["cooling"]["mode"]["param"] = self.temperature.target
|
||||||
|
return main_cfg
|
||||||
|
|
||||||
|
def as_hammer(self, *args, **kwargs) -> dict:
|
||||||
|
return self.as_am_modern(*args, **kwargs)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, dict_conf: dict) -> "MinerConfig":
|
def from_dict(cls, dict_conf: dict) -> "MinerConfig":
|
||||||
|
"""Constructs a MinerConfig object from a dictionary."""
|
||||||
return cls(
|
return cls(
|
||||||
pools=PoolConfig.from_dict(dict_conf.get("pools")),
|
pools=PoolConfig.from_dict(dict_conf.get("pools")),
|
||||||
mining_mode=MiningModeConfig.from_dict(dict_conf.get("mining_mode")),
|
mining_mode=MiningModeConfig.from_dict(dict_conf.get("mining_mode")),
|
||||||
fan_mode=FanModeConfig.from_dict(dict_conf.get("fan_mode")),
|
fan_mode=FanModeConfig.from_dict(dict_conf.get("fan_mode")),
|
||||||
temperature=TemperatureConfig.from_dict(dict_conf.get("temperature")),
|
temperature=TemperatureConfig.from_dict(dict_conf.get("temperature")),
|
||||||
power_scaling=PowerScalingConfig.from_dict(dict_conf.get("power_scaling")),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_api(cls, api_pools: dict) -> "MinerConfig":
|
def from_api(cls, api_pools: dict) -> "MinerConfig":
|
||||||
|
"""Constructs a MinerConfig object from API pool data."""
|
||||||
return cls(pools=PoolConfig.from_api(api_pools))
|
return cls(pools=PoolConfig.from_api(api_pools))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_am_modern(cls, web_conf: dict) -> "MinerConfig":
|
def from_am_modern(cls, web_conf: dict) -> "MinerConfig":
|
||||||
|
"""Constructs a MinerConfig object from web configuration for modern Antminers."""
|
||||||
return cls(
|
return cls(
|
||||||
pools=PoolConfig.from_am_modern(web_conf),
|
pools=PoolConfig.from_am_modern(web_conf),
|
||||||
mining_mode=MiningModeConfig.from_am_modern(web_conf),
|
mining_mode=MiningModeConfig.from_am_modern(web_conf),
|
||||||
@@ -149,38 +201,42 @@ class MinerConfig:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_am_old(cls, web_conf: dict) -> "MinerConfig":
|
def from_am_old(cls, web_conf: dict) -> "MinerConfig":
|
||||||
|
"""Constructs a MinerConfig object from web configuration for old versions of Antminers."""
|
||||||
return cls.from_am_modern(web_conf)
|
return cls.from_am_modern(web_conf)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_goldshell(cls, web_conf: dict) -> "MinerConfig":
|
def from_goldshell(cls, web_conf: dict) -> "MinerConfig":
|
||||||
|
"""Constructs a MinerConfig object from web configuration for Goldshell miners."""
|
||||||
return cls(pools=PoolConfig.from_am_modern(web_conf))
|
return cls(pools=PoolConfig.from_am_modern(web_conf))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_inno(cls, web_pools: list) -> "MinerConfig":
|
def from_inno(cls, web_pools: list) -> "MinerConfig":
|
||||||
|
"""Constructs a MinerConfig object from web configuration for Innosilicon miners."""
|
||||||
return cls(pools=PoolConfig.from_inno(web_pools))
|
return cls(pools=PoolConfig.from_inno(web_pools))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_bosminer(cls, toml_conf: dict) -> "MinerConfig":
|
def from_bosminer(cls, toml_conf: dict) -> "MinerConfig":
|
||||||
|
"""Constructs a MinerConfig object from the bosminer.toml file, same as the `as_bosminer` dumps a dict for writing to that file as toml."""
|
||||||
return cls(
|
return cls(
|
||||||
pools=PoolConfig.from_bosminer(toml_conf),
|
pools=PoolConfig.from_bosminer(toml_conf),
|
||||||
mining_mode=MiningModeConfig.from_bosminer(toml_conf),
|
mining_mode=MiningModeConfig.from_bosminer(toml_conf),
|
||||||
fan_mode=FanModeConfig.from_bosminer(toml_conf),
|
fan_mode=FanModeConfig.from_bosminer(toml_conf),
|
||||||
temperature=TemperatureConfig.from_bosminer(toml_conf),
|
temperature=TemperatureConfig.from_bosminer(toml_conf),
|
||||||
power_scaling=PowerScalingConfig.from_bosminer(toml_conf),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_boser(cls, grpc_miner_conf: dict) -> "MinerConfig":
|
def from_boser(cls, grpc_miner_conf: dict) -> "MinerConfig":
|
||||||
|
"""Constructs a MinerConfig object from gRPC configuration for BOSer."""
|
||||||
return cls(
|
return cls(
|
||||||
pools=PoolConfig.from_boser(grpc_miner_conf),
|
pools=PoolConfig.from_boser(grpc_miner_conf),
|
||||||
mining_mode=MiningModeConfig.from_boser(grpc_miner_conf),
|
mining_mode=MiningModeConfig.from_boser(grpc_miner_conf),
|
||||||
fan_mode=FanModeConfig.from_boser(grpc_miner_conf),
|
fan_mode=FanModeConfig.from_boser(grpc_miner_conf),
|
||||||
temperature=TemperatureConfig.from_boser(grpc_miner_conf),
|
temperature=TemperatureConfig.from_boser(grpc_miner_conf),
|
||||||
power_scaling=PowerScalingConfig.from_boser(grpc_miner_conf),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_epic(cls, web_conf: dict) -> "MinerConfig":
|
def from_epic(cls, web_conf: dict) -> "MinerConfig":
|
||||||
|
"""Constructs a MinerConfig object from web configuration for ePIC miners."""
|
||||||
return cls(
|
return cls(
|
||||||
pools=PoolConfig.from_epic(web_conf),
|
pools=PoolConfig.from_epic(web_conf),
|
||||||
fan_mode=FanModeConfig.from_epic(web_conf),
|
fan_mode=FanModeConfig.from_epic(web_conf),
|
||||||
@@ -190,6 +246,7 @@ class MinerConfig:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_vnish(cls, web_settings: dict) -> "MinerConfig":
|
def from_vnish(cls, web_settings: dict) -> "MinerConfig":
|
||||||
|
"""Constructs a MinerConfig object from web settings for VNish miners."""
|
||||||
return cls(
|
return cls(
|
||||||
pools=PoolConfig.from_vnish(web_settings),
|
pools=PoolConfig.from_vnish(web_settings),
|
||||||
fan_mode=FanModeConfig.from_vnish(web_settings),
|
fan_mode=FanModeConfig.from_vnish(web_settings),
|
||||||
@@ -199,8 +256,46 @@ class MinerConfig:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_auradine(cls, web_conf: dict) -> "MinerConfig":
|
def from_auradine(cls, web_conf: dict) -> "MinerConfig":
|
||||||
|
"""Constructs a MinerConfig object from web configuration for Auradine miners."""
|
||||||
return cls(
|
return cls(
|
||||||
pools=PoolConfig.from_api(web_conf["pools"]),
|
pools=PoolConfig.from_api(web_conf["pools"]),
|
||||||
fan_mode=FanModeConfig.from_auradine(web_conf["fan"]),
|
fan_mode=FanModeConfig.from_auradine(web_conf["fan"]),
|
||||||
mining_mode=MiningModeConfig.from_auradine(web_conf["mode"]),
|
mining_mode=MiningModeConfig.from_auradine(web_conf["mode"]),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_mara(cls, web_miner_config: dict) -> "MinerConfig":
|
||||||
|
return cls(
|
||||||
|
pools=PoolConfig.from_mara(web_miner_config),
|
||||||
|
fan_mode=FanModeConfig.from_mara(web_miner_config),
|
||||||
|
mining_mode=MiningModeConfig.from_mara(web_miner_config),
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_bitaxe(cls, web_system_info: dict) -> "MinerConfig":
|
||||||
|
return cls(
|
||||||
|
pools=PoolConfig.from_bitaxe(web_system_info),
|
||||||
|
fan_mode=FanModeConfig.from_bitaxe(web_system_info),
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_iceriver(cls, web_userpanel: dict) -> "MinerConfig":
|
||||||
|
return cls(
|
||||||
|
pools=PoolConfig.from_iceriver(web_userpanel),
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_luxos(
|
||||||
|
cls, rpc_tempctrl: dict, rpc_fans: dict, rpc_pools: dict, rpc_groups: dict
|
||||||
|
) -> "MinerConfig":
|
||||||
|
return cls(
|
||||||
|
temperature=TemperatureConfig.from_luxos(rpc_tempctrl=rpc_tempctrl),
|
||||||
|
fan_mode=FanModeConfig.from_luxos(
|
||||||
|
rpc_tempctrl=rpc_tempctrl, rpc_fans=rpc_fans
|
||||||
|
),
|
||||||
|
pools=PoolConfig.from_luxos(rpc_pools=rpc_pools, rpc_groups=rpc_groups),
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_hammer(cls, *args, **kwargs) -> "MinerConfig":
|
||||||
|
return cls.from_am_modern(*args, **kwargs)
|
||||||
|
|||||||
@@ -15,9 +15,10 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from dataclasses import asdict, dataclass
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
class MinerConfigOption(Enum):
|
class MinerConfigOption(Enum):
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -46,7 +47,7 @@ class MinerConfigOption(Enum):
|
|||||||
return self.value.as_bosminer()
|
return self.value.as_bosminer()
|
||||||
|
|
||||||
def as_boser(self) -> dict:
|
def as_boser(self) -> dict:
|
||||||
return self.value.as_boser()
|
return self.value.as_boser
|
||||||
|
|
||||||
def as_epic(self) -> dict:
|
def as_epic(self) -> dict:
|
||||||
return self.value.as_epic()
|
return self.value.as_epic()
|
||||||
@@ -57,6 +58,15 @@ class MinerConfigOption(Enum):
|
|||||||
def as_auradine(self) -> dict:
|
def as_auradine(self) -> dict:
|
||||||
return self.value.as_auradine()
|
return self.value.as_auradine()
|
||||||
|
|
||||||
|
def as_mara(self) -> dict:
|
||||||
|
return self.value.as_mara()
|
||||||
|
|
||||||
|
def as_bitaxe(self) -> dict:
|
||||||
|
return self.value.as_bitaxe()
|
||||||
|
|
||||||
|
def as_luxos(self) -> dict:
|
||||||
|
return self.value.as_luxos()
|
||||||
|
|
||||||
def __call__(self, *args, **kwargs):
|
def __call__(self, *args, **kwargs):
|
||||||
return self.value(*args, **kwargs)
|
return self.value(*args, **kwargs)
|
||||||
|
|
||||||
@@ -64,15 +74,20 @@ class MinerConfigOption(Enum):
|
|||||||
def default(cls):
|
def default(cls):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def __getitem__(self, item):
|
||||||
|
try:
|
||||||
|
return getattr(self, item)
|
||||||
|
except AttributeError:
|
||||||
|
raise KeyError
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class MinerConfigValue:
|
class MinerConfigValue(BaseModel):
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, dict_conf: dict | None):
|
def from_dict(cls, dict_conf: dict | None):
|
||||||
return cls()
|
return cls()
|
||||||
|
|
||||||
def as_dict(self) -> dict:
|
def as_dict(self) -> dict:
|
||||||
return asdict(self)
|
return self.model_dump()
|
||||||
|
|
||||||
def as_am_modern(self) -> dict:
|
def as_am_modern(self) -> dict:
|
||||||
return {}
|
return {}
|
||||||
@@ -106,3 +121,18 @@ class MinerConfigValue:
|
|||||||
|
|
||||||
def as_auradine(self) -> dict:
|
def as_auradine(self) -> dict:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
def as_mara(self) -> dict:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def as_bitaxe(self) -> dict:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def as_luxos(self) -> dict:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def __getitem__(self, item):
|
||||||
|
try:
|
||||||
|
return getattr(self, item)
|
||||||
|
except AttributeError:
|
||||||
|
raise KeyError
|
||||||
|
|||||||
@@ -15,14 +15,15 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from dataclasses import dataclass, field
|
from typing import TypeVar, Union
|
||||||
|
|
||||||
|
from pydantic import Field
|
||||||
|
|
||||||
from pyasic.config.base import MinerConfigOption, MinerConfigValue
|
from pyasic.config.base import MinerConfigOption, MinerConfigValue
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class FanModeNormal(MinerConfigValue):
|
class FanModeNormal(MinerConfigValue):
|
||||||
mode: str = field(init=False, default="normal")
|
mode: str = Field(init=False, default="normal")
|
||||||
minimum_fans: int = 1
|
minimum_fans: int = 1
|
||||||
minimum_speed: int = 0
|
minimum_speed: int = 0
|
||||||
|
|
||||||
@@ -44,27 +45,63 @@ class FanModeNormal(MinerConfigValue):
|
|||||||
cls_conf["minimum_speed"] = web_cooling_settings["fan_min_duty"]
|
cls_conf["minimum_speed"] = web_cooling_settings["fan_min_duty"]
|
||||||
return cls(**cls_conf)
|
return cls(**cls_conf)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_bosminer(cls, toml_fan_conf: dict):
|
||||||
|
cls_conf = {}
|
||||||
|
if toml_fan_conf.get("min_fans") is not None:
|
||||||
|
cls_conf["minimum_fans"] = toml_fan_conf["min_fans"]
|
||||||
|
return cls(**cls_conf)
|
||||||
|
|
||||||
def as_am_modern(self) -> dict:
|
def as_am_modern(self) -> dict:
|
||||||
return {"bitmain-fan-ctrl": False, "bitmain-fan-pwn": "100"}
|
return {"bitmain-fan-ctrl": False, "bitmain-fan-pwn": "100"}
|
||||||
|
|
||||||
def as_bosminer(self) -> dict:
|
def as_bosminer(self) -> dict:
|
||||||
return {"temp_control": {"mode": "auto"}}
|
return {
|
||||||
|
"temp_control": {"mode": "auto"},
|
||||||
|
"fan_control": {"min_fans": self.minimum_fans},
|
||||||
|
}
|
||||||
|
|
||||||
def as_epic(self) -> dict:
|
def as_epic(self) -> dict:
|
||||||
return {
|
return {
|
||||||
"fans": {
|
"fans": {
|
||||||
"Auto": {
|
"Auto": {
|
||||||
"Idle Speed": self.minimum_speed
|
"Idle Speed": (
|
||||||
if not self.minimum_speed == 0
|
self.minimum_speed if not self.minimum_speed == 0 else 100
|
||||||
else 100
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def as_mara(self) -> dict:
|
||||||
|
return {
|
||||||
|
"general-config": {"environment-profile": "AirCooling"},
|
||||||
|
"advance-config": {
|
||||||
|
"override-fan-control": False,
|
||||||
|
"fan-fixed-percent": 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
def as_bitaxe(self) -> dict:
|
||||||
|
return {"autoFanspeed": 1}
|
||||||
|
|
||||||
|
def as_luxos(self) -> dict:
|
||||||
|
return {"fanset": {"speed": -1, "min_fans": self.minimum_fans}}
|
||||||
|
|
||||||
|
def as_vnish(self) -> dict:
|
||||||
|
return {
|
||||||
|
"cooling": {
|
||||||
|
"fan_min_count": self.minimum_fans,
|
||||||
|
"fan_min_duty": self.minimum_speed,
|
||||||
|
"mode": {
|
||||||
|
"name": "auto",
|
||||||
|
"param": None, # Target temp, must be set later...
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class FanModeManual(MinerConfigValue):
|
class FanModeManual(MinerConfigValue):
|
||||||
mode: str = field(init=False, default="manual")
|
mode: str = Field(init=False, default="manual")
|
||||||
speed: int = 100
|
speed: int = 100
|
||||||
minimum_fans: int = 1
|
minimum_fans: int = 1
|
||||||
|
|
||||||
@@ -96,7 +133,7 @@ class FanModeManual(MinerConfigValue):
|
|||||||
return cls(**cls_conf)
|
return cls(**cls_conf)
|
||||||
|
|
||||||
def as_am_modern(self) -> dict:
|
def as_am_modern(self) -> dict:
|
||||||
return {"bitmain-fan-ctrl": True, "bitmain-fan-pwn": str(self.speed)}
|
return {"bitmain-fan-ctrl": True, "bitmain-fan-pwm": str(self.speed)}
|
||||||
|
|
||||||
def as_bosminer(self) -> dict:
|
def as_bosminer(self) -> dict:
|
||||||
return {
|
return {
|
||||||
@@ -110,24 +147,61 @@ class FanModeManual(MinerConfigValue):
|
|||||||
def as_epic(self) -> dict:
|
def as_epic(self) -> dict:
|
||||||
return {"fans": {"Manual": {"speed": self.speed}}}
|
return {"fans": {"Manual": {"speed": self.speed}}}
|
||||||
|
|
||||||
|
def as_mara(self) -> dict:
|
||||||
|
return {
|
||||||
|
"general-config": {"environment-profile": "AirCooling"},
|
||||||
|
"advance-config": {
|
||||||
|
"override-fan-control": True,
|
||||||
|
"fan-fixed-percent": self.speed,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
def as_bitaxe(self) -> dict:
|
||||||
|
return {"autoFanspeed": 0, "fanspeed": self.speed}
|
||||||
|
|
||||||
|
def as_luxos(self) -> dict:
|
||||||
|
return {"fanset": {"speed": self.speed, "min_fans": self.minimum_fans}}
|
||||||
|
|
||||||
|
def as_vnish(self) -> dict:
|
||||||
|
return {
|
||||||
|
"cooling": {
|
||||||
|
"fan_min_count": self.minimum_fans,
|
||||||
|
"fan_min_duty": self.speed,
|
||||||
|
"mode": {
|
||||||
|
"name": "manual",
|
||||||
|
"param": self.speed, # Speed value
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class FanModeImmersion(MinerConfigValue):
|
class FanModeImmersion(MinerConfigValue):
|
||||||
mode: str = field(init=False, default="immersion")
|
mode: str = Field(init=False, default="immersion")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, dict_conf: dict | None) -> "FanModeImmersion":
|
def from_dict(cls, dict_conf: dict | None) -> "FanModeImmersion":
|
||||||
return cls()
|
return cls()
|
||||||
|
|
||||||
def as_am_modern(self) -> dict:
|
def as_am_modern(self) -> dict:
|
||||||
return {"bitmain-fan-ctrl": True, "bitmain-fan-pwn": "0"}
|
return {"bitmain-fan-ctrl": True, "bitmain-fan-pwm": "0"}
|
||||||
|
|
||||||
def as_bosminer(self) -> dict:
|
def as_bosminer(self) -> dict:
|
||||||
return {"temp_control": {"mode": "disabled"}}
|
return {
|
||||||
|
"fan_control": {"min_fans": 0},
|
||||||
|
}
|
||||||
|
|
||||||
def as_auradine(self) -> dict:
|
def as_auradine(self) -> dict:
|
||||||
return {"fan": {"percentage": 0}}
|
return {"fan": {"percentage": 0}}
|
||||||
|
|
||||||
|
def as_mara(self) -> dict:
|
||||||
|
return {"general-config": {"environment-profile": "OilImmersionCooling"}}
|
||||||
|
|
||||||
|
def as_luxos(self) -> dict:
|
||||||
|
return {"fanset": {"speed": 0, "min_fans": 0}}
|
||||||
|
|
||||||
|
def as_vnish(self) -> dict:
|
||||||
|
return {"cooling": {"mode": {"name": "immers"}}}
|
||||||
|
|
||||||
|
|
||||||
class FanModeConfig(MinerConfigOption):
|
class FanModeConfig(MinerConfigOption):
|
||||||
normal = FanModeNormal
|
normal = FanModeNormal
|
||||||
@@ -156,7 +230,10 @@ class FanModeConfig(MinerConfigOption):
|
|||||||
if web_conf.get("bitmain-fan-ctrl") is not None:
|
if web_conf.get("bitmain-fan-ctrl") is not None:
|
||||||
fan_manual = web_conf["bitmain-fan-ctrl"]
|
fan_manual = web_conf["bitmain-fan-ctrl"]
|
||||||
if fan_manual:
|
if fan_manual:
|
||||||
return cls.manual(speed=web_conf["bitmain-fan-pwm"])
|
speed = int(web_conf["bitmain-fan-pwm"])
|
||||||
|
if speed == 0:
|
||||||
|
return cls.immersion()
|
||||||
|
return cls.manual(speed=speed)
|
||||||
else:
|
else:
|
||||||
return cls.normal()
|
return cls.normal()
|
||||||
else:
|
else:
|
||||||
@@ -175,20 +252,28 @@ class FanModeConfig(MinerConfigOption):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_bosminer(cls, toml_conf: dict):
|
def from_bosminer(cls, toml_conf: dict):
|
||||||
if toml_conf.get("temp_control") is None:
|
try:
|
||||||
return cls.default()
|
mode = toml_conf["temp_control"]["mode"]
|
||||||
if toml_conf["temp_control"].get("mode") is None:
|
fan_config = toml_conf.get("fan_control", {})
|
||||||
|
if mode == "auto":
|
||||||
|
return cls.normal().from_bosminer(fan_config)
|
||||||
|
elif mode == "manual":
|
||||||
|
if toml_conf.get("fan_control"):
|
||||||
|
return cls.manual().from_bosminer(fan_config)
|
||||||
|
return cls.manual()
|
||||||
|
elif mode == "disabled":
|
||||||
|
return cls.immersion()
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
min_fans = toml_conf["fan_control"]["min_fans"]
|
||||||
|
except KeyError:
|
||||||
return cls.default()
|
return cls.default()
|
||||||
|
|
||||||
mode = toml_conf["temp_control"]["mode"]
|
if min_fans == 0:
|
||||||
if mode == "auto":
|
|
||||||
return cls.normal()
|
|
||||||
elif mode == "manual":
|
|
||||||
if toml_conf.get("fan_control"):
|
|
||||||
return cls.manual().from_bosminer(toml_conf["fan_control"])
|
|
||||||
return cls.manual()
|
|
||||||
elif mode == "disabled":
|
|
||||||
return cls.immersion()
|
return cls.immersion()
|
||||||
|
return cls.normal(minimum_fans=min_fans)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_vnish(cls, web_settings: dict):
|
def from_vnish(cls, web_settings: dict):
|
||||||
@@ -214,7 +299,7 @@ class FanModeConfig(MinerConfigOption):
|
|||||||
keys = temperature_conf.keys()
|
keys = temperature_conf.keys()
|
||||||
if "auto" in keys:
|
if "auto" in keys:
|
||||||
if "minimumRequiredFans" in keys:
|
if "minimumRequiredFans" in keys:
|
||||||
return cls.normal(temperature_conf["minimumRequiredFans"])
|
return cls.normal(minimum_fans=temperature_conf["minimumRequiredFans"])
|
||||||
return cls.normal()
|
return cls.normal()
|
||||||
if "manual" in keys:
|
if "manual" in keys:
|
||||||
conf = {}
|
conf = {}
|
||||||
@@ -232,4 +317,53 @@ class FanModeConfig(MinerConfigOption):
|
|||||||
fan_1_target = fan_data["Target"]
|
fan_1_target = fan_data["Target"]
|
||||||
return cls.manual(speed=round((fan_1_target / fan_1_max) * 100))
|
return cls.manual(speed=round((fan_1_target / fan_1_max) * 100))
|
||||||
except LookupError:
|
except LookupError:
|
||||||
return cls.default()
|
pass
|
||||||
|
return cls.default()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_mara(cls, web_config: dict):
|
||||||
|
try:
|
||||||
|
mode = web_config["general-config"]["environment-profile"]
|
||||||
|
if mode == "AirCooling":
|
||||||
|
if web_config["advance-config"]["override-fan-control"]:
|
||||||
|
return cls.manual(
|
||||||
|
speed=web_config["advance-config"]["fan-fixed-percent"]
|
||||||
|
)
|
||||||
|
return cls.normal()
|
||||||
|
return cls.immersion()
|
||||||
|
except LookupError:
|
||||||
|
pass
|
||||||
|
return cls.default()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_bitaxe(cls, web_system_info: dict):
|
||||||
|
if web_system_info["autofanspeed"] == 1:
|
||||||
|
return cls.normal()
|
||||||
|
else:
|
||||||
|
return cls.manual(speed=web_system_info["fanspeed"])
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_luxos(cls, rpc_fans: dict, rpc_tempctrl: dict):
|
||||||
|
try:
|
||||||
|
mode = rpc_tempctrl["TEMPCTRL"][0]["Mode"]
|
||||||
|
if mode == "Manual":
|
||||||
|
speed = rpc_fans["FANS"][0]["Speed"]
|
||||||
|
min_fans = rpc_fans["FANCTRL"][0]["MinFans"]
|
||||||
|
if min_fans == 0 and speed == 0:
|
||||||
|
return cls.immersion()
|
||||||
|
return cls.manual(
|
||||||
|
speed=speed,
|
||||||
|
minimum_fans=min_fans,
|
||||||
|
)
|
||||||
|
return cls.normal(
|
||||||
|
minimum_fans=rpc_fans["FANCTRL"][0]["MinFans"],
|
||||||
|
)
|
||||||
|
except LookupError:
|
||||||
|
pass
|
||||||
|
return cls.default()
|
||||||
|
|
||||||
|
|
||||||
|
FanMode = TypeVar(
|
||||||
|
"FanMode",
|
||||||
|
bound=Union[FanModeNormal, FanModeManual, FanModeImmersion],
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,415 +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. -
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from dataclasses import dataclass, field
|
|
||||||
|
|
||||||
from pyasic.config.base import MinerConfigOption, MinerConfigValue
|
|
||||||
from pyasic.web.braiins_os.proto.braiins.bos.v1 import (
|
|
||||||
HashrateTargetMode,
|
|
||||||
PerformanceMode,
|
|
||||||
Power,
|
|
||||||
PowerTargetMode,
|
|
||||||
SaveAction,
|
|
||||||
SetPerformanceModeRequest,
|
|
||||||
TeraHashrate,
|
|
||||||
TunerPerformanceMode,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class MiningModeNormal(MinerConfigValue):
|
|
||||||
mode: str = field(init=False, default="normal")
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_dict(cls, dict_conf: dict | None) -> "MiningModeNormal":
|
|
||||||
return cls()
|
|
||||||
|
|
||||||
def as_am_modern(self) -> dict:
|
|
||||||
return {"miner-mode": "0"}
|
|
||||||
|
|
||||||
def as_wm(self) -> dict:
|
|
||||||
return {"mode": self.mode}
|
|
||||||
|
|
||||||
def as_auradine(self) -> dict:
|
|
||||||
return {"mode": {"mode": self.mode}}
|
|
||||||
|
|
||||||
def as_epic(self) -> dict:
|
|
||||||
return {"ptune": {"enabled": False}}
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class MiningModeSleep(MinerConfigValue):
|
|
||||||
mode: str = field(init=False, default="sleep")
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_dict(cls, dict_conf: dict | None) -> "MiningModeSleep":
|
|
||||||
return cls()
|
|
||||||
|
|
||||||
def as_am_modern(self) -> dict:
|
|
||||||
return {"miner-mode": "1"}
|
|
||||||
|
|
||||||
def as_wm(self) -> dict:
|
|
||||||
return {"mode": self.mode}
|
|
||||||
|
|
||||||
def as_auradine(self) -> dict:
|
|
||||||
return {"mode": {"sleep": "on"}}
|
|
||||||
|
|
||||||
def as_epic(self) -> dict:
|
|
||||||
return {"ptune": {"algo": "Sleep", "target": 0}}
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class MiningModeLPM(MinerConfigValue):
|
|
||||||
mode: str = field(init=False, default="low")
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_dict(cls, dict_conf: dict | None) -> "MiningModeLPM":
|
|
||||||
return cls()
|
|
||||||
|
|
||||||
def as_am_modern(self) -> dict:
|
|
||||||
return {"miner-mode": "3"}
|
|
||||||
|
|
||||||
def as_wm(self) -> dict:
|
|
||||||
return {"mode": self.mode}
|
|
||||||
|
|
||||||
def as_auradine(self) -> dict:
|
|
||||||
return {"mode": {"mode": "eco"}}
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class MiningModeHPM(MinerConfigValue):
|
|
||||||
mode: str = field(init=False, default="high")
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_dict(cls, dict_conf: dict | None) -> "MiningModeHPM":
|
|
||||||
return cls()
|
|
||||||
|
|
||||||
def as_am_modern(self) -> dict:
|
|
||||||
return {"miner-mode": "0"}
|
|
||||||
|
|
||||||
def as_wm(self) -> dict:
|
|
||||||
return {"mode": self.mode}
|
|
||||||
|
|
||||||
def as_auradine(self) -> dict:
|
|
||||||
return {"mode": {"mode": "turbo"}}
|
|
||||||
|
|
||||||
|
|
||||||
class StandardPowerTuneAlgo(MinerConfigValue):
|
|
||||||
mode: str = field(init=False, default="standard")
|
|
||||||
|
|
||||||
def as_epic(self):
|
|
||||||
return VOptPowerTuneAlgo().as_epic()
|
|
||||||
|
|
||||||
|
|
||||||
class VOptPowerTuneAlgo(MinerConfigValue):
|
|
||||||
mode: str = field(init=False, default="standard")
|
|
||||||
|
|
||||||
def as_epic(self):
|
|
||||||
return "VoltageOptimizer"
|
|
||||||
|
|
||||||
|
|
||||||
class ChipTunePowerTuneAlgo(MinerConfigValue):
|
|
||||||
mode: str = field(init=False, default="standard")
|
|
||||||
|
|
||||||
def as_epic(self):
|
|
||||||
return "ChipTune"
|
|
||||||
|
|
||||||
|
|
||||||
class PowerTunerAlgo(MinerConfigOption):
|
|
||||||
standard = StandardPowerTuneAlgo
|
|
||||||
voltage_optimizer = VOptPowerTuneAlgo
|
|
||||||
chip_tune = ChipTunePowerTuneAlgo
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def default(cls):
|
|
||||||
return cls.standard()
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class MiningModePowerTune(MinerConfigValue):
|
|
||||||
mode: str = field(init=False, default="power_tuning")
|
|
||||||
power: int = None
|
|
||||||
algo: PowerTunerAlgo = field(default_factory=PowerTunerAlgo.default)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_dict(cls, dict_conf: dict | None) -> "MiningModePowerTune":
|
|
||||||
cls_conf = {}
|
|
||||||
if dict_conf.get("power"):
|
|
||||||
cls_conf["power"] = dict_conf["power"]
|
|
||||||
if dict_conf.get("algo"):
|
|
||||||
cls_conf["algo"] = dict_conf["algo"]
|
|
||||||
|
|
||||||
return cls(**cls_conf)
|
|
||||||
|
|
||||||
def as_am_modern(self) -> dict:
|
|
||||||
return {"miner-mode": "0"}
|
|
||||||
|
|
||||||
def as_wm(self) -> dict:
|
|
||||||
if self.power is not None:
|
|
||||||
return {"mode": self.mode, self.mode: {"wattage": self.power}}
|
|
||||||
return {}
|
|
||||||
|
|
||||||
def as_bosminer(self) -> dict:
|
|
||||||
return {"autotuning": {"enabled": True, "psu_power_limit": self.power}}
|
|
||||||
|
|
||||||
def as_boser(self) -> dict:
|
|
||||||
return {
|
|
||||||
"set_performance_mode": SetPerformanceModeRequest(
|
|
||||||
save_action=SaveAction.SAVE_ACTION_SAVE_AND_APPLY,
|
|
||||||
mode=PerformanceMode(
|
|
||||||
tuner_mode=TunerPerformanceMode(
|
|
||||||
power_target=PowerTargetMode(
|
|
||||||
power_target=Power(watt=self.power)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
|
|
||||||
def as_auradine(self) -> dict:
|
|
||||||
return {"mode": {"mode": "custom", "tune": "power", "power": self.power}}
|
|
||||||
|
|
||||||
def as_epic(self) -> dict:
|
|
||||||
return {"ptune": {**self.algo.as_epic(), "target": self.power}}
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class MiningModeHashrateTune(MinerConfigValue):
|
|
||||||
mode: str = field(init=False, default="hashrate_tuning")
|
|
||||||
hashrate: int = None
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_dict(cls, dict_conf: dict | None) -> "MiningModeHashrateTune":
|
|
||||||
return cls(dict_conf.get("hashrate"))
|
|
||||||
|
|
||||||
def as_am_modern(self) -> dict:
|
|
||||||
return {"miner-mode": "0"}
|
|
||||||
|
|
||||||
def as_boser(self) -> dict:
|
|
||||||
return {
|
|
||||||
"set_performance_mode": SetPerformanceModeRequest(
|
|
||||||
save_action=SaveAction.SAVE_ACTION_SAVE_AND_APPLY,
|
|
||||||
mode=PerformanceMode(
|
|
||||||
tuner_mode=TunerPerformanceMode(
|
|
||||||
hashrate_target=HashrateTargetMode(
|
|
||||||
hashrate_target=TeraHashrate(
|
|
||||||
terahash_per_second=self.hashrate
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
def as_auradine(self) -> dict:
|
|
||||||
return {"mode": {"mode": "custom", "tune": "ths", "ths": self.hashrate}}
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class ManualBoardSettings(MinerConfigValue):
|
|
||||||
freq: float
|
|
||||||
volt: float
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_dict(cls, dict_conf: dict | None) -> "ManualBoardSettings":
|
|
||||||
return cls(freq=dict_conf["freq"], volt=dict_conf["volt"])
|
|
||||||
|
|
||||||
def as_am_modern(self) -> dict:
|
|
||||||
return {"miner-mode": "0"}
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class MiningModeManual(MinerConfigValue):
|
|
||||||
mode: str = field(init=False, default="manual")
|
|
||||||
|
|
||||||
global_freq: float
|
|
||||||
global_volt: float
|
|
||||||
boards: dict[int, ManualBoardSettings] = field(default_factory=dict)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_dict(cls, dict_conf: dict | None) -> "MiningModeManual":
|
|
||||||
return cls(
|
|
||||||
global_freq=dict_conf["global_freq"],
|
|
||||||
global_volt=dict_conf["global_volt"],
|
|
||||||
boards={i: ManualBoardSettings.from_dict(dict_conf[i]) for i in dict_conf},
|
|
||||||
)
|
|
||||||
|
|
||||||
def as_am_modern(self) -> dict:
|
|
||||||
return {"miner-mode": "0"}
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_vnish(cls, web_overclock_settings: dict) -> "MiningModeManual":
|
|
||||||
# will raise KeyError if it cant find the settings, values cannot be empty
|
|
||||||
voltage = web_overclock_settings["globals"]["volt"]
|
|
||||||
freq = web_overclock_settings["globals"]["freq"]
|
|
||||||
boards = {
|
|
||||||
idx: ManualBoardSettings(
|
|
||||||
freq=board["freq"],
|
|
||||||
volt=voltage if not board["freq"] == 0 else 0,
|
|
||||||
)
|
|
||||||
for idx, board in enumerate(web_overclock_settings["chains"])
|
|
||||||
}
|
|
||||||
return cls(global_freq=freq, global_volt=voltage, boards=boards)
|
|
||||||
|
|
||||||
|
|
||||||
class MiningModeConfig(MinerConfigOption):
|
|
||||||
normal = MiningModeNormal
|
|
||||||
low = MiningModeLPM
|
|
||||||
high = MiningModeHPM
|
|
||||||
sleep = MiningModeSleep
|
|
||||||
power_tuning = MiningModePowerTune
|
|
||||||
hashrate_tuning = MiningModeHashrateTune
|
|
||||||
manual = MiningModeManual
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def default(cls):
|
|
||||||
return cls.normal()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_dict(cls, dict_conf: dict | None):
|
|
||||||
if dict_conf is None:
|
|
||||||
return cls.default()
|
|
||||||
|
|
||||||
mode = dict_conf.get("mode")
|
|
||||||
if mode is None:
|
|
||||||
return cls.default()
|
|
||||||
|
|
||||||
cls_attr = getattr(cls, mode)
|
|
||||||
if cls_attr is not None:
|
|
||||||
return cls_attr().from_dict(dict_conf)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_am_modern(cls, web_conf: dict):
|
|
||||||
if web_conf.get("bitmain-work-mode") is not None:
|
|
||||||
work_mode = web_conf["bitmain-work-mode"]
|
|
||||||
if work_mode == "":
|
|
||||||
return cls.default()
|
|
||||||
if int(work_mode) == 0:
|
|
||||||
return cls.normal()
|
|
||||||
elif int(work_mode) == 1:
|
|
||||||
return cls.sleep()
|
|
||||||
elif int(work_mode) == 3:
|
|
||||||
return cls.low()
|
|
||||||
return cls.default()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_epic(cls, web_conf: dict):
|
|
||||||
try:
|
|
||||||
tuner_running = web_conf["PerpetualTune"]["Running"]
|
|
||||||
if tuner_running:
|
|
||||||
algo_info = web_conf["PerpetualTune"]["Algorithm"]
|
|
||||||
if algo_info.get("VoltageOptimizer") is not None:
|
|
||||||
return cls.power_tuning(
|
|
||||||
power=algo_info["VoltageOptimizer"]["Target"],
|
|
||||||
algo=PowerTunerAlgo.voltage_optimizer,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
return cls.power_tuning(
|
|
||||||
power=algo_info["ChipTune"]["Target"],
|
|
||||||
algo=PowerTunerAlgo.chip_tune,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
return cls.normal()
|
|
||||||
except KeyError:
|
|
||||||
return cls.default()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_bosminer(cls, toml_conf: dict):
|
|
||||||
if toml_conf.get("autotuning") is None:
|
|
||||||
return cls.default()
|
|
||||||
autotuning_conf = toml_conf["autotuning"]
|
|
||||||
|
|
||||||
if autotuning_conf.get("enabled") is None:
|
|
||||||
return cls.default()
|
|
||||||
if not autotuning_conf["enabled"]:
|
|
||||||
return cls.default()
|
|
||||||
|
|
||||||
if autotuning_conf.get("psu_power_limit") is not None:
|
|
||||||
# old autotuning conf
|
|
||||||
return cls.power_tuning(autotuning_conf["psu_power_limit"])
|
|
||||||
if autotuning_conf.get("mode") is not None:
|
|
||||||
# new autotuning conf
|
|
||||||
mode = autotuning_conf["mode"]
|
|
||||||
if mode == "power_target":
|
|
||||||
if autotuning_conf.get("power_target") is not None:
|
|
||||||
return cls.power_tuning(autotuning_conf["power_target"])
|
|
||||||
return cls.power_tuning()
|
|
||||||
if mode == "hashrate_target":
|
|
||||||
if autotuning_conf.get("hashrate_target") is not None:
|
|
||||||
return cls.hashrate_tuning(autotuning_conf["hashrate_target"])
|
|
||||||
return cls.hashrate_tuning()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_vnish(cls, web_settings: dict):
|
|
||||||
try:
|
|
||||||
mode_settings = web_settings["miner"]["overclock"]
|
|
||||||
except KeyError:
|
|
||||||
return cls.default()
|
|
||||||
|
|
||||||
if mode_settings["preset"] == "disabled":
|
|
||||||
return MiningModeManual.from_vnish(mode_settings)
|
|
||||||
else:
|
|
||||||
return cls.power_tuning(int(mode_settings["preset"]))
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_boser(cls, grpc_miner_conf: dict):
|
|
||||||
try:
|
|
||||||
tuner_conf = grpc_miner_conf["tuner"]
|
|
||||||
if not tuner_conf.get("enabled", False):
|
|
||||||
return cls.default()
|
|
||||||
except LookupError:
|
|
||||||
return cls.default()
|
|
||||||
|
|
||||||
if tuner_conf.get("tunerMode") is not None:
|
|
||||||
if tuner_conf["tunerMode"] == 1:
|
|
||||||
if tuner_conf.get("powerTarget") is not None:
|
|
||||||
return cls.power_tuning(tuner_conf["powerTarget"]["watt"])
|
|
||||||
return cls.power_tuning()
|
|
||||||
|
|
||||||
if tuner_conf["tunerMode"] == 2:
|
|
||||||
if tuner_conf.get("hashrateTarget") is not None:
|
|
||||||
return cls.hashrate_tuning(
|
|
||||||
int(tuner_conf["hashrateTarget"]["terahashPerSecond"])
|
|
||||||
)
|
|
||||||
return cls.hashrate_tuning()
|
|
||||||
|
|
||||||
if tuner_conf.get("powerTarget") is not None:
|
|
||||||
return cls.power_tuning(tuner_conf["powerTarget"]["watt"])
|
|
||||||
|
|
||||||
if tuner_conf.get("hashrateTarget") is not None:
|
|
||||||
return cls.hashrate_tuning(
|
|
||||||
int(tuner_conf["hashrateTarget"]["terahashPerSecond"])
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_auradine(cls, web_mode: dict):
|
|
||||||
try:
|
|
||||||
mode_data = web_mode["Mode"][0]
|
|
||||||
if mode_data.get("Sleep") == "on":
|
|
||||||
return cls.sleep()
|
|
||||||
if mode_data.get("Mode") == "normal":
|
|
||||||
return cls.normal()
|
|
||||||
if mode_data.get("Mode") == "eco":
|
|
||||||
return cls.low()
|
|
||||||
if mode_data.get("Mode") == "turbo":
|
|
||||||
return cls.high()
|
|
||||||
if mode_data.get("Ths") is not None:
|
|
||||||
return cls.hashrate_tuning(mode_data["Ths"])
|
|
||||||
if mode_data.get("Power") is not None:
|
|
||||||
return cls.power_tuning(mode_data["Power"])
|
|
||||||
except LookupError:
|
|
||||||
return cls.default()
|
|
||||||
676
pyasic/config/mining/__init__.py
Normal file
676
pyasic/config/mining/__init__.py
Normal file
@@ -0,0 +1,676 @@
|
|||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# 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 __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import field
|
||||||
|
from typing import TypeVar, Union
|
||||||
|
|
||||||
|
from pyasic import settings
|
||||||
|
from pyasic.config.base import MinerConfigOption, MinerConfigValue
|
||||||
|
from pyasic.web.braiins_os.proto.braiins.bos.v1 import (
|
||||||
|
DpsHashrateTarget,
|
||||||
|
DpsPowerTarget,
|
||||||
|
DpsTarget,
|
||||||
|
HashrateTargetMode,
|
||||||
|
PerformanceMode,
|
||||||
|
Power,
|
||||||
|
PowerTargetMode,
|
||||||
|
SaveAction,
|
||||||
|
SetDpsRequest,
|
||||||
|
SetPerformanceModeRequest,
|
||||||
|
TeraHashrate,
|
||||||
|
TunerPerformanceMode,
|
||||||
|
)
|
||||||
|
|
||||||
|
from .algo import TunerAlgo, TunerAlgoType
|
||||||
|
from .scaling import ScalingConfig
|
||||||
|
|
||||||
|
|
||||||
|
class MiningModeNormal(MinerConfigValue):
|
||||||
|
mode: str = field(init=False, default="normal")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, dict_conf: dict | None) -> "MiningModeNormal":
|
||||||
|
return cls()
|
||||||
|
|
||||||
|
def as_am_modern(self) -> dict:
|
||||||
|
if settings.get("antminer_mining_mode_as_str", False):
|
||||||
|
return {"miner-mode": "0"}
|
||||||
|
return {"miner-mode": 0}
|
||||||
|
|
||||||
|
def as_wm(self) -> dict:
|
||||||
|
return {"mode": self.mode}
|
||||||
|
|
||||||
|
def as_auradine(self) -> dict:
|
||||||
|
return {"mode": {"mode": self.mode}}
|
||||||
|
|
||||||
|
def as_epic(self) -> dict:
|
||||||
|
return {"ptune": {"enabled": False}}
|
||||||
|
|
||||||
|
def as_goldshell(self) -> dict:
|
||||||
|
return {"settings": {"level": 0}}
|
||||||
|
|
||||||
|
def as_mara(self) -> dict:
|
||||||
|
return {
|
||||||
|
"mode": {
|
||||||
|
"work-mode-selector": "Stock",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def as_luxos(self) -> dict:
|
||||||
|
return {"autotunerset": {"enabled": False}}
|
||||||
|
|
||||||
|
|
||||||
|
class MiningModeSleep(MinerConfigValue):
|
||||||
|
mode: str = field(init=False, default="sleep")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, dict_conf: dict | None) -> "MiningModeSleep":
|
||||||
|
return cls()
|
||||||
|
|
||||||
|
def as_am_modern(self) -> dict:
|
||||||
|
if settings.get("antminer_mining_mode_as_str", False):
|
||||||
|
return {"miner-mode": "1"}
|
||||||
|
return {"miner-mode": 1}
|
||||||
|
|
||||||
|
def as_wm(self) -> dict:
|
||||||
|
return {"mode": self.mode}
|
||||||
|
|
||||||
|
def as_auradine(self) -> dict:
|
||||||
|
return {"mode": {"sleep": "on"}}
|
||||||
|
|
||||||
|
def as_epic(self) -> dict:
|
||||||
|
return {"ptune": {"algo": "Sleep", "target": 0}}
|
||||||
|
|
||||||
|
def as_goldshell(self) -> dict:
|
||||||
|
return {"settings": {"level": 3}}
|
||||||
|
|
||||||
|
def as_mara(self) -> dict:
|
||||||
|
return {
|
||||||
|
"mode": {
|
||||||
|
"work-mode-selector": "Sleep",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class MiningModeLPM(MinerConfigValue):
|
||||||
|
mode: str = field(init=False, default="low")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, dict_conf: dict | None) -> "MiningModeLPM":
|
||||||
|
return cls()
|
||||||
|
|
||||||
|
def as_am_modern(self) -> dict:
|
||||||
|
if settings.get("antminer_mining_mode_as_str", False):
|
||||||
|
return {"miner-mode": "3"}
|
||||||
|
return {"miner-mode": 3}
|
||||||
|
|
||||||
|
def as_wm(self) -> dict:
|
||||||
|
return {"mode": self.mode}
|
||||||
|
|
||||||
|
def as_auradine(self) -> dict:
|
||||||
|
return {"mode": {"mode": "eco"}}
|
||||||
|
|
||||||
|
def as_goldshell(self) -> dict:
|
||||||
|
return {"settings": {"level": 1}}
|
||||||
|
|
||||||
|
|
||||||
|
class MiningModeHPM(MinerConfigValue):
|
||||||
|
mode: str = field(init=False, default="high")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, dict_conf: dict | None) -> "MiningModeHPM":
|
||||||
|
return cls()
|
||||||
|
|
||||||
|
def as_am_modern(self) -> dict:
|
||||||
|
if settings.get("antminer_mining_mode_as_str", False):
|
||||||
|
return {"miner-mode": "0"}
|
||||||
|
return {"miner-mode": 0}
|
||||||
|
|
||||||
|
def as_wm(self) -> dict:
|
||||||
|
return {"mode": self.mode}
|
||||||
|
|
||||||
|
def as_auradine(self) -> dict:
|
||||||
|
return {"mode": {"mode": "turbo"}}
|
||||||
|
|
||||||
|
|
||||||
|
class MiningModePowerTune(MinerConfigValue):
|
||||||
|
class Config:
|
||||||
|
arbitrary_types_allowed = True
|
||||||
|
|
||||||
|
mode: str = field(init=False, default="power_tuning")
|
||||||
|
power: int | None = None
|
||||||
|
algo: TunerAlgoType = field(default_factory=TunerAlgo.default)
|
||||||
|
scaling: ScalingConfig | None = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, dict_conf: dict | None) -> "MiningModePowerTune":
|
||||||
|
cls_conf = {}
|
||||||
|
if dict_conf.get("power"):
|
||||||
|
cls_conf["power"] = dict_conf["power"]
|
||||||
|
if dict_conf.get("algo"):
|
||||||
|
cls_conf["algo"] = TunerAlgo.from_dict(dict_conf["algo"])
|
||||||
|
if dict_conf.get("scaling"):
|
||||||
|
cls_conf["scaling"] = ScalingConfig.from_dict(dict_conf["scaling"])
|
||||||
|
|
||||||
|
return cls(**cls_conf)
|
||||||
|
|
||||||
|
def as_am_modern(self) -> dict:
|
||||||
|
if settings.get("antminer_mining_mode_as_str", False):
|
||||||
|
return {"miner-mode": "0"}
|
||||||
|
return {"miner-mode": 0}
|
||||||
|
|
||||||
|
def as_wm(self) -> dict:
|
||||||
|
if self.power is not None:
|
||||||
|
return {"mode": self.mode, self.mode: {"wattage": self.power}}
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def as_bosminer(self) -> dict:
|
||||||
|
tuning_cfg = {"enabled": True, "mode": "power_target"}
|
||||||
|
if self.power is not None:
|
||||||
|
tuning_cfg["power_target"] = self.power
|
||||||
|
|
||||||
|
cfg = {"autotuning": tuning_cfg}
|
||||||
|
|
||||||
|
if self.scaling is not None:
|
||||||
|
scaling_cfg = {"enabled": True}
|
||||||
|
if self.scaling.step is not None:
|
||||||
|
scaling_cfg["power_step"] = self.scaling.step
|
||||||
|
if self.scaling.minimum is not None:
|
||||||
|
scaling_cfg["min_power_target"] = self.scaling.minimum
|
||||||
|
if self.scaling.shutdown is not None:
|
||||||
|
scaling_cfg = {**scaling_cfg, **self.scaling.shutdown.as_bosminer()}
|
||||||
|
cfg["performance_scaling"] = scaling_cfg
|
||||||
|
|
||||||
|
return cfg
|
||||||
|
|
||||||
|
def as_boser(self) -> dict:
|
||||||
|
cfg = {
|
||||||
|
"set_performance_mode": SetPerformanceModeRequest(
|
||||||
|
save_action=SaveAction.SAVE_AND_APPLY,
|
||||||
|
mode=PerformanceMode(
|
||||||
|
tuner_mode=TunerPerformanceMode(
|
||||||
|
power_target=PowerTargetMode(
|
||||||
|
power_target=Power(watt=self.power)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
if self.scaling is not None:
|
||||||
|
sd_cfg = {}
|
||||||
|
if self.scaling.shutdown is not None:
|
||||||
|
sd_cfg = self.scaling.shutdown.as_boser()
|
||||||
|
cfg["set_dps"] = (
|
||||||
|
SetDpsRequest(
|
||||||
|
enable=True,
|
||||||
|
**sd_cfg,
|
||||||
|
target=DpsTarget(
|
||||||
|
power_target=DpsPowerTarget(
|
||||||
|
power_step=Power(self.scaling.step),
|
||||||
|
min_power_target=Power(self.scaling.minimum),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return cfg
|
||||||
|
|
||||||
|
def as_auradine(self) -> dict:
|
||||||
|
return {"mode": {"mode": "custom", "tune": "power", "power": self.power}}
|
||||||
|
|
||||||
|
def as_mara(self) -> dict:
|
||||||
|
return {
|
||||||
|
"mode": {
|
||||||
|
"work-mode-selector": "Auto",
|
||||||
|
"concorde": {
|
||||||
|
"mode-select": "PowerTarget",
|
||||||
|
"power-target": self.power,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def as_luxos(self) -> dict:
|
||||||
|
return {"autotunerset": {"enabled": True}}
|
||||||
|
|
||||||
|
|
||||||
|
class MiningModeHashrateTune(MinerConfigValue):
|
||||||
|
class Config:
|
||||||
|
arbitrary_types_allowed = True
|
||||||
|
|
||||||
|
mode: str = field(init=False, default="hashrate_tuning")
|
||||||
|
hashrate: int = None
|
||||||
|
algo: TunerAlgoType = field(default_factory=TunerAlgo.default)
|
||||||
|
scaling: ScalingConfig = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, dict_conf: dict | None) -> "MiningModeHashrateTune":
|
||||||
|
cls_conf = {}
|
||||||
|
if dict_conf.get("hashrate"):
|
||||||
|
cls_conf["hashrate"] = dict_conf["hashrate"]
|
||||||
|
if dict_conf.get("algo"):
|
||||||
|
cls_conf["algo"] = TunerAlgo.from_dict(dict_conf["algo"])
|
||||||
|
if dict_conf.get("scaling"):
|
||||||
|
cls_conf["scaling"] = ScalingConfig.from_dict(dict_conf["scaling"])
|
||||||
|
|
||||||
|
return cls(**cls_conf)
|
||||||
|
|
||||||
|
def as_am_modern(self) -> dict:
|
||||||
|
if settings.get("antminer_mining_mode_as_str", False):
|
||||||
|
return {"miner-mode": "0"}
|
||||||
|
return {"miner-mode": 0}
|
||||||
|
|
||||||
|
def as_bosminer(self) -> dict:
|
||||||
|
conf = {"enabled": True, "mode": "hashrate_target"}
|
||||||
|
if self.hashrate is not None:
|
||||||
|
conf["hashrate_target"] = self.hashrate
|
||||||
|
return {"autotuning": conf}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def as_boser(self) -> dict:
|
||||||
|
cfg = {
|
||||||
|
"set_performance_mode": SetPerformanceModeRequest(
|
||||||
|
save_action=SaveAction.SAVE_AND_APPLY,
|
||||||
|
mode=PerformanceMode(
|
||||||
|
tuner_mode=TunerPerformanceMode(
|
||||||
|
hashrate_target=HashrateTargetMode(
|
||||||
|
hashrate_target=TeraHashrate(
|
||||||
|
terahash_per_second=self.hashrate
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if self.scaling is not None:
|
||||||
|
sd_cfg = {}
|
||||||
|
if self.scaling.shutdown is not None:
|
||||||
|
sd_cfg = self.scaling.shutdown.as_boser()
|
||||||
|
cfg["set_dps"] = (
|
||||||
|
SetDpsRequest(
|
||||||
|
enable=True,
|
||||||
|
**sd_cfg,
|
||||||
|
target=DpsTarget(
|
||||||
|
hashrate_target=DpsHashrateTarget(
|
||||||
|
hashrate_step=TeraHashrate(self.scaling.step),
|
||||||
|
min_hashrate_target=TeraHashrate(self.scaling.minimum),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return cfg
|
||||||
|
|
||||||
|
def as_auradine(self) -> dict:
|
||||||
|
return {"mode": {"mode": "custom", "tune": "ths", "ths": self.hashrate}}
|
||||||
|
|
||||||
|
def as_epic(self) -> dict:
|
||||||
|
mode = {
|
||||||
|
"ptune": {
|
||||||
|
"algo": self.algo.as_epic(),
|
||||||
|
"target": self.hashrate,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if self.scaling is not None:
|
||||||
|
if self.scaling.minimum is not None:
|
||||||
|
mode["ptune"]["min_throttle"] = self.scaling.minimum
|
||||||
|
if self.scaling.step is not None:
|
||||||
|
mode["ptune"]["throttle_step"] = self.scaling.step
|
||||||
|
return mode
|
||||||
|
|
||||||
|
def as_mara(self) -> dict:
|
||||||
|
return {
|
||||||
|
"mode": {
|
||||||
|
"work-mode-selector": "Auto",
|
||||||
|
"concorde": {
|
||||||
|
"mode-select": "Hashrate",
|
||||||
|
"hash-target": self.hashrate,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def as_luxos(self) -> dict:
|
||||||
|
return {"autotunerset": {"enabled": True}}
|
||||||
|
|
||||||
|
|
||||||
|
class ManualBoardSettings(MinerConfigValue):
|
||||||
|
freq: float
|
||||||
|
volt: float
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, dict_conf: dict | None) -> "ManualBoardSettings":
|
||||||
|
return cls(freq=dict_conf["freq"], volt=dict_conf["volt"])
|
||||||
|
|
||||||
|
def as_am_modern(self) -> dict:
|
||||||
|
if settings.get("antminer_mining_mode_as_str", False):
|
||||||
|
return {"miner-mode": "0"}
|
||||||
|
return {"miner-mode": 0}
|
||||||
|
|
||||||
|
def as_vnish(self) -> dict:
|
||||||
|
return {"freq": self.freq}
|
||||||
|
|
||||||
|
|
||||||
|
class MiningModeManual(MinerConfigValue):
|
||||||
|
mode: str = field(init=False, default="manual")
|
||||||
|
|
||||||
|
global_freq: float
|
||||||
|
global_volt: float
|
||||||
|
boards: dict[int, ManualBoardSettings] = field(default_factory=dict)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, dict_conf: dict | None) -> "MiningModeManual":
|
||||||
|
return cls(
|
||||||
|
global_freq=dict_conf["global_freq"],
|
||||||
|
global_volt=dict_conf["global_volt"],
|
||||||
|
boards={i: ManualBoardSettings.from_dict(dict_conf[i]) for i in dict_conf},
|
||||||
|
)
|
||||||
|
|
||||||
|
def as_am_modern(self) -> dict:
|
||||||
|
if settings.get("antminer_mining_mode_as_str", False):
|
||||||
|
return {"miner-mode": "0"}
|
||||||
|
return {"miner-mode": 0}
|
||||||
|
|
||||||
|
def as_vnish(self) -> dict:
|
||||||
|
return {
|
||||||
|
"overclock": {
|
||||||
|
"chains": [b.as_vnish() for b in self.boards.values() if b.freq != 0],
|
||||||
|
"globals": {
|
||||||
|
"freq": int(self.global_freq),
|
||||||
|
"volt": int(self.global_volt),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_vnish(cls, web_overclock_settings: dict) -> "MiningModeManual":
|
||||||
|
# will raise KeyError if it cant find the settings, values cannot be empty
|
||||||
|
voltage = web_overclock_settings["globals"]["volt"]
|
||||||
|
freq = web_overclock_settings["globals"]["freq"]
|
||||||
|
boards = {
|
||||||
|
idx: ManualBoardSettings(
|
||||||
|
freq=board["freq"],
|
||||||
|
volt=voltage if not board["freq"] == 0 else 0,
|
||||||
|
)
|
||||||
|
for idx, board in enumerate(web_overclock_settings["chains"])
|
||||||
|
}
|
||||||
|
return cls(global_freq=freq, global_volt=voltage, boards=boards)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_epic(cls, epic_conf: dict) -> "MiningModeManual":
|
||||||
|
voltage = 0
|
||||||
|
freq = 0
|
||||||
|
if epic_conf.get("HwConfig") is not None:
|
||||||
|
freq = epic_conf["HwConfig"]["Boards Target Clock"][0]["Data"]
|
||||||
|
if epic_conf.get("Power Supply Stats") is not None:
|
||||||
|
voltage = epic_conf["Power Supply Stats"]["Target Voltage"]
|
||||||
|
boards = {}
|
||||||
|
if epic_conf.get("HBs") is not None:
|
||||||
|
boards = {
|
||||||
|
board["Index"]: ManualBoardSettings(
|
||||||
|
freq=board["Core Clock Avg"], volt=board["Input Voltage"]
|
||||||
|
)
|
||||||
|
for board in epic_conf["HBs"]
|
||||||
|
}
|
||||||
|
return cls(global_freq=freq, global_volt=voltage, boards=boards)
|
||||||
|
|
||||||
|
def as_mara(self) -> dict:
|
||||||
|
return {
|
||||||
|
"mode": {
|
||||||
|
"work-mode-selector": "Fixed",
|
||||||
|
"fixed": {
|
||||||
|
"frequency": str(self.global_freq),
|
||||||
|
"voltage": self.global_volt,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class MiningModeConfig(MinerConfigOption):
|
||||||
|
normal = MiningModeNormal
|
||||||
|
low = MiningModeLPM
|
||||||
|
high = MiningModeHPM
|
||||||
|
sleep = MiningModeSleep
|
||||||
|
power_tuning = MiningModePowerTune
|
||||||
|
hashrate_tuning = MiningModeHashrateTune
|
||||||
|
manual = MiningModeManual
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def default(cls):
|
||||||
|
return cls.normal()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, dict_conf: dict | None):
|
||||||
|
if dict_conf is None:
|
||||||
|
return cls.default()
|
||||||
|
|
||||||
|
mode = dict_conf.get("mode")
|
||||||
|
if mode is None:
|
||||||
|
return cls.default()
|
||||||
|
|
||||||
|
cls_attr = getattr(cls, mode)
|
||||||
|
if cls_attr is not None:
|
||||||
|
return cls_attr().from_dict(dict_conf)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_am_modern(cls, web_conf: dict):
|
||||||
|
if web_conf.get("bitmain-work-mode") is not None:
|
||||||
|
work_mode = web_conf["bitmain-work-mode"]
|
||||||
|
if work_mode == "":
|
||||||
|
return cls.default()
|
||||||
|
if int(work_mode) == 0:
|
||||||
|
return cls.normal()
|
||||||
|
elif int(work_mode) == 1:
|
||||||
|
return cls.sleep()
|
||||||
|
elif int(work_mode) == 3:
|
||||||
|
return cls.low()
|
||||||
|
return cls.default()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_epic(cls, web_conf: dict):
|
||||||
|
try:
|
||||||
|
tuner_running = web_conf["PerpetualTune"]["Running"]
|
||||||
|
if tuner_running:
|
||||||
|
algo_info = web_conf["PerpetualTune"]["Algorithm"]
|
||||||
|
if algo_info.get("VoltageOptimizer") is not None:
|
||||||
|
scaling_cfg = None
|
||||||
|
if "Throttle Step" in algo_info["VoltageOptimizer"]:
|
||||||
|
scaling_cfg = ScalingConfig(
|
||||||
|
minimum=algo_info["VoltageOptimizer"].get(
|
||||||
|
"Min Throttle Target"
|
||||||
|
),
|
||||||
|
step=algo_info["VoltageOptimizer"].get("Throttle Step"),
|
||||||
|
)
|
||||||
|
|
||||||
|
return cls.hashrate_tuning(
|
||||||
|
hashrate=algo_info["VoltageOptimizer"].get("Target"),
|
||||||
|
algo=TunerAlgo.voltage_optimizer(),
|
||||||
|
scaling=scaling_cfg,
|
||||||
|
)
|
||||||
|
elif algo_info.get("BoardTune") is not None:
|
||||||
|
scaling_cfg = None
|
||||||
|
if "Throttle Step" in algo_info["BoardTune"]:
|
||||||
|
scaling_cfg = ScalingConfig(
|
||||||
|
minimum=algo_info["BoardTune"].get("Min Throttle Target"),
|
||||||
|
step=algo_info["BoardTune"].get("Throttle Step"),
|
||||||
|
)
|
||||||
|
|
||||||
|
return cls.hashrate_tuning(
|
||||||
|
hashrate=algo_info["BoardTune"].get("Target"),
|
||||||
|
algo=TunerAlgo.board_tune(),
|
||||||
|
scaling=scaling_cfg,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return cls.hashrate_tuning(
|
||||||
|
hashrate=algo_info["ChipTune"].get("Target"),
|
||||||
|
algo=TunerAlgo.chip_tune(),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return MiningModeManual.from_epic(web_conf)
|
||||||
|
except KeyError:
|
||||||
|
return cls.default()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_bosminer(cls, toml_conf: dict):
|
||||||
|
if toml_conf.get("autotuning") is None:
|
||||||
|
return cls.default()
|
||||||
|
autotuning_conf = toml_conf["autotuning"]
|
||||||
|
|
||||||
|
if autotuning_conf.get("enabled") is None:
|
||||||
|
return cls.default()
|
||||||
|
if not autotuning_conf["enabled"]:
|
||||||
|
return cls.default()
|
||||||
|
|
||||||
|
if autotuning_conf.get("psu_power_limit") is not None:
|
||||||
|
# old autotuning conf
|
||||||
|
return cls.power_tuning(
|
||||||
|
power=autotuning_conf["psu_power_limit"],
|
||||||
|
scaling=ScalingConfig.from_bosminer(toml_conf, mode="power"),
|
||||||
|
)
|
||||||
|
if autotuning_conf.get("mode") is not None:
|
||||||
|
# new autotuning conf
|
||||||
|
mode = autotuning_conf["mode"]
|
||||||
|
if mode == "power_target":
|
||||||
|
if autotuning_conf.get("power_target") is not None:
|
||||||
|
return cls.power_tuning(
|
||||||
|
power=autotuning_conf["power_target"],
|
||||||
|
scaling=ScalingConfig.from_bosminer(toml_conf, mode="power"),
|
||||||
|
)
|
||||||
|
return cls.power_tuning(
|
||||||
|
scaling=ScalingConfig.from_bosminer(toml_conf, mode="power"),
|
||||||
|
)
|
||||||
|
if mode == "hashrate_target":
|
||||||
|
if autotuning_conf.get("hashrate_target") is not None:
|
||||||
|
return cls.hashrate_tuning(
|
||||||
|
hashrate=autotuning_conf["hashrate_target"],
|
||||||
|
scaling=ScalingConfig.from_bosminer(toml_conf, mode="hashrate"),
|
||||||
|
)
|
||||||
|
return cls.hashrate_tuning(
|
||||||
|
scaling=ScalingConfig.from_bosminer(toml_conf, mode="hashrate"),
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_vnish(cls, web_settings: dict):
|
||||||
|
try:
|
||||||
|
mode_settings = web_settings["miner"]["overclock"]
|
||||||
|
except KeyError:
|
||||||
|
return cls.default()
|
||||||
|
|
||||||
|
if mode_settings["preset"] == "disabled":
|
||||||
|
return MiningModeManual.from_vnish(mode_settings)
|
||||||
|
else:
|
||||||
|
return cls.power_tuning(power=int(mode_settings["preset"]))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_boser(cls, grpc_miner_conf: dict):
|
||||||
|
try:
|
||||||
|
tuner_conf = grpc_miner_conf["tuner"]
|
||||||
|
if not tuner_conf.get("enabled", False):
|
||||||
|
return cls.default()
|
||||||
|
except LookupError:
|
||||||
|
return cls.default()
|
||||||
|
|
||||||
|
if tuner_conf.get("tunerMode") is not None:
|
||||||
|
if tuner_conf["tunerMode"] == 1:
|
||||||
|
if tuner_conf.get("powerTarget") is not None:
|
||||||
|
return cls.power_tuning(
|
||||||
|
power=tuner_conf["powerTarget"]["watt"],
|
||||||
|
scaling=ScalingConfig.from_boser(grpc_miner_conf, mode="power"),
|
||||||
|
)
|
||||||
|
return cls.power_tuning(
|
||||||
|
scaling=ScalingConfig.from_boser(grpc_miner_conf, mode="power")
|
||||||
|
)
|
||||||
|
|
||||||
|
if tuner_conf["tunerMode"] == 2:
|
||||||
|
if tuner_conf.get("hashrateTarget") is not None:
|
||||||
|
return cls.hashrate_tuning(
|
||||||
|
hashrate=int(tuner_conf["hashrateTarget"]["terahashPerSecond"]),
|
||||||
|
scaling=ScalingConfig.from_boser(
|
||||||
|
grpc_miner_conf, mode="hashrate"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return cls.hashrate_tuning(
|
||||||
|
scaling=ScalingConfig.from_boser(grpc_miner_conf, mode="hashrate"),
|
||||||
|
)
|
||||||
|
|
||||||
|
if tuner_conf.get("powerTarget") is not None:
|
||||||
|
return cls.power_tuning(
|
||||||
|
power=tuner_conf["powerTarget"]["watt"],
|
||||||
|
scaling=ScalingConfig.from_boser(grpc_miner_conf, mode="power"),
|
||||||
|
)
|
||||||
|
|
||||||
|
if tuner_conf.get("hashrateTarget") is not None:
|
||||||
|
return cls.hashrate_tuning(
|
||||||
|
hashrate=int(tuner_conf["hashrateTarget"]["terahashPerSecond"]),
|
||||||
|
scaling=ScalingConfig.from_boser(grpc_miner_conf, mode="hashrate"),
|
||||||
|
)
|
||||||
|
|
||||||
|
return cls.default()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_auradine(cls, web_mode: dict):
|
||||||
|
try:
|
||||||
|
mode_data = web_mode["Mode"][0]
|
||||||
|
if mode_data.get("Sleep") == "on":
|
||||||
|
return cls.sleep()
|
||||||
|
if mode_data.get("Mode") == "normal":
|
||||||
|
return cls.normal()
|
||||||
|
if mode_data.get("Mode") == "eco":
|
||||||
|
return cls.low()
|
||||||
|
if mode_data.get("Mode") == "turbo":
|
||||||
|
return cls.high()
|
||||||
|
if mode_data.get("Ths") is not None:
|
||||||
|
return cls.hashrate_tuning(hashrate=mode_data["Ths"])
|
||||||
|
if mode_data.get("Power") is not None:
|
||||||
|
return cls.power_tuning(power=mode_data["Power"])
|
||||||
|
except LookupError:
|
||||||
|
return cls.default()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_mara(cls, web_config: dict):
|
||||||
|
try:
|
||||||
|
mode = web_config["mode"]["work-mode-selector"]
|
||||||
|
if mode == "Fixed":
|
||||||
|
fixed_conf = web_config["mode"]["fixed"]
|
||||||
|
return cls.manual(
|
||||||
|
global_freq=int(fixed_conf["frequency"]),
|
||||||
|
global_volt=fixed_conf["voltage"],
|
||||||
|
)
|
||||||
|
elif mode == "Stock":
|
||||||
|
return cls.normal()
|
||||||
|
elif mode == "Sleep":
|
||||||
|
return cls.sleep()
|
||||||
|
elif mode == "Auto":
|
||||||
|
auto_conf = web_config["mode"]["concorde"]
|
||||||
|
auto_mode = auto_conf["mode-select"]
|
||||||
|
if auto_mode == "Hashrate":
|
||||||
|
return cls.hashrate_tuning(hashrate=auto_conf["hash-target"])
|
||||||
|
elif auto_mode == "PowerTarget":
|
||||||
|
return cls.power_tuning(power=auto_conf["power-target"])
|
||||||
|
except LookupError:
|
||||||
|
pass
|
||||||
|
return cls.default()
|
||||||
|
|
||||||
|
|
||||||
|
MiningMode = TypeVar(
|
||||||
|
"MiningMode",
|
||||||
|
bound=Union[
|
||||||
|
MiningModeNormal,
|
||||||
|
MiningModeHPM,
|
||||||
|
MiningModeLPM,
|
||||||
|
MiningModeSleep,
|
||||||
|
MiningModeManual,
|
||||||
|
MiningModePowerTune,
|
||||||
|
MiningModeHashrateTune,
|
||||||
|
],
|
||||||
|
)
|
||||||
66
pyasic/config/mining/algo.py
Normal file
66
pyasic/config/mining/algo.py
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from typing import TypeVar, Union
|
||||||
|
|
||||||
|
from pyasic.config.base import MinerConfigOption, MinerConfigValue
|
||||||
|
|
||||||
|
|
||||||
|
class StandardTuneAlgo(MinerConfigValue):
|
||||||
|
mode: str = field(init=False, default="standard")
|
||||||
|
|
||||||
|
def as_epic(self) -> str:
|
||||||
|
return VOptAlgo().as_epic()
|
||||||
|
|
||||||
|
|
||||||
|
class VOptAlgo(MinerConfigValue):
|
||||||
|
mode: str = field(init=False, default="voltage_optimizer")
|
||||||
|
|
||||||
|
def as_epic(self) -> str:
|
||||||
|
return "VoltageOptimizer"
|
||||||
|
|
||||||
|
|
||||||
|
class BoardTuneAlgo(MinerConfigValue):
|
||||||
|
mode: str = field(init=False, default="board_tune")
|
||||||
|
|
||||||
|
def as_epic(self) -> str:
|
||||||
|
return "BoardTune"
|
||||||
|
|
||||||
|
|
||||||
|
class ChipTuneAlgo(MinerConfigValue):
|
||||||
|
mode: str = field(init=False, default="chip_tune")
|
||||||
|
|
||||||
|
def as_epic(self) -> str:
|
||||||
|
return "ChipTune"
|
||||||
|
|
||||||
|
|
||||||
|
class TunerAlgo(MinerConfigOption):
|
||||||
|
standard = StandardTuneAlgo
|
||||||
|
voltage_optimizer = VOptAlgo
|
||||||
|
board_tune = BoardTuneAlgo
|
||||||
|
chip_tune = ChipTuneAlgo
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def default(cls) -> TunerAlgoType:
|
||||||
|
return cls.standard()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, dict_conf: dict | None) -> TunerAlgoType:
|
||||||
|
mode = dict_conf.get("mode")
|
||||||
|
if mode is None:
|
||||||
|
return cls.default()
|
||||||
|
|
||||||
|
cls_attr = getattr(cls, mode)
|
||||||
|
if cls_attr is not None:
|
||||||
|
return cls_attr().from_dict(dict_conf)
|
||||||
|
|
||||||
|
|
||||||
|
TunerAlgoType = TypeVar(
|
||||||
|
"TunerAlgoType",
|
||||||
|
bound=Union[
|
||||||
|
StandardTuneAlgo,
|
||||||
|
VOptAlgo,
|
||||||
|
BoardTuneAlgo,
|
||||||
|
ChipTuneAlgo,
|
||||||
|
],
|
||||||
|
)
|
||||||
131
pyasic/config/mining/scaling.py
Normal file
131
pyasic/config/mining/scaling.py
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# 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 __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
from pyasic.config.base import MinerConfigValue
|
||||||
|
|
||||||
|
|
||||||
|
class ScalingShutdown(MinerConfigValue):
|
||||||
|
enabled: bool = False
|
||||||
|
duration: int = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, dict_conf: dict | None) -> "ScalingShutdown":
|
||||||
|
return cls(
|
||||||
|
enabled=dict_conf.get("enabled", False), duration=dict_conf.get("duration")
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_bosminer(cls, power_scaling_conf: dict):
|
||||||
|
sd_enabled = power_scaling_conf.get("shutdown_enabled")
|
||||||
|
if sd_enabled is not None:
|
||||||
|
return cls(
|
||||||
|
enabled=sd_enabled, duration=power_scaling_conf.get("shutdown_duration")
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_boser(cls, power_scaling_conf: dict):
|
||||||
|
sd_enabled = power_scaling_conf.get("shutdownEnabled")
|
||||||
|
if sd_enabled is not None:
|
||||||
|
try:
|
||||||
|
return cls(
|
||||||
|
enabled=sd_enabled,
|
||||||
|
duration=power_scaling_conf["shutdownDuration"]["hours"],
|
||||||
|
)
|
||||||
|
except KeyError:
|
||||||
|
return cls(enabled=sd_enabled)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def as_bosminer(self) -> dict:
|
||||||
|
cfg = {"shutdown_enabled": self.enabled}
|
||||||
|
|
||||||
|
if self.duration is not None:
|
||||||
|
cfg["shutdown_duration"] = self.duration
|
||||||
|
|
||||||
|
return cfg
|
||||||
|
|
||||||
|
def as_boser(self) -> dict:
|
||||||
|
return {"enable_shutdown": self.enabled, "shutdown_duration": self.duration}
|
||||||
|
|
||||||
|
|
||||||
|
class ScalingConfig(MinerConfigValue):
|
||||||
|
step: int = None
|
||||||
|
minimum: int = None
|
||||||
|
shutdown: ScalingShutdown = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, dict_conf: dict | None) -> "ScalingConfig":
|
||||||
|
cls_conf = {
|
||||||
|
"step": dict_conf.get("step"),
|
||||||
|
"minimum": dict_conf.get("minimum"),
|
||||||
|
}
|
||||||
|
shutdown = dict_conf.get("shutdown")
|
||||||
|
if shutdown is not None:
|
||||||
|
cls_conf["shutdown"] = ScalingShutdown.from_dict(shutdown)
|
||||||
|
return cls(**cls_conf)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_bosminer(cls, toml_conf: dict, mode: str = None):
|
||||||
|
if mode == "power":
|
||||||
|
return cls._from_bosminer_power(toml_conf)
|
||||||
|
if mode == "hashrate":
|
||||||
|
# not implemented yet
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _from_bosminer_power(cls, toml_conf: dict):
|
||||||
|
power_scaling = toml_conf.get("power_scaling")
|
||||||
|
if power_scaling is None:
|
||||||
|
power_scaling = toml_conf.get("performance_scaling")
|
||||||
|
if power_scaling is not None:
|
||||||
|
enabled = power_scaling.get("enabled")
|
||||||
|
if not enabled:
|
||||||
|
return None
|
||||||
|
power_step = power_scaling.get("power_step")
|
||||||
|
min_power = power_scaling.get("min_psu_power_limit")
|
||||||
|
if min_power is None:
|
||||||
|
min_power = power_scaling.get("min_power_target")
|
||||||
|
sd_mode = ScalingShutdown.from_bosminer(power_scaling)
|
||||||
|
|
||||||
|
return cls(step=power_step, minimum=min_power, shutdown=sd_mode)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_boser(cls, grpc_miner_conf: dict, mode: str = None):
|
||||||
|
if mode == "power":
|
||||||
|
return cls._from_boser_power(grpc_miner_conf)
|
||||||
|
if mode == "hashrate":
|
||||||
|
# not implemented yet
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _from_boser_power(cls, grpc_miner_conf: dict):
|
||||||
|
try:
|
||||||
|
dps_conf = grpc_miner_conf["dps"]
|
||||||
|
if not dps_conf.get("enabled", False):
|
||||||
|
return None
|
||||||
|
except LookupError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
conf = {"shutdown": ScalingShutdown.from_boser(dps_conf)}
|
||||||
|
|
||||||
|
if dps_conf.get("minPowerTarget") is not None:
|
||||||
|
conf["minimum"] = dps_conf["minPowerTarget"]["watt"]
|
||||||
|
if dps_conf.get("powerStep") is not None:
|
||||||
|
conf["step"] = dps_conf["powerStep"]["watt"]
|
||||||
|
return cls(**conf)
|
||||||
@@ -17,13 +17,20 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import random
|
import random
|
||||||
import string
|
import string
|
||||||
from dataclasses import dataclass, field
|
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
|
from pydantic import Field
|
||||||
|
|
||||||
from pyasic.config.base import MinerConfigValue
|
from pyasic.config.base import MinerConfigValue
|
||||||
|
from pyasic.web.braiins_os.proto.braiins.bos.v1 import (
|
||||||
|
PoolConfiguration,
|
||||||
|
PoolGroupConfiguration,
|
||||||
|
Quota,
|
||||||
|
SaveAction,
|
||||||
|
SetPoolGroupsRequest,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class Pool(MinerConfigValue):
|
class Pool(MinerConfigValue):
|
||||||
url: str
|
url: str
|
||||||
user: str
|
user: str
|
||||||
@@ -118,6 +125,36 @@ class Pool(MinerConfigValue):
|
|||||||
}
|
}
|
||||||
return {"pool": self.url, "login": self.user, "password": self.password}
|
return {"pool": self.url, "login": self.user, "password": self.password}
|
||||||
|
|
||||||
|
def as_mara(self, user_suffix: str = None) -> dict:
|
||||||
|
if user_suffix is not None:
|
||||||
|
return {
|
||||||
|
"url": self.url,
|
||||||
|
"user": f"{self.user}{user_suffix}",
|
||||||
|
"pass": self.password,
|
||||||
|
}
|
||||||
|
return {"url": self.url, "user": self.user, "pass": self.password}
|
||||||
|
|
||||||
|
def as_bitaxe(self, user_suffix: str = None) -> dict:
|
||||||
|
return {
|
||||||
|
"stratumURL": self.url,
|
||||||
|
"stratumUser": f"{self.user}{user_suffix}",
|
||||||
|
"stratumPassword": self.password,
|
||||||
|
}
|
||||||
|
|
||||||
|
def as_boser(self) -> PoolConfiguration:
|
||||||
|
return PoolConfiguration(
|
||||||
|
url=self.url, user=self.user, password=self.password, enabled=True
|
||||||
|
)
|
||||||
|
|
||||||
|
def as_vnish(self, user_suffix: str = None) -> dict:
|
||||||
|
if user_suffix is not None:
|
||||||
|
return {
|
||||||
|
"url": self.url,
|
||||||
|
"user": f"{self.user}{user_suffix}",
|
||||||
|
"pass": self.password,
|
||||||
|
}
|
||||||
|
return {"url": self.url, "user": self.user, "pass": self.password}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, dict_conf: dict | None) -> "Pool":
|
def from_dict(cls, dict_conf: dict | None) -> "Pool":
|
||||||
return cls(
|
return cls(
|
||||||
@@ -164,7 +201,7 @@ class Pool(MinerConfigValue):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def from_vnish(cls, web_pool: dict) -> "Pool":
|
def from_vnish(cls, web_pool: dict) -> "Pool":
|
||||||
return cls(
|
return cls(
|
||||||
url=web_pool["url"],
|
url="stratum+tcp://" + web_pool["url"],
|
||||||
user=web_pool["user"],
|
user=web_pool["user"],
|
||||||
password=web_pool["pass"],
|
password=web_pool["pass"],
|
||||||
)
|
)
|
||||||
@@ -177,12 +214,40 @@ class Pool(MinerConfigValue):
|
|||||||
password=grpc_pool["password"],
|
password=grpc_pool["password"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_mara(cls, web_pool: dict) -> "Pool":
|
||||||
|
return cls(
|
||||||
|
url=web_pool["url"],
|
||||||
|
user=web_pool["user"],
|
||||||
|
password=web_pool["pass"],
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_bitaxe(cls, web_system_info: dict) -> "Pool":
|
||||||
|
url = f"stratum+tcp://{web_system_info['stratumURL']}:{web_system_info['stratumPort']}"
|
||||||
|
return cls(
|
||||||
|
url=url,
|
||||||
|
user=web_system_info["stratumUser"],
|
||||||
|
password=web_system_info.get("stratumPassword", ""),
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_luxos(cls, rpc_pools: dict) -> "Pool":
|
||||||
|
return cls.from_api(rpc_pools)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_iceriver(cls, web_pool: dict) -> "Pool":
|
||||||
|
return cls(
|
||||||
|
url=web_pool["addr"],
|
||||||
|
user=web_pool["user"],
|
||||||
|
password=web_pool["pass"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class PoolGroup(MinerConfigValue):
|
class PoolGroup(MinerConfigValue):
|
||||||
pools: list[Pool] = field(default_factory=list)
|
pools: list[Pool] = Field(default_factory=list)
|
||||||
quota: int = 1
|
quota: int = 1
|
||||||
name: str = None
|
name: str | None = None
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
if self.name is None:
|
if self.name is None:
|
||||||
@@ -197,7 +262,7 @@ class PoolGroup(MinerConfigValue):
|
|||||||
if len(self.pools) > idx:
|
if len(self.pools) > idx:
|
||||||
pools.append(self.pools[idx].as_am_modern(user_suffix=user_suffix))
|
pools.append(self.pools[idx].as_am_modern(user_suffix=user_suffix))
|
||||||
else:
|
else:
|
||||||
pools.append(Pool("", "", "").as_am_modern())
|
pools.append(Pool(url="", user="", password="").as_am_modern())
|
||||||
idx += 1
|
idx += 1
|
||||||
return pools
|
return pools
|
||||||
|
|
||||||
@@ -210,7 +275,7 @@ class PoolGroup(MinerConfigValue):
|
|||||||
**self.pools[idx].as_wm(idx=idx + 1, user_suffix=user_suffix)
|
**self.pools[idx].as_wm(idx=idx + 1, user_suffix=user_suffix)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
pools.update(**Pool("", "", "").as_wm(idx=idx + 1))
|
pools.update(**Pool(url="", user="", password="").as_wm(idx=idx + 1))
|
||||||
idx += 1
|
idx += 1
|
||||||
return pools
|
return pools
|
||||||
|
|
||||||
@@ -223,7 +288,9 @@ class PoolGroup(MinerConfigValue):
|
|||||||
**self.pools[idx].as_am_old(idx=idx + 1, user_suffix=user_suffix)
|
**self.pools[idx].as_am_old(idx=idx + 1, user_suffix=user_suffix)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
pools.update(**Pool("", "", "").as_am_old(idx=idx + 1))
|
pools.update(
|
||||||
|
**Pool(url="", user="", password="").as_am_old(idx=idx + 1)
|
||||||
|
)
|
||||||
idx += 1
|
idx += 1
|
||||||
return pools
|
return pools
|
||||||
|
|
||||||
@@ -233,7 +300,7 @@ class PoolGroup(MinerConfigValue):
|
|||||||
def as_avalon(self, user_suffix: str = None) -> str:
|
def as_avalon(self, user_suffix: str = None) -> str:
|
||||||
if len(self.pools) > 0:
|
if len(self.pools) > 0:
|
||||||
return self.pools[0].as_avalon(user_suffix=user_suffix)
|
return self.pools[0].as_avalon(user_suffix=user_suffix)
|
||||||
return Pool("", "", "").as_avalon()
|
return Pool(url="", user="", password="").as_avalon()
|
||||||
|
|
||||||
def as_inno(self, user_suffix: str = None) -> dict:
|
def as_inno(self, user_suffix: str = None) -> dict:
|
||||||
pools = {}
|
pools = {}
|
||||||
@@ -244,7 +311,7 @@ class PoolGroup(MinerConfigValue):
|
|||||||
**self.pools[idx].as_inno(idx=idx + 1, user_suffix=user_suffix)
|
**self.pools[idx].as_inno(idx=idx + 1, user_suffix=user_suffix)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
pools.update(**Pool("", "", "").as_inno(idx=idx + 1))
|
pools.update(**Pool(url="", user="", password="").as_inno(idx=idx + 1))
|
||||||
idx += 1
|
idx += 1
|
||||||
return pools
|
return pools
|
||||||
|
|
||||||
@@ -264,16 +331,24 @@ class PoolGroup(MinerConfigValue):
|
|||||||
def as_auradine(self, user_suffix: str = None) -> list:
|
def as_auradine(self, user_suffix: str = None) -> list:
|
||||||
return [p.as_auradine(user_suffix=user_suffix) for p in self.pools]
|
return [p.as_auradine(user_suffix=user_suffix) for p in self.pools]
|
||||||
|
|
||||||
def as_epic(self, user_suffix: str = None) -> dict:
|
def as_epic(self, user_suffix: str = None) -> list:
|
||||||
if len(self.pools) > 0:
|
return [p.as_epic(user_suffix=user_suffix) for p in self.pools]
|
||||||
conf = {
|
|
||||||
"name": self.name,
|
def as_mara(self, user_suffix: str = None) -> list:
|
||||||
"pool": [pool.as_epic(user_suffix=user_suffix) for pool in self.pools],
|
return [p.as_mara(user_suffix=user_suffix) for p in self.pools]
|
||||||
}
|
|
||||||
if self.quota is not None:
|
def as_bitaxe(self, user_suffix: str = None) -> dict:
|
||||||
conf["quota"] = self.quota
|
return self.pools[0].as_bitaxe(user_suffix=user_suffix)
|
||||||
return conf
|
|
||||||
return {"name": self.name, "pool": []}
|
def as_boser(self, user_suffix: str = None) -> PoolGroupConfiguration:
|
||||||
|
return PoolGroupConfiguration(
|
||||||
|
name=self.name,
|
||||||
|
quota=Quota(value=self.quota),
|
||||||
|
pools=[p.as_boser() for p in self.pools],
|
||||||
|
)
|
||||||
|
|
||||||
|
def as_vnish(self, user_suffix: str = None) -> dict:
|
||||||
|
return {"pools": [p.as_vnish(user_suffix=user_suffix) for p in self.pools]}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, dict_conf: dict | None) -> "PoolGroup":
|
def from_dict(cls, dict_conf: dict | None) -> "PoolGroup":
|
||||||
@@ -309,11 +384,11 @@ class PoolGroup(MinerConfigValue):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_goldshell(cls, web_pools: list) -> "PoolGroup":
|
def from_goldshell(cls, web_pools: list) -> "PoolGroup":
|
||||||
return cls([Pool.from_goldshell(p) for p in web_pools])
|
return cls(pools=[Pool.from_goldshell(p) for p in web_pools])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_inno(cls, web_pools: list) -> "PoolGroup":
|
def from_inno(cls, web_pools: list) -> "PoolGroup":
|
||||||
return cls([Pool.from_inno(p) for p in web_pools])
|
return cls(pools=[Pool.from_inno(p) for p in web_pools])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_bosminer(cls, toml_group_conf: dict) -> "PoolGroup":
|
def from_bosminer(cls, toml_group_conf: dict) -> "PoolGroup":
|
||||||
@@ -327,7 +402,7 @@ class PoolGroup(MinerConfigValue):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_vnish(cls, web_settings_pools: dict) -> "PoolGroup":
|
def from_vnish(cls, web_settings_pools: dict) -> "PoolGroup":
|
||||||
return cls([Pool.from_vnish(p) for p in web_settings_pools])
|
return cls(pools=[Pool.from_vnish(p) for p in web_settings_pools])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_boser(cls, grpc_pool_group: dict) -> "PoolGroup":
|
def from_boser(cls, grpc_pool_group: dict) -> "PoolGroup":
|
||||||
@@ -335,17 +410,35 @@ class PoolGroup(MinerConfigValue):
|
|||||||
return cls(
|
return cls(
|
||||||
pools=[Pool.from_boser(p) for p in grpc_pool_group["pools"]],
|
pools=[Pool.from_boser(p) for p in grpc_pool_group["pools"]],
|
||||||
name=grpc_pool_group["name"],
|
name=grpc_pool_group["name"],
|
||||||
quota=grpc_pool_group["quota"]["value"]
|
quota=(
|
||||||
if grpc_pool_group.get("quota") is not None
|
grpc_pool_group["quota"]["value"]
|
||||||
else 1,
|
if grpc_pool_group.get("quota") is not None
|
||||||
|
else 1
|
||||||
|
),
|
||||||
)
|
)
|
||||||
except LookupError:
|
except LookupError:
|
||||||
return cls()
|
return cls()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_mara(cls, web_config_pools: dict) -> "PoolGroup":
|
||||||
|
return cls(pools=[Pool.from_mara(pool_conf) for pool_conf in web_config_pools])
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_bitaxe(cls, web_system_info: dict) -> "PoolGroup":
|
||||||
|
return cls(pools=[Pool.from_bitaxe(web_system_info)])
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_iceriver(cls, web_userpanel: dict) -> "PoolGroup":
|
||||||
|
return cls(
|
||||||
|
pools=[
|
||||||
|
Pool.from_iceriver(web_pool)
|
||||||
|
for web_pool in web_userpanel["data"]["pools"]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class PoolConfig(MinerConfigValue):
|
class PoolConfig(MinerConfigValue):
|
||||||
groups: List[PoolGroup] = field(default_factory=list)
|
groups: List[PoolGroup] = Field(default_factory=list)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def default(cls) -> "PoolConfig":
|
def default(cls) -> "PoolConfig":
|
||||||
@@ -405,7 +498,12 @@ class PoolConfig(MinerConfigValue):
|
|||||||
return {"group": [PoolGroup().as_bosminer()]}
|
return {"group": [PoolGroup().as_bosminer()]}
|
||||||
|
|
||||||
def as_boser(self, user_suffix: str = None) -> dict:
|
def as_boser(self, user_suffix: str = None) -> dict:
|
||||||
return {}
|
return {
|
||||||
|
"set_pool_groups": SetPoolGroupsRequest(
|
||||||
|
save_action=SaveAction.SAVE_AND_APPLY,
|
||||||
|
pool_groups=[g.as_boser(user_suffix=user_suffix) for g in self.groups],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
def as_auradine(self, user_suffix: str = None) -> dict:
|
def as_auradine(self, user_suffix: str = None) -> dict:
|
||||||
if len(self.groups) > 0:
|
if len(self.groups) > 0:
|
||||||
@@ -421,9 +519,7 @@ class PoolConfig(MinerConfigValue):
|
|||||||
return {
|
return {
|
||||||
"pools": {
|
"pools": {
|
||||||
"coin": "Btc",
|
"coin": "Btc",
|
||||||
"stratum_configs": [
|
"stratum_configs": self.groups[0].as_epic(user_suffix=user_suffix),
|
||||||
g.as_epic(user_suffix=user_suffix) for g in self.groups
|
|
||||||
],
|
|
||||||
"unique_id": False,
|
"unique_id": False,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -435,6 +531,20 @@ class PoolConfig(MinerConfigValue):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def as_mara(self, user_suffix: str = None) -> dict:
|
||||||
|
if len(self.groups) > 0:
|
||||||
|
return {"pools": self.groups[0].as_mara(user_suffix=user_suffix)}
|
||||||
|
return {"pools": []}
|
||||||
|
|
||||||
|
def as_bitaxe(self, user_suffix: str = None) -> dict:
|
||||||
|
return self.groups[0].as_bitaxe(user_suffix=user_suffix)
|
||||||
|
|
||||||
|
def as_luxos(self, user_suffix: str = None) -> dict:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def as_vnish(self, user_suffix: str = None) -> dict:
|
||||||
|
return self.groups[0].as_vnish(user_suffix=user_suffix)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_api(cls, api_pools: dict) -> "PoolConfig":
|
def from_api(cls, api_pools: dict) -> "PoolConfig":
|
||||||
try:
|
try:
|
||||||
@@ -443,38 +553,38 @@ class PoolConfig(MinerConfigValue):
|
|||||||
return PoolConfig.default()
|
return PoolConfig.default()
|
||||||
pool_data = sorted(pool_data, key=lambda x: int(x["POOL"]))
|
pool_data = sorted(pool_data, key=lambda x: int(x["POOL"]))
|
||||||
|
|
||||||
return cls([PoolGroup.from_api(pool_data)])
|
return cls(groups=[PoolGroup.from_api(pool_data)])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_epic(cls, web_conf: dict) -> "PoolConfig":
|
def from_epic(cls, web_conf: dict) -> "PoolConfig":
|
||||||
pool_data = web_conf["StratumConfigs"]
|
pool_data = web_conf["StratumConfigs"]
|
||||||
return cls([PoolGroup.from_epic(pool_data)])
|
return cls(groups=[PoolGroup.from_epic(pool_data)])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_am_modern(cls, web_conf: dict) -> "PoolConfig":
|
def from_am_modern(cls, web_conf: dict) -> "PoolConfig":
|
||||||
pool_data = web_conf["pools"]
|
pool_data = web_conf["pools"]
|
||||||
|
|
||||||
return cls([PoolGroup.from_am_modern(pool_data)])
|
return cls(groups=[PoolGroup.from_am_modern(pool_data)])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_goldshell(cls, web_pools: list) -> "PoolConfig":
|
def from_goldshell(cls, web_pools: list) -> "PoolConfig":
|
||||||
return cls([PoolGroup.from_goldshell(web_pools)])
|
return cls(groups=[PoolGroup.from_goldshell(web_pools)])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_inno(cls, web_pools: list) -> "PoolConfig":
|
def from_inno(cls, web_pools: list) -> "PoolConfig":
|
||||||
return cls([PoolGroup.from_inno(web_pools)])
|
return cls(groups=[PoolGroup.from_inno(web_pools)])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_bosminer(cls, toml_conf: dict) -> "PoolConfig":
|
def from_bosminer(cls, toml_conf: dict) -> "PoolConfig":
|
||||||
if toml_conf.get("group") is None:
|
if toml_conf.get("group") is None:
|
||||||
return cls()
|
return cls()
|
||||||
|
|
||||||
return cls([PoolGroup.from_bosminer(g) for g in toml_conf["group"]])
|
return cls(groups=[PoolGroup.from_bosminer(g) for g in toml_conf["group"]])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_vnish(cls, web_settings: dict) -> "PoolConfig":
|
def from_vnish(cls, web_settings: dict) -> "PoolConfig":
|
||||||
try:
|
try:
|
||||||
return cls([PoolGroup.from_vnish(web_settings["miner"]["pools"])])
|
return cls(groups=[PoolGroup.from_vnish(web_settings["miner"]["pools"])])
|
||||||
except LookupError:
|
except LookupError:
|
||||||
return cls()
|
return cls()
|
||||||
|
|
||||||
@@ -489,3 +599,32 @@ class PoolConfig(MinerConfigValue):
|
|||||||
)
|
)
|
||||||
except LookupError:
|
except LookupError:
|
||||||
return cls()
|
return cls()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_mara(cls, web_config: dict) -> "PoolConfig":
|
||||||
|
return cls(groups=[PoolGroup.from_mara(web_config["pools"])])
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_bitaxe(cls, web_system_info: dict) -> "PoolConfig":
|
||||||
|
return cls(groups=[PoolGroup.from_bitaxe(web_system_info)])
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_iceriver(cls, web_userpanel: dict) -> "PoolConfig":
|
||||||
|
return cls(groups=[PoolGroup.from_iceriver(web_userpanel)])
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_luxos(cls, rpc_groups: dict, rpc_pools: dict) -> "PoolConfig":
|
||||||
|
return cls(
|
||||||
|
groups=[
|
||||||
|
PoolGroup(
|
||||||
|
pools=[
|
||||||
|
Pool.from_luxos(pool)
|
||||||
|
for pool in rpc_pools["POOLS"]
|
||||||
|
if pool["GROUP"] == group["GROUP"]
|
||||||
|
],
|
||||||
|
name=group["Name"],
|
||||||
|
quota=group["Quota"],
|
||||||
|
)
|
||||||
|
for group in rpc_groups["GROUPS"]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,217 +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. -
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from dataclasses import dataclass, field
|
|
||||||
|
|
||||||
from pyasic.config.base import MinerConfigOption, MinerConfigValue
|
|
||||||
from pyasic.web.braiins_os.proto.braiins.bos.v1 import (
|
|
||||||
DpsPowerTarget,
|
|
||||||
DpsTarget,
|
|
||||||
Power,
|
|
||||||
SetDpsRequest,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class PowerScalingShutdownEnabled(MinerConfigValue):
|
|
||||||
mode: str = field(init=False, default="enabled")
|
|
||||||
duration: int = None
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_dict(cls, dict_conf: dict | None) -> "PowerScalingShutdownEnabled":
|
|
||||||
return cls(duration=dict_conf.get("duration"))
|
|
||||||
|
|
||||||
def as_bosminer(self) -> dict:
|
|
||||||
cfg = {"shutdown_enabled": True}
|
|
||||||
|
|
||||||
if self.duration is not None:
|
|
||||||
cfg["shutdown_duration"] = self.duration
|
|
||||||
|
|
||||||
return cfg
|
|
||||||
|
|
||||||
def as_boser(self) -> dict:
|
|
||||||
return {"enable_shutdown": True, "shutdown_duration": self.duration}
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class PowerScalingShutdownDisabled(MinerConfigValue):
|
|
||||||
mode: str = field(init=False, default="disabled")
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_dict(cls, dict_conf: dict | None) -> "PowerScalingShutdownDisabled":
|
|
||||||
return cls()
|
|
||||||
|
|
||||||
def as_bosminer(self) -> dict:
|
|
||||||
return {"shutdown_enabled": False}
|
|
||||||
|
|
||||||
def as_boser(self) -> dict:
|
|
||||||
return {"enable_shutdown ": False}
|
|
||||||
|
|
||||||
|
|
||||||
class PowerScalingShutdown(MinerConfigOption):
|
|
||||||
enabled = PowerScalingShutdownEnabled
|
|
||||||
disabled = PowerScalingShutdownDisabled
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_dict(cls, dict_conf: dict | None):
|
|
||||||
if dict_conf is None:
|
|
||||||
return cls.default()
|
|
||||||
|
|
||||||
mode = dict_conf.get("mode")
|
|
||||||
if mode is None:
|
|
||||||
return cls.default()
|
|
||||||
|
|
||||||
clsattr = getattr(cls, mode)
|
|
||||||
if clsattr is not None:
|
|
||||||
return clsattr().from_dict(dict_conf)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_bosminer(cls, power_scaling_conf: dict):
|
|
||||||
sd_enabled = power_scaling_conf.get("shutdown_enabled")
|
|
||||||
if sd_enabled is not None:
|
|
||||||
if sd_enabled:
|
|
||||||
return cls.enabled(power_scaling_conf.get("shutdown_duration"))
|
|
||||||
else:
|
|
||||||
return cls.disabled()
|
|
||||||
return None
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_boser(cls, power_scaling_conf: dict):
|
|
||||||
sd_enabled = power_scaling_conf.get("shutdownEnabled")
|
|
||||||
if sd_enabled is not None:
|
|
||||||
if sd_enabled:
|
|
||||||
try:
|
|
||||||
return cls.enabled(power_scaling_conf["shutdownDuration"]["hours"])
|
|
||||||
except KeyError:
|
|
||||||
return cls.enabled()
|
|
||||||
else:
|
|
||||||
return cls.disabled()
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class PowerScalingEnabled(MinerConfigValue):
|
|
||||||
mode: str = field(init=False, default="enabled")
|
|
||||||
power_step: int = None
|
|
||||||
minimum_power: int = None
|
|
||||||
shutdown_enabled: PowerScalingShutdownEnabled | PowerScalingShutdownDisabled = None
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_bosminer(cls, power_scaling_conf: dict) -> "PowerScalingEnabled":
|
|
||||||
power_step = power_scaling_conf.get("power_step")
|
|
||||||
min_power = power_scaling_conf.get("min_psu_power_limit")
|
|
||||||
sd_mode = PowerScalingShutdown.from_bosminer(power_scaling_conf)
|
|
||||||
|
|
||||||
return cls(
|
|
||||||
power_step=power_step, minimum_power=min_power, shutdown_enabled=sd_mode
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_dict(cls, dict_conf: dict | None) -> "PowerScalingEnabled":
|
|
||||||
cls_conf = {
|
|
||||||
"power_step": dict_conf.get("power_step"),
|
|
||||||
"minimum_power": dict_conf.get("minimum_power"),
|
|
||||||
}
|
|
||||||
shutdown_enabled = dict_conf.get("shutdown_enabled")
|
|
||||||
if shutdown_enabled is not None:
|
|
||||||
cls_conf["shutdown_enabled"] = PowerScalingShutdown.from_dict(
|
|
||||||
shutdown_enabled
|
|
||||||
)
|
|
||||||
return cls(**cls_conf)
|
|
||||||
|
|
||||||
def as_bosminer(self) -> dict:
|
|
||||||
cfg = {"enabled": True}
|
|
||||||
if self.power_step is not None:
|
|
||||||
cfg["power_step"] = self.power_step
|
|
||||||
if self.minimum_power is not None:
|
|
||||||
cfg["min_psu_power_limit"] = self.minimum_power
|
|
||||||
|
|
||||||
if self.shutdown_enabled is not None:
|
|
||||||
cfg = {**cfg, **self.shutdown_enabled.as_bosminer()}
|
|
||||||
|
|
||||||
return {"power_scaling": cfg}
|
|
||||||
|
|
||||||
def as_boser(self) -> dict:
|
|
||||||
return {
|
|
||||||
"set_dps": SetDpsRequest(
|
|
||||||
enable=True,
|
|
||||||
**self.shutdown_enabled.as_boser(),
|
|
||||||
target=DpsTarget(
|
|
||||||
power_target=DpsPowerTarget(
|
|
||||||
power_step=Power(self.power_step),
|
|
||||||
min_power_target=Power(self.minimum_power),
|
|
||||||
)
|
|
||||||
),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class PowerScalingDisabled(MinerConfigValue):
|
|
||||||
mode: str = field(init=False, default="disabled")
|
|
||||||
|
|
||||||
|
|
||||||
class PowerScalingConfig(MinerConfigOption):
|
|
||||||
enabled = PowerScalingEnabled
|
|
||||||
disabled = PowerScalingDisabled
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def default(cls):
|
|
||||||
return cls.disabled()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_dict(cls, dict_conf: dict | None):
|
|
||||||
if dict_conf is None:
|
|
||||||
return cls.default()
|
|
||||||
|
|
||||||
mode = dict_conf.get("mode")
|
|
||||||
if mode is None:
|
|
||||||
return cls.default()
|
|
||||||
|
|
||||||
clsattr = getattr(cls, mode)
|
|
||||||
if clsattr is not None:
|
|
||||||
return clsattr().from_dict(dict_conf)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_bosminer(cls, toml_conf: dict):
|
|
||||||
power_scaling = toml_conf.get("power_scaling")
|
|
||||||
if power_scaling is not None:
|
|
||||||
enabled = power_scaling.get("enabled")
|
|
||||||
if enabled is not None:
|
|
||||||
if enabled:
|
|
||||||
return cls.enabled().from_bosminer(power_scaling)
|
|
||||||
else:
|
|
||||||
return cls.disabled()
|
|
||||||
|
|
||||||
return cls.default()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_boser(cls, grpc_miner_conf: dict):
|
|
||||||
try:
|
|
||||||
dps_conf = grpc_miner_conf["dps"]
|
|
||||||
if not dps_conf.get("enabled", False):
|
|
||||||
return cls.disabled()
|
|
||||||
except LookupError:
|
|
||||||
return cls.default()
|
|
||||||
|
|
||||||
conf = {"shutdown_enabled": PowerScalingShutdown.from_boser(dps_conf)}
|
|
||||||
|
|
||||||
if dps_conf.get("minPowerTarget") is not None:
|
|
||||||
conf["minimum_power"] = dps_conf["minPowerTarget"]["watt"]
|
|
||||||
if dps_conf.get("powerStep") is not None:
|
|
||||||
conf["power_step"] = dps_conf["powerStep"]["watt"]
|
|
||||||
return cls.enabled(**conf)
|
|
||||||
@@ -20,11 +20,10 @@ from dataclasses import dataclass
|
|||||||
from pyasic.config.base import MinerConfigValue
|
from pyasic.config.base import MinerConfigValue
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class TemperatureConfig(MinerConfigValue):
|
class TemperatureConfig(MinerConfigValue):
|
||||||
target: int = None
|
target: int | None = None
|
||||||
hot: int = None
|
hot: int | None = None
|
||||||
danger: int = None
|
danger: int | None = None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def default(cls):
|
def default(cls):
|
||||||
@@ -38,18 +37,28 @@ class TemperatureConfig(MinerConfigValue):
|
|||||||
temp_cfg["hot_temp"] = self.hot
|
temp_cfg["hot_temp"] = self.hot
|
||||||
if self.danger is not None:
|
if self.danger is not None:
|
||||||
temp_cfg["dangerous_temp"] = self.danger
|
temp_cfg["dangerous_temp"] = self.danger
|
||||||
|
if len(temp_cfg) == 0:
|
||||||
|
return {}
|
||||||
return {"temp_control": temp_cfg}
|
return {"temp_control": temp_cfg}
|
||||||
|
|
||||||
def as_epic(self) -> dict:
|
def as_epic(self) -> dict:
|
||||||
temps_config = {"temps": {}, "fans": {"Auto": {}}}
|
temps_config = {"temps": {}, "fans": {"Auto": {}}}
|
||||||
if self.target is not None:
|
if self.target is not None:
|
||||||
temps_config["fans"]["Target Temperature"] = self.target
|
temps_config["fans"]["Auto"]["Target Temperature"] = self.target
|
||||||
else:
|
else:
|
||||||
temps_config["fans"]["Target Temperature"] = 60
|
temps_config["fans"]["Auto"]["Target Temperature"] = 60
|
||||||
if self.danger is not None:
|
if self.danger is not None:
|
||||||
temps_config["temps"]["shutdown"] = self.danger
|
temps_config["temps"]["critical"] = self.danger
|
||||||
|
if self.hot is not None:
|
||||||
|
temps_config["temps"]["shutdown"] = self.hot
|
||||||
return temps_config
|
return temps_config
|
||||||
|
|
||||||
|
def as_luxos(self) -> dict:
|
||||||
|
return {"tempctrlset": [self.target or "", self.hot or "", self.danger or ""]}
|
||||||
|
|
||||||
|
def as_vnish(self) -> dict:
|
||||||
|
return {"misc": {"restart_temp": self.danger}}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, dict_conf: dict | None) -> "TemperatureConfig":
|
def from_dict(cls, dict_conf: dict | None) -> "TemperatureConfig":
|
||||||
return cls(
|
return cls(
|
||||||
@@ -67,26 +76,38 @@ class TemperatureConfig(MinerConfigValue):
|
|||||||
hot=temp_control.get("hot_temp"),
|
hot=temp_control.get("hot_temp"),
|
||||||
danger=temp_control.get("dangerous_temp"),
|
danger=temp_control.get("dangerous_temp"),
|
||||||
)
|
)
|
||||||
|
return cls()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_epic(cls, web_conf: dict) -> "TemperatureConfig":
|
def from_epic(cls, web_conf: dict) -> "TemperatureConfig":
|
||||||
try:
|
try:
|
||||||
dangerous_temp = web_conf["Misc"]["Shutdown Temp"]
|
dangerous_temp = web_conf["Misc"]["Critical Temp"]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
dangerous_temp = None
|
dangerous_temp = None
|
||||||
|
try:
|
||||||
|
hot_temp = web_conf["Misc"]["Shutdown Temp"]
|
||||||
|
except KeyError:
|
||||||
|
hot_temp = None
|
||||||
# Need to do this in two blocks to avoid KeyError if one is missing
|
# Need to do this in two blocks to avoid KeyError if one is missing
|
||||||
try:
|
try:
|
||||||
target_temp = web_conf["Fans"]["Fan Mode"]["Auto"]["Target Temperature"]
|
target_temp = web_conf["Fans"]["Fan Mode"]["Auto"]["Target Temperature"]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
target_temp = None
|
target_temp = None
|
||||||
|
|
||||||
return cls(target=target_temp, danger=dangerous_temp)
|
return cls(target=target_temp, hot=hot_temp, danger=dangerous_temp)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_vnish(cls, web_settings: dict) -> "TemperatureConfig":
|
def from_vnish(cls, web_settings: dict) -> "TemperatureConfig":
|
||||||
|
try:
|
||||||
|
dangerous_temp = web_settings["misc"]["restart_temp"]
|
||||||
|
except KeyError:
|
||||||
|
dangerous_temp = None
|
||||||
try:
|
try:
|
||||||
if web_settings["miner"]["cooling"]["mode"]["name"] == "auto":
|
if web_settings["miner"]["cooling"]["mode"]["name"] == "auto":
|
||||||
return cls(target=web_settings["miner"]["cooling"]["mode"]["param"])
|
return cls(
|
||||||
|
target=web_settings["miner"]["cooling"]["mode"]["param"],
|
||||||
|
danger=dangerous_temp,
|
||||||
|
)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
return cls()
|
return cls()
|
||||||
@@ -121,3 +142,16 @@ class TemperatureConfig(MinerConfigValue):
|
|||||||
|
|
||||||
return cls(**conf)
|
return cls(**conf)
|
||||||
return cls.default()
|
return cls.default()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_luxos(cls, rpc_tempctrl: dict) -> "TemperatureConfig":
|
||||||
|
try:
|
||||||
|
tempctrl_config = rpc_tempctrl["TEMPCTRL"][0]
|
||||||
|
return cls(
|
||||||
|
target=tempctrl_config.get("Target"),
|
||||||
|
hot=tempctrl_config.get("Hot"),
|
||||||
|
danger=tempctrl_config.get("Dangerous"),
|
||||||
|
)
|
||||||
|
except LookupError:
|
||||||
|
pass
|
||||||
|
return cls.default()
|
||||||
|
|||||||
@@ -15,22 +15,24 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
import json
|
|
||||||
import time
|
import time
|
||||||
from dataclasses import asdict, dataclass, field, fields
|
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from typing import Any, List, Union
|
from typing import Any, List, Union
|
||||||
|
|
||||||
|
from pydantic import BaseModel, Field, computed_field, field_serializer
|
||||||
|
|
||||||
from pyasic.config import MinerConfig
|
from pyasic.config import MinerConfig
|
||||||
from pyasic.config.mining import MiningModePowerTune
|
from pyasic.config.mining import MiningModePowerTune
|
||||||
|
from pyasic.data.pools import PoolMetrics, Scheme
|
||||||
|
from pyasic.device.algorithm.hashrate import AlgoHashRateType
|
||||||
|
|
||||||
from .boards import HashBoard
|
from .boards import HashBoard
|
||||||
|
from .device import DeviceInfo
|
||||||
from .error_codes import BraiinsOSError, InnosiliconError, WhatsminerError, X19Error
|
from .error_codes import BraiinsOSError, InnosiliconError, WhatsminerError, X19Error
|
||||||
from .fans import Fan
|
from .fans import Fan
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
class MinerData(BaseModel):
|
||||||
class MinerData:
|
|
||||||
"""A Dataclass to standardize data returned from miners (specifically `AnyMiner().get_data()`)
|
"""A Dataclass to standardize data returned from miners (specifically `AnyMiner().get_data()`)
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
@@ -38,20 +40,24 @@ class MinerData:
|
|||||||
datetime: The time and date this data was generated.
|
datetime: The time and date this data was generated.
|
||||||
uptime: The uptime of the miner in seconds.
|
uptime: The uptime of the miner in seconds.
|
||||||
mac: The MAC address of the miner as a str.
|
mac: The MAC address of the miner as a str.
|
||||||
|
device_info: Info about the device, such as model, make, and firmware.
|
||||||
model: The model of the miner as a str.
|
model: The model of the miner as a str.
|
||||||
make: The make of the miner as a str.
|
make: The make of the miner as a str.
|
||||||
|
firmware: The firmware on the miner as a str.
|
||||||
|
algo: The mining algorithm of the miner as a str.
|
||||||
api_ver: The current api version on the miner as a str.
|
api_ver: The current api version on the miner as a str.
|
||||||
fw_ver: The current firmware version on the miner as a str.
|
fw_ver: The current firmware version on the miner as a str.
|
||||||
hostname: The network hostname of the miner as a str.
|
hostname: The network hostname of the miner as a str.
|
||||||
hashrate: The hashrate of the miner in TH/s as a float. Calculated automatically.
|
hashrate: The hashrate of the miner in TH/s as a float. Calculated automatically.
|
||||||
_hashrate: Backup for hashrate found via API instead of hashboards.
|
|
||||||
expected_hashrate: The factory nominal hashrate of the miner in TH/s as a float.
|
expected_hashrate: The factory nominal hashrate of the miner in TH/s as a float.
|
||||||
hashboards: A list of [`HashBoard`][pyasic.data.HashBoard]s on the miner with their statistics.
|
hashboards: A list of [`HashBoard`][pyasic.data.HashBoard]s on the miner with their statistics.
|
||||||
temperature_avg: The average temperature across the boards. Calculated automatically.
|
temperature_avg: The average temperature across the boards. Calculated automatically.
|
||||||
env_temp: The environment temps as a float.
|
env_temp: The environment temps as a float.
|
||||||
wattage: Current power draw of the miner as an int.
|
wattage: Current power draw of the miner as an int.
|
||||||
|
voltage: Current output voltage of the PSU as an float.
|
||||||
wattage_limit: Power limit of the miner as an int.
|
wattage_limit: Power limit of the miner as an int.
|
||||||
fans: A list of fans on the miner with their speeds.
|
fans: A list of fans on the miner with their speeds.
|
||||||
|
expected_fans: The number of fans expected on a miner.
|
||||||
fan_psu: The speed of the PSU on the fan if the miner collects it.
|
fan_psu: The speed of the PSU on the fan if the miner collects it.
|
||||||
total_chips: The total number of chips on all boards. Calculated automatically.
|
total_chips: The total number of chips on all boards. Calculated automatically.
|
||||||
expected_chips: The expected number of chips in the miner as an int.
|
expected_chips: The expected number of chips in the miner as an int.
|
||||||
@@ -64,53 +70,73 @@ class MinerData:
|
|||||||
fault_light: Whether the fault light is on as a boolean.
|
fault_light: Whether the fault light is on as a boolean.
|
||||||
efficiency: Efficiency of the miner in J/TH (Watts per TH/s). Calculated automatically.
|
efficiency: Efficiency of the miner in J/TH (Watts per TH/s). Calculated automatically.
|
||||||
is_mining: Whether the miner is mining.
|
is_mining: Whether the miner is mining.
|
||||||
|
pools: A list of PoolMetrics instances, each representing metrics for a pool.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# general
|
||||||
ip: str
|
ip: str
|
||||||
datetime: datetime = None
|
raw_datetime: datetime = Field(
|
||||||
uptime: int = None
|
exclude=True, default_factory=datetime.now(timezone.utc).astimezone, repr=False
|
||||||
mac: str = None
|
)
|
||||||
model: str = None
|
|
||||||
make: str = None
|
# about
|
||||||
api_ver: str = None
|
device_info: DeviceInfo | None = None
|
||||||
fw_ver: str = None
|
mac: str | None = None
|
||||||
hostname: str = None
|
api_ver: str | None = None
|
||||||
hashrate: float = field(init=False)
|
fw_ver: str | None = None
|
||||||
_hashrate: float = field(repr=False, default=None)
|
hostname: str | None = None
|
||||||
expected_hashrate: float = None
|
|
||||||
hashboards: List[HashBoard] = field(default_factory=list)
|
# hashrate
|
||||||
expected_hashboards: int = None
|
raw_hashrate: AlgoHashRateType = Field(exclude=True, default=None, repr=False)
|
||||||
temperature_avg: int = field(init=False)
|
|
||||||
env_temp: float = None
|
# expected
|
||||||
wattage: int = None
|
expected_hashrate: AlgoHashRateType | None = None
|
||||||
wattage_limit: int = field(init=False)
|
expected_hashboards: int | None = None
|
||||||
_wattage_limit: int = field(repr=False, default=None)
|
expected_chips: int | None = None
|
||||||
fans: List[Fan] = field(default_factory=list)
|
expected_fans: int | None = None
|
||||||
fan_psu: int = None
|
|
||||||
total_chips: int = field(init=False)
|
# temperature
|
||||||
expected_chips: int = None
|
env_temp: int | None = None
|
||||||
percent_expected_chips: float = field(init=False)
|
|
||||||
percent_expected_hashrate: float = field(init=False)
|
# power
|
||||||
percent_expected_wattage: float = field(init=False)
|
wattage: int | None = None
|
||||||
nominal: bool = field(init=False)
|
voltage: float | None = None
|
||||||
config: MinerConfig = None
|
raw_wattage_limit: int | None = Field(exclude=True, default=None, repr=False)
|
||||||
|
|
||||||
|
# fans
|
||||||
|
fans: List[Fan] = Field(default_factory=list)
|
||||||
|
fan_psu: int | None = None
|
||||||
|
|
||||||
|
# boards
|
||||||
|
hashboards: List[HashBoard] = Field(default_factory=list)
|
||||||
|
|
||||||
|
# config
|
||||||
|
config: MinerConfig | None = None
|
||||||
|
fault_light: bool | None = None
|
||||||
|
|
||||||
|
# errors
|
||||||
errors: List[
|
errors: List[
|
||||||
Union[WhatsminerError, BraiinsOSError, X19Error, InnosiliconError]
|
Union[
|
||||||
] = field(default_factory=list)
|
WhatsminerError,
|
||||||
fault_light: Union[bool, None] = None
|
BraiinsOSError,
|
||||||
efficiency: int = field(init=False)
|
X19Error,
|
||||||
|
InnosiliconError,
|
||||||
|
]
|
||||||
|
] = Field(default_factory=list)
|
||||||
|
|
||||||
|
# mining state
|
||||||
is_mining: bool = True
|
is_mining: bool = True
|
||||||
|
uptime: int | None = None
|
||||||
|
|
||||||
|
# pools
|
||||||
|
pools: list[PoolMetrics] = Field(default_factory=list)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fields(cls):
|
def fields(cls):
|
||||||
return [f.name for f in fields(cls) if not f.name.startswith("_")]
|
return list(cls.model_fields.keys())
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def dict_factory(x):
|
|
||||||
return {k: v for (k, v) in x if not k.startswith("_")}
|
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
self.datetime = datetime.now(timezone.utc).astimezone()
|
self.raw_datetime = datetime.now(timezone.utc).astimezone()
|
||||||
|
|
||||||
def get(self, __key: str, default: Any = None):
|
def get(self, __key: str, default: Any = None):
|
||||||
try:
|
try:
|
||||||
@@ -138,19 +164,19 @@ class MinerData:
|
|||||||
|
|
||||||
def __floordiv__(self, other):
|
def __floordiv__(self, other):
|
||||||
cp = copy.deepcopy(self)
|
cp = copy.deepcopy(self)
|
||||||
for key in self:
|
for key in self.fields():
|
||||||
item = getattr(self, key)
|
item = getattr(self, key)
|
||||||
if isinstance(item, int):
|
if isinstance(item, int):
|
||||||
setattr(cp, key, item // other)
|
setattr(cp, key, item // other)
|
||||||
if isinstance(item, float):
|
if isinstance(item, float):
|
||||||
setattr(cp, key, round(item / other, 2))
|
setattr(cp, key, item / other)
|
||||||
return cp
|
return cp
|
||||||
|
|
||||||
def __add__(self, other):
|
def __add__(self, other):
|
||||||
if not isinstance(other, MinerData):
|
if not isinstance(other, MinerData):
|
||||||
raise TypeError("Cannot add MinerData to non MinerData type.")
|
raise TypeError("Cannot add MinerData to non MinerData type.")
|
||||||
cp = copy.deepcopy(self)
|
cp = copy.deepcopy(self)
|
||||||
for key in self:
|
for key in self.fields():
|
||||||
item = getattr(self, key)
|
item = getattr(self, key)
|
||||||
other_item = getattr(other, key)
|
other_item = getattr(other, key)
|
||||||
if item is None:
|
if item is None:
|
||||||
@@ -170,34 +196,49 @@ class MinerData:
|
|||||||
setattr(cp, key, item & other_item)
|
setattr(cp, key, item & other_item)
|
||||||
return cp
|
return cp
|
||||||
|
|
||||||
|
@computed_field # type: ignore[misc]
|
||||||
@property
|
@property
|
||||||
def hashrate(self): # noqa - Skip PyCharm inspection
|
def hashrate(self) -> AlgoHashRateType:
|
||||||
if len(self.hashboards) > 0:
|
if len(self.hashboards) > 0:
|
||||||
hr_data = []
|
hr_data = []
|
||||||
for item in self.hashboards:
|
for item in self.hashboards:
|
||||||
if item.hashrate is not None:
|
if item.hashrate is not None:
|
||||||
hr_data.append(item.hashrate)
|
hr_data.append(item.hashrate)
|
||||||
if len(hr_data) > 0:
|
if len(hr_data) > 0:
|
||||||
return round(sum(hr_data), 2)
|
return sum(hr_data, start=type(hr_data[0])(rate=0))
|
||||||
return self._hashrate
|
return self.raw_hashrate
|
||||||
|
|
||||||
|
@field_serializer("hashrate")
|
||||||
|
def serialize_hashrate(self, hashrate: AlgoHashRateType | None) -> float:
|
||||||
|
if hashrate is not None:
|
||||||
|
return float(hashrate)
|
||||||
|
|
||||||
|
@field_serializer("expected_hashrate")
|
||||||
|
def serialize_expected_hashrate(
|
||||||
|
self, expected_hashrate: AlgoHashRateType | None, _info
|
||||||
|
) -> float:
|
||||||
|
if expected_hashrate is not None:
|
||||||
|
return float(expected_hashrate)
|
||||||
|
|
||||||
@hashrate.setter
|
@hashrate.setter
|
||||||
def hashrate(self, val):
|
def hashrate(self, val):
|
||||||
self._hashrate = val
|
self.raw_hashrate = val
|
||||||
|
|
||||||
|
@computed_field # type: ignore[misc]
|
||||||
@property
|
@property
|
||||||
def wattage_limit(self): # noqa - Skip PyCharm inspection
|
def wattage_limit(self) -> int:
|
||||||
if self.config is not None:
|
if self.config is not None:
|
||||||
if isinstance(self.config.mining_mode, MiningModePowerTune):
|
if isinstance(self.config.mining_mode, MiningModePowerTune):
|
||||||
return self.config.mining_mode.power
|
return self.config.mining_mode.power
|
||||||
return self._wattage_limit
|
return self.raw_wattage_limit
|
||||||
|
|
||||||
@wattage_limit.setter
|
@wattage_limit.setter
|
||||||
def wattage_limit(self, val: int):
|
def wattage_limit(self, val: int):
|
||||||
self._wattage_limit = val
|
self.raw_wattage_limit = val
|
||||||
|
|
||||||
|
@computed_field # type: ignore[misc]
|
||||||
@property
|
@property
|
||||||
def total_chips(self): # noqa - Skip PyCharm inspection
|
def total_chips(self) -> int | None:
|
||||||
if len(self.hashboards) > 0:
|
if len(self.hashboards) > 0:
|
||||||
chip_data = []
|
chip_data = []
|
||||||
for item in self.hashboards:
|
for item in self.hashboards:
|
||||||
@@ -207,58 +248,45 @@ class MinerData:
|
|||||||
return sum(chip_data)
|
return sum(chip_data)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@total_chips.setter
|
@computed_field # type: ignore[misc]
|
||||||
def total_chips(self, val):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def nominal(self): # noqa - Skip PyCharm inspection
|
def nominal(self) -> bool | None:
|
||||||
if self.total_chips is None or self.expected_chips is None:
|
if self.total_chips is None or self.expected_chips is None:
|
||||||
return None
|
return None
|
||||||
return self.expected_chips == self.total_chips
|
return self.expected_chips == self.total_chips
|
||||||
|
|
||||||
@nominal.setter
|
@computed_field # type: ignore[misc]
|
||||||
def nominal(self, val):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def percent_expected_chips(self): # noqa - Skip PyCharm inspection
|
def percent_expected_chips(self) -> int | None:
|
||||||
if self.total_chips is None or self.expected_chips is None:
|
if self.total_chips is None or self.expected_chips is None:
|
||||||
return None
|
return None
|
||||||
if self.total_chips == 0 or self.expected_chips == 0:
|
if self.total_chips == 0 or self.expected_chips == 0:
|
||||||
return 0
|
return 0
|
||||||
return round((self.total_chips / self.expected_chips) * 100)
|
return round((self.total_chips / self.expected_chips) * 100)
|
||||||
|
|
||||||
@percent_expected_chips.setter
|
@computed_field # type: ignore[misc]
|
||||||
def percent_expected_chips(self, val):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def percent_expected_hashrate(self): # noqa - Skip PyCharm inspection
|
def percent_expected_hashrate(self) -> int | None:
|
||||||
if self.hashrate is None or self.expected_hashrate is None:
|
if self.hashrate is None or self.expected_hashrate is None:
|
||||||
return None
|
return None
|
||||||
if self.hashrate == 0 or self.expected_hashrate == 0:
|
try:
|
||||||
|
return round((self.hashrate / self.expected_hashrate) * 100)
|
||||||
|
except ZeroDivisionError:
|
||||||
return 0
|
return 0
|
||||||
return round((self.hashrate / self.expected_hashrate) * 100)
|
|
||||||
|
|
||||||
@percent_expected_hashrate.setter
|
|
||||||
def percent_expected_hashrate(self, val):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
@computed_field # type: ignore[misc]
|
||||||
@property
|
@property
|
||||||
def percent_expected_wattage(self): # noqa - Skip PyCharm inspection
|
def percent_expected_wattage(self) -> int | None:
|
||||||
if self.wattage_limit is None or self.wattage is None:
|
if self.wattage_limit is None or self.wattage is None:
|
||||||
return None
|
return None
|
||||||
if self.wattage_limit == 0 or self.wattage == 0:
|
try:
|
||||||
|
return round((self.wattage / self.wattage_limit) * 100)
|
||||||
|
except ZeroDivisionError:
|
||||||
return 0
|
return 0
|
||||||
return round((self.wattage / self.wattage_limit) * 100)
|
|
||||||
|
|
||||||
@percent_expected_wattage.setter
|
|
||||||
def percent_expected_wattage(self, val):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
@computed_field # type: ignore[misc]
|
||||||
@property
|
@property
|
||||||
def temperature_avg(self): # noqa - Skip PyCharm inspection
|
def temperature_avg(self) -> int | None:
|
||||||
total_temp = 0
|
total_temp = 0
|
||||||
temp_count = 0
|
temp_count = 0
|
||||||
for hb in self.hashboards:
|
for hb in self.hashboards:
|
||||||
@@ -269,24 +297,55 @@ class MinerData:
|
|||||||
return None
|
return None
|
||||||
return round(total_temp / temp_count)
|
return round(total_temp / temp_count)
|
||||||
|
|
||||||
@temperature_avg.setter
|
@computed_field # type: ignore[misc]
|
||||||
def temperature_avg(self, val):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def efficiency(self): # noqa - Skip PyCharm inspection
|
def efficiency(self) -> int | None:
|
||||||
if self.hashrate is None or self.wattage is None:
|
if self.hashrate is None or self.wattage is None:
|
||||||
return None
|
return None
|
||||||
if self.hashrate == 0 or self.wattage == 0:
|
try:
|
||||||
|
return round(self.wattage / float(self.hashrate))
|
||||||
|
except ZeroDivisionError:
|
||||||
return 0
|
return 0
|
||||||
return round(self.wattage / self.hashrate)
|
|
||||||
|
|
||||||
@efficiency.setter
|
@computed_field # type: ignore[misc]
|
||||||
def efficiency(self, val):
|
@property
|
||||||
pass
|
def datetime(self) -> str:
|
||||||
|
return self.raw_datetime.isoformat()
|
||||||
|
|
||||||
|
@computed_field # type: ignore[misc]
|
||||||
|
@property
|
||||||
|
def timestamp(self) -> int:
|
||||||
|
return int(time.mktime(self.raw_datetime.timetuple()))
|
||||||
|
|
||||||
|
@computed_field # type: ignore[misc]
|
||||||
|
@property
|
||||||
|
def make(self) -> str:
|
||||||
|
if self.device_info.make is not None:
|
||||||
|
return str(self.device_info.make)
|
||||||
|
|
||||||
|
@computed_field # type: ignore[misc]
|
||||||
|
@property
|
||||||
|
def model(self) -> str:
|
||||||
|
if self.device_info.model is not None:
|
||||||
|
return str(self.device_info.model)
|
||||||
|
|
||||||
|
@computed_field # type: ignore[misc]
|
||||||
|
@property
|
||||||
|
def firmware(self) -> str:
|
||||||
|
if self.device_info.firmware is not None:
|
||||||
|
return str(self.device_info.firmware)
|
||||||
|
|
||||||
|
@computed_field # type: ignore[misc]
|
||||||
|
@property
|
||||||
|
def algo(self) -> str:
|
||||||
|
if self.device_info.algo is not None:
|
||||||
|
return str(self.device_info.algo)
|
||||||
|
|
||||||
|
def keys(self) -> list:
|
||||||
|
return list(self.model_fields.keys())
|
||||||
|
|
||||||
def asdict(self) -> dict:
|
def asdict(self) -> dict:
|
||||||
return asdict(self, dict_factory=self.dict_factory)
|
return self.model_dump()
|
||||||
|
|
||||||
def as_dict(self) -> dict:
|
def as_dict(self) -> dict:
|
||||||
"""Get this dataclass as a dictionary.
|
"""Get this dataclass as a dictionary.
|
||||||
@@ -302,9 +361,7 @@ class MinerData:
|
|||||||
Returns:
|
Returns:
|
||||||
A JSON version of this class.
|
A JSON version of this class.
|
||||||
"""
|
"""
|
||||||
data = self.asdict()
|
return self.model_dump_json()
|
||||||
data["datetime"] = str(int(time.mktime(data["datetime"].timetuple())))
|
|
||||||
return json.dumps(data)
|
|
||||||
|
|
||||||
def as_csv(self) -> str:
|
def as_csv(self) -> str:
|
||||||
"""Get this dataclass as CSV.
|
"""Get this dataclass as CSV.
|
||||||
@@ -313,7 +370,6 @@ class MinerData:
|
|||||||
A CSV version of this class with no headers.
|
A CSV version of this class with no headers.
|
||||||
"""
|
"""
|
||||||
data = self.asdict()
|
data = self.asdict()
|
||||||
data["datetime"] = str(int(time.mktime(data["datetime"].timetuple())))
|
|
||||||
errs = []
|
errs = []
|
||||||
for error in data["errors"]:
|
for error in data["errors"]:
|
||||||
errs.append(error["error_message"])
|
errs.append(error["error_message"])
|
||||||
@@ -334,7 +390,7 @@ class MinerData:
|
|||||||
field_data = []
|
field_data = []
|
||||||
|
|
||||||
tags = ["ip", "mac", "model", "hostname"]
|
tags = ["ip", "mac", "model", "hostname"]
|
||||||
for attribute in self:
|
for attribute in self.fields():
|
||||||
if attribute in tags:
|
if attribute in tags:
|
||||||
escaped_data = self.get(attribute, "Unknown").replace(" ", "\\ ")
|
escaped_data = self.get(attribute, "Unknown").replace(" ", "\\ ")
|
||||||
tag_data.append(f"{attribute}={escaped_data}")
|
tag_data.append(f"{attribute}={escaped_data}")
|
||||||
@@ -378,6 +434,6 @@ class MinerData:
|
|||||||
|
|
||||||
tags_str = ",".join(tag_data)
|
tags_str = ",".join(tag_data)
|
||||||
field_str = ",".join(field_data)
|
field_str = ",".join(field_data)
|
||||||
timestamp = str(int(time.mktime(self.datetime.timetuple()) * 1e9))
|
timestamp = str(self.timestamp * 1e9)
|
||||||
|
|
||||||
return " ".join([tags_str, field_str, timestamp])
|
return " ".join([tags_str, field_str, timestamp])
|
||||||
|
|||||||
@@ -13,13 +13,16 @@
|
|||||||
# See the License for the specific language governing permissions and -
|
# See the License for the specific language governing permissions and -
|
||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from dataclasses import dataclass
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
from pydantic import BaseModel, field_serializer
|
||||||
|
|
||||||
@dataclass
|
from pyasic.device.algorithm.hashrate import AlgoHashRateType
|
||||||
class HashBoard:
|
|
||||||
|
|
||||||
|
class HashBoard(BaseModel):
|
||||||
"""A Dataclass to standardize hashboard data.
|
"""A Dataclass to standardize hashboard data.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
@@ -31,16 +34,27 @@ class HashBoard:
|
|||||||
expected_chips: The expected chip count of the board as an int.
|
expected_chips: The expected chip count of the board as an int.
|
||||||
serial_number: The serial number of the board.
|
serial_number: The serial number of the board.
|
||||||
missing: Whether the board is returned from the miners data as a bool.
|
missing: Whether the board is returned from the miners data as a bool.
|
||||||
|
tuned: Whether the board is tuned as a bool.
|
||||||
|
active: Whether the board is currently tuning as a bool.
|
||||||
|
voltage: Current input voltage of the board as a float.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
slot: int = 0
|
slot: int = 0
|
||||||
hashrate: float = None
|
hashrate: AlgoHashRateType | None = None
|
||||||
temp: int = None
|
temp: float | None = None
|
||||||
chip_temp: int = None
|
chip_temp: float | None = None
|
||||||
chips: int = None
|
chips: int | None = None
|
||||||
expected_chips: int = None
|
expected_chips: int | None = None
|
||||||
serial_number: str = None
|
serial_number: str | None = None
|
||||||
missing: bool = True
|
missing: bool = True
|
||||||
|
tuned: bool | None = None
|
||||||
|
active: bool | None = None
|
||||||
|
voltage: float | None = None
|
||||||
|
|
||||||
|
@field_serializer("hashrate")
|
||||||
|
def serialize_hashrate(self, hashrate: AlgoHashRateType | None) -> float:
|
||||||
|
if hashrate is not None:
|
||||||
|
return float(hashrate)
|
||||||
|
|
||||||
def get(self, __key: str, default: Any = None):
|
def get(self, __key: str, default: Any = None):
|
||||||
try:
|
try:
|
||||||
|
|||||||
31
pyasic/data/device.py
Normal file
31
pyasic/data/device.py
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
from pydantic import BaseModel, ConfigDict, field_serializer
|
||||||
|
|
||||||
|
from pyasic.device.algorithm import MinerAlgoType
|
||||||
|
from pyasic.device.firmware import MinerFirmware
|
||||||
|
from pyasic.device.makes import MinerMake
|
||||||
|
from pyasic.device.models import MinerModelType
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceInfo(BaseModel):
|
||||||
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
||||||
|
|
||||||
|
make: MinerMake | None = None
|
||||||
|
model: MinerModelType | None = None
|
||||||
|
firmware: MinerFirmware | None = None
|
||||||
|
algo: type[MinerAlgoType] | None = None
|
||||||
|
|
||||||
|
@field_serializer("make")
|
||||||
|
def serialize_make(self, make: MinerMake, _info):
|
||||||
|
return str(make)
|
||||||
|
|
||||||
|
@field_serializer("model")
|
||||||
|
def serialize_model(self, model: MinerModelType, _info):
|
||||||
|
return str(model)
|
||||||
|
|
||||||
|
@field_serializer("firmware")
|
||||||
|
def serialize_firmware(self, firmware: MinerFirmware, _info):
|
||||||
|
return str(firmware)
|
||||||
|
|
||||||
|
@field_serializer("algo")
|
||||||
|
def serialize_algo(self, algo: MinerAlgoType, _info):
|
||||||
|
return str(algo)
|
||||||
@@ -13,12 +13,10 @@
|
|||||||
# See the License for the specific language governing permissions and -
|
# See the License for the specific language governing permissions and -
|
||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
from pyasic.data.error_codes.base import BaseMinerError
|
||||||
from dataclasses import asdict, dataclass, fields
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
class X19Error(BaseMinerError):
|
||||||
class X19Error:
|
|
||||||
"""A Dataclass to handle error codes of X19 miners.
|
"""A Dataclass to handle error codes of X19 miners.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
@@ -28,10 +26,3 @@ class X19Error:
|
|||||||
|
|
||||||
error_message: str
|
error_message: str
|
||||||
error_code: int = 0
|
error_code: int = 0
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def fields(cls):
|
|
||||||
return fields(cls)
|
|
||||||
|
|
||||||
def asdict(self):
|
|
||||||
return asdict(self)
|
|
||||||
|
|||||||
18
pyasic/data/error_codes/base.py
Normal file
18
pyasic/data/error_codes/base.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class BaseMinerError(BaseModel):
|
||||||
|
@classmethod
|
||||||
|
def fields(cls):
|
||||||
|
return list(cls.model_fields.keys())
|
||||||
|
|
||||||
|
def asdict(self) -> dict:
|
||||||
|
return self.model_dump()
|
||||||
|
|
||||||
|
def as_dict(self) -> dict:
|
||||||
|
"""Get this dataclass as a dictionary.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A dictionary version of this class.
|
||||||
|
"""
|
||||||
|
return self.asdict()
|
||||||
@@ -14,11 +14,10 @@
|
|||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from dataclasses import asdict, dataclass, fields
|
from pyasic.data.error_codes.base import BaseMinerError
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
class BraiinsOSError(BaseMinerError):
|
||||||
class BraiinsOSError:
|
|
||||||
"""A Dataclass to handle error codes of BraiinsOS+ miners.
|
"""A Dataclass to handle error codes of BraiinsOS+ miners.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
@@ -28,10 +27,3 @@ class BraiinsOSError:
|
|||||||
|
|
||||||
error_message: str
|
error_message: str
|
||||||
error_code: int = 0
|
error_code: int = 0
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def fields(cls):
|
|
||||||
return fields(cls)
|
|
||||||
|
|
||||||
def asdict(self):
|
|
||||||
return asdict(self)
|
|
||||||
|
|||||||
@@ -14,11 +14,13 @@
|
|||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from dataclasses import asdict, dataclass, field, fields
|
|
||||||
|
from pydantic import computed_field
|
||||||
|
|
||||||
|
from pyasic.data.error_codes.base import BaseMinerError
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
class InnosiliconError(BaseMinerError):
|
||||||
class InnosiliconError:
|
|
||||||
"""A Dataclass to handle error codes of Innosilicon miners.
|
"""A Dataclass to handle error codes of Innosilicon miners.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
@@ -27,25 +29,14 @@ class InnosiliconError:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
error_code: int
|
error_code: int
|
||||||
error_message: str = field(init=False)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def fields(cls):
|
|
||||||
return fields(cls)
|
|
||||||
|
|
||||||
|
@computed_field # type: ignore[misc]
|
||||||
@property
|
@property
|
||||||
def error_message(self): # noqa - Skip PyCharm inspection
|
def error_message(self) -> str: # noqa - Skip PyCharm inspection
|
||||||
if self.error_code in ERROR_CODES:
|
if self.error_code in ERROR_CODES:
|
||||||
return ERROR_CODES[self.error_code]
|
return ERROR_CODES[self.error_code]
|
||||||
return "Unknown error type."
|
return "Unknown error type."
|
||||||
|
|
||||||
@error_message.setter
|
|
||||||
def error_message(self, val):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def asdict(self):
|
|
||||||
return asdict(self)
|
|
||||||
|
|
||||||
|
|
||||||
ERROR_CODES = {
|
ERROR_CODES = {
|
||||||
21: "The PLUG signal of the hash board is not detected.",
|
21: "The PLUG signal of the hash board is not detected.",
|
||||||
|
|||||||
@@ -13,12 +13,12 @@
|
|||||||
# See the License for the specific language governing permissions and -
|
# See the License for the specific language governing permissions and -
|
||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
from pydantic import computed_field
|
||||||
|
|
||||||
from dataclasses import asdict, dataclass, field, fields
|
from pyasic.data.error_codes.base import BaseMinerError
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
class WhatsminerError(BaseMinerError):
|
||||||
class WhatsminerError:
|
|
||||||
"""A Dataclass to handle error codes of Whatsminers.
|
"""A Dataclass to handle error codes of Whatsminers.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
@@ -27,14 +27,10 @@ class WhatsminerError:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
error_code: int
|
error_code: int
|
||||||
error_message: str = field(init=False)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def fields(cls):
|
|
||||||
return fields(cls)
|
|
||||||
|
|
||||||
|
@computed_field # type: ignore[misc]
|
||||||
@property
|
@property
|
||||||
def error_message(self): # noqa - Skip PyCharm inspection
|
def error_message(self) -> str: # noqa - Skip PyCharm inspection
|
||||||
if len(str(self.error_code)) == 6 and not str(self.error_code)[:1] == "1":
|
if len(str(self.error_code)) == 6 and not str(self.error_code)[:1] == "1":
|
||||||
err_type = int(str(self.error_code)[:2])
|
err_type = int(str(self.error_code)[:2])
|
||||||
err_subtype = int(str(self.error_code)[2:3])
|
err_subtype = int(str(self.error_code)[2:3])
|
||||||
@@ -74,13 +70,6 @@ class WhatsminerError:
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
return "Unknown error type."
|
return "Unknown error type."
|
||||||
|
|
||||||
@error_message.setter
|
|
||||||
def error_message(self, val):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def asdict(self):
|
|
||||||
return asdict(self)
|
|
||||||
|
|
||||||
|
|
||||||
ERROR_CODES = {
|
ERROR_CODES = {
|
||||||
1: { # Fan error
|
1: { # Fan error
|
||||||
|
|||||||
@@ -14,12 +14,12 @@
|
|||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from dataclasses import dataclass
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class Fan:
|
class Fan(BaseModel):
|
||||||
"""A Dataclass to standardize fan data.
|
"""A Dataclass to standardize fan data.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
|
|||||||
94
pyasic/data/pools.py
Normal file
94
pyasic/data/pools.py
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
from enum import Enum
|
||||||
|
from typing import Optional
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
from pydantic import BaseModel, computed_field, model_serializer
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
|
||||||
|
class Scheme(Enum):
|
||||||
|
STRATUM_V1 = "stratum+tcp"
|
||||||
|
STRATUM_V2 = "stratum2+tcp"
|
||||||
|
STRATUM_V1_SSL = "stratum+ssl"
|
||||||
|
|
||||||
|
|
||||||
|
class PoolUrl(BaseModel):
|
||||||
|
scheme: Scheme
|
||||||
|
host: str
|
||||||
|
port: int
|
||||||
|
pubkey: Optional[str] = None
|
||||||
|
|
||||||
|
@model_serializer
|
||||||
|
def serialize(self):
|
||||||
|
return str(self)
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
if self.scheme == Scheme.STRATUM_V2 and self.pubkey:
|
||||||
|
return f"{self.scheme.value}://{self.host}:{self.port}/{self.pubkey}"
|
||||||
|
else:
|
||||||
|
return f"{self.scheme.value}://{self.host}:{self.port}"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_str(cls, url: str) -> Self | None:
|
||||||
|
parsed_url = urlparse(url)
|
||||||
|
if not parsed_url.hostname:
|
||||||
|
return None
|
||||||
|
if not parsed_url.scheme.strip() == "":
|
||||||
|
scheme = Scheme(parsed_url.scheme)
|
||||||
|
else:
|
||||||
|
scheme = Scheme.STRATUM_V1
|
||||||
|
host = parsed_url.hostname
|
||||||
|
port = parsed_url.port
|
||||||
|
pubkey = parsed_url.path.lstrip("/") if scheme == Scheme.STRATUM_V2 else None
|
||||||
|
return cls(scheme=scheme, host=host, port=port, pubkey=pubkey)
|
||||||
|
|
||||||
|
|
||||||
|
class PoolMetrics(BaseModel):
|
||||||
|
"""A dataclass to standardize pool metrics returned from miners.
|
||||||
|
Attributes:
|
||||||
|
|
||||||
|
accepted: Number of accepted shares.
|
||||||
|
rejected: Number of rejected shares.
|
||||||
|
get_failures: Number of failures in obtaining work from the pool.
|
||||||
|
remote_failures: Number of failures communicating with the pool server.
|
||||||
|
active: Indicates if the miner is connected to the stratum server.
|
||||||
|
Alive : Indicates if a pool is alive.
|
||||||
|
url: URL of the pool.
|
||||||
|
index: Index of the pool.
|
||||||
|
user: Username for the pool.
|
||||||
|
pool_rejected_percent: Percentage of rejected shares by the pool.
|
||||||
|
pool_stale_percent: Percentage of stale shares by the pool.
|
||||||
|
"""
|
||||||
|
|
||||||
|
url: PoolUrl | None
|
||||||
|
accepted: int | None = None
|
||||||
|
rejected: int | None = None
|
||||||
|
get_failures: int | None = None
|
||||||
|
remote_failures: int | None = None
|
||||||
|
active: bool | None = None
|
||||||
|
alive: bool | None = None
|
||||||
|
index: int | None = None
|
||||||
|
user: str | None = None
|
||||||
|
|
||||||
|
@computed_field # type: ignore[misc]
|
||||||
|
@property
|
||||||
|
def pool_rejected_percent(self) -> float: # noqa - Skip PyCharm inspection
|
||||||
|
"""Calculate and return the percentage of rejected shares"""
|
||||||
|
return self._calculate_percentage(self.rejected, self.accepted + self.rejected)
|
||||||
|
|
||||||
|
@computed_field # type: ignore[misc]
|
||||||
|
@property
|
||||||
|
def pool_stale_percent(self) -> float: # noqa - Skip PyCharm inspection
|
||||||
|
"""Calculate and return the percentage of stale shares."""
|
||||||
|
return self._calculate_percentage(
|
||||||
|
self.get_failures, self.accepted + self.rejected
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _calculate_percentage(value: int, total: int) -> float:
|
||||||
|
"""Calculate the percentage."""
|
||||||
|
if value is None or total is None:
|
||||||
|
return 0
|
||||||
|
if total == 0:
|
||||||
|
return 0
|
||||||
|
return (value / total) * 100
|
||||||
4
pyasic/device/__init__.py
Normal file
4
pyasic/device/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
from .algorithm import MinerAlgo
|
||||||
|
from .firmware import MinerFirmware
|
||||||
|
from .makes import MinerMake
|
||||||
|
from .models import MinerModel
|
||||||
26
pyasic/device/algorithm/__init__.py
Normal file
26
pyasic/device/algorithm/__init__.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
from .base import MinerAlgoType
|
||||||
|
from .blake256 import Blake256Algo
|
||||||
|
from .eaglesong import EaglesongAlgo
|
||||||
|
from .equihash import EquihashAlgo
|
||||||
|
from .ethash import EtHashAlgo
|
||||||
|
from .handshake import HandshakeAlgo
|
||||||
|
from .hashrate import *
|
||||||
|
from .hashrate.unit import *
|
||||||
|
from .kadena import KadenaAlgo
|
||||||
|
from .kheavyhash import KHeavyHashAlgo
|
||||||
|
from .scrypt import ScryptAlgo
|
||||||
|
from .sha256 import SHA256Algo
|
||||||
|
from .x11 import X11Algo
|
||||||
|
|
||||||
|
|
||||||
|
class MinerAlgo:
|
||||||
|
SHA256 = SHA256Algo
|
||||||
|
SCRYPT = ScryptAlgo
|
||||||
|
KHEAVYHASH = KHeavyHashAlgo
|
||||||
|
KADENA = KadenaAlgo
|
||||||
|
HANDSHAKE = HandshakeAlgo
|
||||||
|
X11 = X11Algo
|
||||||
|
BLAKE256 = Blake256Algo
|
||||||
|
EAGLESONG = EaglesongAlgo
|
||||||
|
ETHASH = EtHashAlgo
|
||||||
|
EQUIHASH = EquihashAlgo
|
||||||
16
pyasic/device/algorithm/base.py
Normal file
16
pyasic/device/algorithm/base.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .hashrate.base import AlgoHashRateType
|
||||||
|
from .hashrate.unit.base import AlgoHashRateUnitType
|
||||||
|
|
||||||
|
|
||||||
|
class MinerAlgoMeta(type):
|
||||||
|
name: str
|
||||||
|
|
||||||
|
def __str__(cls):
|
||||||
|
return cls.name
|
||||||
|
|
||||||
|
|
||||||
|
class MinerAlgoType(metaclass=MinerAlgoMeta):
|
||||||
|
hashrate: type[AlgoHashRateType]
|
||||||
|
unit: type[AlgoHashRateUnitType]
|
||||||
13
pyasic/device/algorithm/blake256.py
Normal file
13
pyasic/device/algorithm/blake256.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import MinerAlgoType
|
||||||
|
from .hashrate import Blake256HashRate
|
||||||
|
from .hashrate.unit import Blake256Unit
|
||||||
|
|
||||||
|
|
||||||
|
# make this json serializable
|
||||||
|
class Blake256Algo(MinerAlgoType):
|
||||||
|
hashrate: type[Blake256HashRate] = Blake256HashRate
|
||||||
|
unit: type[Blake256Unit] = Blake256Unit
|
||||||
|
|
||||||
|
name = "Blake256"
|
||||||
13
pyasic/device/algorithm/eaglesong.py
Normal file
13
pyasic/device/algorithm/eaglesong.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import MinerAlgoType
|
||||||
|
from .hashrate import EaglesongHashRate
|
||||||
|
from .hashrate.unit import EaglesongUnit
|
||||||
|
|
||||||
|
|
||||||
|
# make this json serializable
|
||||||
|
class EaglesongAlgo(MinerAlgoType):
|
||||||
|
hashrate: type[EaglesongHashRate] = EaglesongHashRate
|
||||||
|
unit: type[EaglesongUnit] = EaglesongUnit
|
||||||
|
|
||||||
|
name = "Eaglesong"
|
||||||
13
pyasic/device/algorithm/equihash.py
Normal file
13
pyasic/device/algorithm/equihash.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import MinerAlgoType
|
||||||
|
from .hashrate import EquihashHashRate
|
||||||
|
from .hashrate.unit import EquihashUnit
|
||||||
|
|
||||||
|
|
||||||
|
# make this json serializable
|
||||||
|
class EquihashAlgo(MinerAlgoType):
|
||||||
|
hashrate: type[EquihashHashRate] = EquihashHashRate
|
||||||
|
unit: type[EquihashUnit] = EquihashUnit
|
||||||
|
|
||||||
|
name = "Equihash"
|
||||||
12
pyasic/device/algorithm/ethash.py
Normal file
12
pyasic/device/algorithm/ethash.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import MinerAlgoType
|
||||||
|
from .hashrate import EtHashHashRate
|
||||||
|
from .hashrate.unit import EtHashUnit
|
||||||
|
|
||||||
|
|
||||||
|
class EtHashAlgo(MinerAlgoType):
|
||||||
|
hashrate: type[EtHashHashRate] = EtHashHashRate
|
||||||
|
unit: type[EtHashUnit] = EtHashUnit
|
||||||
|
|
||||||
|
name = "EtHash"
|
||||||
13
pyasic/device/algorithm/handshake.py
Normal file
13
pyasic/device/algorithm/handshake.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import MinerAlgoType
|
||||||
|
from .hashrate import HandshakeHashRate
|
||||||
|
from .hashrate.unit import HandshakeUnit
|
||||||
|
|
||||||
|
|
||||||
|
# make this json serializable
|
||||||
|
class HandshakeAlgo(MinerAlgoType):
|
||||||
|
hashrate: type[HandshakeHashRate] = HandshakeHashRate
|
||||||
|
unit: type[HandshakeUnit] = HandshakeUnit
|
||||||
|
|
||||||
|
name = "Handshake"
|
||||||
24
pyasic/device/algorithm/hashrate/__init__.py
Normal file
24
pyasic/device/algorithm/hashrate/__init__.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
from .base import AlgoHashRateType
|
||||||
|
from .blake256 import Blake256HashRate
|
||||||
|
from .eaglesong import EaglesongHashRate
|
||||||
|
from .equihash import EquihashHashRate
|
||||||
|
from .ethash import EtHashHashRate
|
||||||
|
from .handshake import HandshakeHashRate
|
||||||
|
from .kadena import KadenaHashRate
|
||||||
|
from .kheavyhash import KHeavyHashHashRate
|
||||||
|
from .scrypt import ScryptHashRate
|
||||||
|
from .sha256 import SHA256HashRate
|
||||||
|
from .x11 import X11HashRate
|
||||||
|
|
||||||
|
|
||||||
|
class AlgoHashRate:
|
||||||
|
SHA256 = SHA256HashRate
|
||||||
|
SCRYPT = ScryptHashRate
|
||||||
|
KHEAVYHASH = KHeavyHashHashRate
|
||||||
|
KADENA = KadenaHashRate
|
||||||
|
HANDSHAKE = HandshakeHashRate
|
||||||
|
X11 = X11HashRate
|
||||||
|
BLAKE256 = Blake256HashRate
|
||||||
|
EAGLESONG = EaglesongHashRate
|
||||||
|
ETHASH = EtHashHashRate
|
||||||
|
EQUIHASH = EquihashHashRate
|
||||||
62
pyasic/device/algorithm/hashrate/base.py
Normal file
62
pyasic/device/algorithm/hashrate/base.py
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
from abc import ABC, abstractmethod
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
from .unit.base import AlgoHashRateUnitType
|
||||||
|
|
||||||
|
|
||||||
|
class AlgoHashRateType(BaseModel, ABC):
|
||||||
|
unit: AlgoHashRateUnitType
|
||||||
|
rate: float
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def into(self, other: "AlgoHashRateUnitType"):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __float__(self):
|
||||||
|
return float(self.rate)
|
||||||
|
|
||||||
|
def __int__(self):
|
||||||
|
return int(self.rate)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"{self.rate} {str(self.unit)}"
|
||||||
|
|
||||||
|
def __round__(self, n: int = None):
|
||||||
|
return round(self.rate, n)
|
||||||
|
|
||||||
|
def __add__(self, other: Self | int | float) -> Self:
|
||||||
|
if isinstance(other, self.__class__):
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate + other.into(self.unit).rate, unit=self.unit
|
||||||
|
)
|
||||||
|
return self.__class__(rate=self.rate + other, unit=self.unit)
|
||||||
|
|
||||||
|
def __sub__(self, other: Self | int | float) -> Self:
|
||||||
|
if isinstance(other, self.__class__):
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate - other.into(self.unit).rate, unit=self.unit
|
||||||
|
)
|
||||||
|
return self.__class__(rate=self.rate - other, unit=self.unit)
|
||||||
|
|
||||||
|
def __truediv__(self, other: Self | int | float) -> Self:
|
||||||
|
if isinstance(other, self.__class__):
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate / other.into(self.unit).rate, unit=self.unit
|
||||||
|
)
|
||||||
|
return self.__class__(rate=self.rate / other, unit=self.unit)
|
||||||
|
|
||||||
|
def __floordiv__(self, other: Self | int | float) -> Self:
|
||||||
|
if isinstance(other, self.__class__):
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate // other.into(self.unit).rate, unit=self.unit
|
||||||
|
)
|
||||||
|
return self.__class__(rate=self.rate // other, unit=self.unit)
|
||||||
|
|
||||||
|
def __mul__(self, other: Self | int | float) -> Self:
|
||||||
|
if isinstance(other, self.__class__):
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate * other.into(self.unit).rate, unit=self.unit
|
||||||
|
)
|
||||||
|
return self.__class__(rate=self.rate * other, unit=self.unit)
|
||||||
18
pyasic/device/algorithm/hashrate/blake256.py
Normal file
18
pyasic/device/algorithm/hashrate/blake256.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
from pyasic.device.algorithm.hashrate.base import AlgoHashRateType
|
||||||
|
from pyasic.device.algorithm.hashrate.unit.blake256 import Blake256Unit
|
||||||
|
|
||||||
|
from .unit import HashUnit
|
||||||
|
|
||||||
|
|
||||||
|
class Blake256HashRate(AlgoHashRateType):
|
||||||
|
rate: float
|
||||||
|
unit: Blake256Unit = HashUnit.BLAKE256.default
|
||||||
|
|
||||||
|
def into(self, other: Blake256Unit) -> Self:
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate / (other.value / self.unit.value), unit=other
|
||||||
|
)
|
||||||
18
pyasic/device/algorithm/hashrate/eaglesong.py
Normal file
18
pyasic/device/algorithm/hashrate/eaglesong.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
from pyasic.device.algorithm.hashrate.base import AlgoHashRateType
|
||||||
|
from pyasic.device.algorithm.hashrate.unit.eaglesong import EaglesongUnit
|
||||||
|
|
||||||
|
from .unit import HashUnit
|
||||||
|
|
||||||
|
|
||||||
|
class EaglesongHashRate(AlgoHashRateType):
|
||||||
|
rate: float
|
||||||
|
unit: EaglesongUnit = HashUnit.EAGLESONG.default
|
||||||
|
|
||||||
|
def into(self, other: EaglesongUnit) -> Self:
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate / (other.value / self.unit.value), unit=other
|
||||||
|
)
|
||||||
18
pyasic/device/algorithm/hashrate/equihash.py
Normal file
18
pyasic/device/algorithm/hashrate/equihash.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
from pyasic.device.algorithm.hashrate.base import AlgoHashRateType
|
||||||
|
from pyasic.device.algorithm.hashrate.unit.equihash import EquihashUnit
|
||||||
|
|
||||||
|
from .unit import HashUnit
|
||||||
|
|
||||||
|
|
||||||
|
class EquihashHashRate(AlgoHashRateType):
|
||||||
|
rate: float
|
||||||
|
unit: EquihashUnit = HashUnit.ETHASH.default
|
||||||
|
|
||||||
|
def into(self, other: EquihashUnit) -> Self:
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate / (other.value / self.unit.value), unit=other
|
||||||
|
)
|
||||||
18
pyasic/device/algorithm/hashrate/ethash.py
Normal file
18
pyasic/device/algorithm/hashrate/ethash.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
from pyasic.device.algorithm.hashrate.base import AlgoHashRateType
|
||||||
|
from pyasic.device.algorithm.hashrate.unit.ethash import EtHashUnit
|
||||||
|
|
||||||
|
from .unit import HashUnit
|
||||||
|
|
||||||
|
|
||||||
|
class EtHashHashRate(AlgoHashRateType):
|
||||||
|
rate: float
|
||||||
|
unit: EtHashUnit = HashUnit.ETHASH.default
|
||||||
|
|
||||||
|
def into(self, other: EtHashUnit) -> Self:
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate / (other.value / self.unit.value), unit=other
|
||||||
|
)
|
||||||
18
pyasic/device/algorithm/hashrate/handshake.py
Normal file
18
pyasic/device/algorithm/hashrate/handshake.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
from pyasic.device.algorithm.hashrate.base import AlgoHashRateType
|
||||||
|
from pyasic.device.algorithm.hashrate.unit.handshake import HandshakeUnit
|
||||||
|
|
||||||
|
from .unit import HashUnit
|
||||||
|
|
||||||
|
|
||||||
|
class HandshakeHashRate(AlgoHashRateType):
|
||||||
|
rate: float
|
||||||
|
unit: HandshakeUnit = HashUnit.HANDSHAKE.default
|
||||||
|
|
||||||
|
def into(self, other: HandshakeUnit) -> Self:
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate / (other.value / self.unit.value), unit=other
|
||||||
|
)
|
||||||
18
pyasic/device/algorithm/hashrate/kadena.py
Normal file
18
pyasic/device/algorithm/hashrate/kadena.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
from pyasic.device.algorithm.hashrate.base import AlgoHashRateType
|
||||||
|
from pyasic.device.algorithm.hashrate.unit.kadena import KadenaUnit
|
||||||
|
|
||||||
|
from .unit import HashUnit
|
||||||
|
|
||||||
|
|
||||||
|
class KadenaHashRate(AlgoHashRateType):
|
||||||
|
rate: float
|
||||||
|
unit: KadenaUnit = HashUnit.KADENA.default
|
||||||
|
|
||||||
|
def into(self, other: KadenaUnit) -> Self:
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate / (other.value / self.unit.value), unit=other
|
||||||
|
)
|
||||||
18
pyasic/device/algorithm/hashrate/kheavyhash.py
Normal file
18
pyasic/device/algorithm/hashrate/kheavyhash.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
from pyasic.device.algorithm.hashrate.base import AlgoHashRateType
|
||||||
|
from pyasic.device.algorithm.hashrate.unit.kheavyhash import KHeavyHashUnit
|
||||||
|
|
||||||
|
from .unit import HashUnit
|
||||||
|
|
||||||
|
|
||||||
|
class KHeavyHashHashRate(AlgoHashRateType):
|
||||||
|
rate: float
|
||||||
|
unit: KHeavyHashUnit = HashUnit.KHEAVYHASH.default
|
||||||
|
|
||||||
|
def into(self, other: KHeavyHashUnit) -> Self:
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate / (other.value / self.unit.value), unit=other
|
||||||
|
)
|
||||||
18
pyasic/device/algorithm/hashrate/scrypt.py
Normal file
18
pyasic/device/algorithm/hashrate/scrypt.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
from pyasic.device.algorithm.hashrate.base import AlgoHashRateType
|
||||||
|
from pyasic.device.algorithm.hashrate.unit.scrypt import ScryptUnit
|
||||||
|
|
||||||
|
from .unit import HashUnit
|
||||||
|
|
||||||
|
|
||||||
|
class ScryptHashRate(AlgoHashRateType):
|
||||||
|
rate: float
|
||||||
|
unit: ScryptUnit = HashUnit.SCRYPT.default
|
||||||
|
|
||||||
|
def into(self, other: ScryptUnit) -> Self:
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate / (other.value / self.unit.value), unit=other
|
||||||
|
)
|
||||||
18
pyasic/device/algorithm/hashrate/sha256.py
Normal file
18
pyasic/device/algorithm/hashrate/sha256.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
from pyasic.device.algorithm.hashrate.base import AlgoHashRateType
|
||||||
|
from pyasic.device.algorithm.hashrate.unit.sha256 import SHA256Unit
|
||||||
|
|
||||||
|
from .unit import HashUnit
|
||||||
|
|
||||||
|
|
||||||
|
class SHA256HashRate(AlgoHashRateType):
|
||||||
|
rate: float
|
||||||
|
unit: SHA256Unit = HashUnit.SHA256.default
|
||||||
|
|
||||||
|
def into(self, other: SHA256Unit) -> Self:
|
||||||
|
return self.__class__(
|
||||||
|
rate=self.rate / (other.value / self.unit.value), unit=other
|
||||||
|
)
|
||||||
23
pyasic/device/algorithm/hashrate/unit/__init__.py
Normal file
23
pyasic/device/algorithm/hashrate/unit/__init__.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
from .blake256 import Blake256Unit
|
||||||
|
from .eaglesong import EaglesongUnit
|
||||||
|
from .equihash import EquihashUnit
|
||||||
|
from .ethash import EtHashUnit
|
||||||
|
from .handshake import HandshakeUnit
|
||||||
|
from .kadena import KadenaUnit
|
||||||
|
from .kheavyhash import KHeavyHashUnit
|
||||||
|
from .scrypt import ScryptUnit
|
||||||
|
from .sha256 import SHA256Unit
|
||||||
|
from .x11 import X11Unit
|
||||||
|
|
||||||
|
|
||||||
|
class HashUnit:
|
||||||
|
SHA256 = SHA256Unit
|
||||||
|
SCRYPT = ScryptUnit
|
||||||
|
KHEAVYHASH = KHeavyHashUnit
|
||||||
|
KADENA = KadenaUnit
|
||||||
|
HANDSHAKE = HandshakeUnit
|
||||||
|
X11 = X11Unit
|
||||||
|
BLAKE256 = Blake256Unit
|
||||||
|
EAGLESONG = EaglesongUnit
|
||||||
|
ETHASH = EtHashUnit
|
||||||
|
EQUIHASH = EquihashUnit
|
||||||
55
pyasic/device/algorithm/hashrate/unit/base.py
Normal file
55
pyasic/device/algorithm/hashrate/unit/base.py
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
from enum import IntEnum
|
||||||
|
|
||||||
|
|
||||||
|
class AlgoHashRateUnitType(IntEnum):
|
||||||
|
H: int
|
||||||
|
KH: int
|
||||||
|
MH: int
|
||||||
|
GH: int
|
||||||
|
TH: int
|
||||||
|
PH: int
|
||||||
|
EH: int
|
||||||
|
ZH: int
|
||||||
|
|
||||||
|
default: int
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if self.value == self.H:
|
||||||
|
return "H/s"
|
||||||
|
if self.value == self.KH:
|
||||||
|
return "KH/s"
|
||||||
|
if self.value == self.MH:
|
||||||
|
return "MH/s"
|
||||||
|
if self.value == self.GH:
|
||||||
|
return "GH/s"
|
||||||
|
if self.value == self.TH:
|
||||||
|
return "TH/s"
|
||||||
|
if self.value == self.PH:
|
||||||
|
return "PH/s"
|
||||||
|
if self.value == self.EH:
|
||||||
|
return "EH/s"
|
||||||
|
if self.value == self.ZH:
|
||||||
|
return "ZH/s"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_str(cls, value: str):
|
||||||
|
if value == "H":
|
||||||
|
return cls.H
|
||||||
|
elif value == "KH":
|
||||||
|
return cls.KH
|
||||||
|
elif value == "MH":
|
||||||
|
return cls.MH
|
||||||
|
elif value == "GH":
|
||||||
|
return cls.GH
|
||||||
|
elif value == "TH":
|
||||||
|
return cls.TH
|
||||||
|
elif value == "PH":
|
||||||
|
return cls.PH
|
||||||
|
elif value == "EH":
|
||||||
|
return cls.EH
|
||||||
|
elif value == "ZH":
|
||||||
|
return cls.ZH
|
||||||
|
return cls.default
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return str(self)
|
||||||
16
pyasic/device/algorithm/hashrate/unit/blake256.py
Normal file
16
pyasic/device/algorithm/hashrate/unit/blake256.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import AlgoHashRateUnitType
|
||||||
|
|
||||||
|
|
||||||
|
class Blake256Unit(AlgoHashRateUnitType):
|
||||||
|
H = 1
|
||||||
|
KH = int(H) * 1000
|
||||||
|
MH = int(KH) * 1000
|
||||||
|
GH = int(MH) * 1000
|
||||||
|
TH = int(GH) * 1000
|
||||||
|
PH = int(TH) * 1000
|
||||||
|
EH = int(PH) * 1000
|
||||||
|
ZH = int(EH) * 1000
|
||||||
|
|
||||||
|
default = TH
|
||||||
16
pyasic/device/algorithm/hashrate/unit/eaglesong.py
Normal file
16
pyasic/device/algorithm/hashrate/unit/eaglesong.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import AlgoHashRateUnitType
|
||||||
|
|
||||||
|
|
||||||
|
class EaglesongUnit(AlgoHashRateUnitType):
|
||||||
|
H = 1
|
||||||
|
KH = int(H) * 1000
|
||||||
|
MH = int(KH) * 1000
|
||||||
|
GH = int(MH) * 1000
|
||||||
|
TH = int(GH) * 1000
|
||||||
|
PH = int(TH) * 1000
|
||||||
|
EH = int(PH) * 1000
|
||||||
|
ZH = int(EH) * 1000
|
||||||
|
|
||||||
|
default = TH
|
||||||
34
pyasic/device/algorithm/hashrate/unit/equihash.py
Normal file
34
pyasic/device/algorithm/hashrate/unit/equihash.py
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import AlgoHashRateUnitType
|
||||||
|
|
||||||
|
|
||||||
|
class EquihashUnit(AlgoHashRateUnitType):
|
||||||
|
H = 1
|
||||||
|
KH = int(H) * 1000
|
||||||
|
MH = int(KH) * 1000
|
||||||
|
GH = int(MH) * 1000
|
||||||
|
TH = int(GH) * 1000
|
||||||
|
PH = int(TH) * 1000
|
||||||
|
EH = int(PH) * 1000
|
||||||
|
ZH = int(EH) * 1000
|
||||||
|
|
||||||
|
default = KH
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if self.value == self.H:
|
||||||
|
return "Sol/s"
|
||||||
|
if self.value == self.KH:
|
||||||
|
return "KSol/s"
|
||||||
|
if self.value == self.MH:
|
||||||
|
return "MSol/s"
|
||||||
|
if self.value == self.GH:
|
||||||
|
return "GSol/s"
|
||||||
|
if self.value == self.TH:
|
||||||
|
return "TSol/s"
|
||||||
|
if self.value == self.PH:
|
||||||
|
return "PSol/s"
|
||||||
|
if self.value == self.EH:
|
||||||
|
return "ESol/s"
|
||||||
|
if self.value == self.ZH:
|
||||||
|
return "ZSol/s"
|
||||||
16
pyasic/device/algorithm/hashrate/unit/ethash.py
Normal file
16
pyasic/device/algorithm/hashrate/unit/ethash.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import AlgoHashRateUnitType
|
||||||
|
|
||||||
|
|
||||||
|
class EtHashUnit(AlgoHashRateUnitType):
|
||||||
|
H = 1
|
||||||
|
KH = int(H) * 1000
|
||||||
|
MH = int(KH) * 1000
|
||||||
|
GH = int(MH) * 1000
|
||||||
|
TH = int(GH) * 1000
|
||||||
|
PH = int(TH) * 1000
|
||||||
|
EH = int(PH) * 1000
|
||||||
|
ZH = int(EH) * 1000
|
||||||
|
|
||||||
|
default = MH
|
||||||
16
pyasic/device/algorithm/hashrate/unit/handshake.py
Normal file
16
pyasic/device/algorithm/hashrate/unit/handshake.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import AlgoHashRateUnitType
|
||||||
|
|
||||||
|
|
||||||
|
class HandshakeUnit(AlgoHashRateUnitType):
|
||||||
|
H = 1
|
||||||
|
KH = int(H) * 1000
|
||||||
|
MH = int(KH) * 1000
|
||||||
|
GH = int(MH) * 1000
|
||||||
|
TH = int(GH) * 1000
|
||||||
|
PH = int(TH) * 1000
|
||||||
|
EH = int(PH) * 1000
|
||||||
|
ZH = int(EH) * 1000
|
||||||
|
|
||||||
|
default = TH
|
||||||
16
pyasic/device/algorithm/hashrate/unit/kadena.py
Normal file
16
pyasic/device/algorithm/hashrate/unit/kadena.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import AlgoHashRateUnitType
|
||||||
|
|
||||||
|
|
||||||
|
class KadenaUnit(AlgoHashRateUnitType):
|
||||||
|
H = 1
|
||||||
|
KH = int(H) * 1000
|
||||||
|
MH = int(KH) * 1000
|
||||||
|
GH = int(MH) * 1000
|
||||||
|
TH = int(GH) * 1000
|
||||||
|
PH = int(TH) * 1000
|
||||||
|
EH = int(PH) * 1000
|
||||||
|
ZH = int(EH) * 1000
|
||||||
|
|
||||||
|
default = TH
|
||||||
16
pyasic/device/algorithm/hashrate/unit/kheavyhash.py
Normal file
16
pyasic/device/algorithm/hashrate/unit/kheavyhash.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from .base import AlgoHashRateUnitType
|
||||||
|
|
||||||
|
|
||||||
|
class KHeavyHashUnit(AlgoHashRateUnitType):
|
||||||
|
H = 1
|
||||||
|
KH = int(H) * 1000
|
||||||
|
MH = int(KH) * 1000
|
||||||
|
GH = int(MH) * 1000
|
||||||
|
TH = int(GH) * 1000
|
||||||
|
PH = int(TH) * 1000
|
||||||
|
EH = int(PH) * 1000
|
||||||
|
ZH = int(EH) * 1000
|
||||||
|
|
||||||
|
default = TH
|
||||||
16
pyasic/device/algorithm/hashrate/unit/scrypt.py
Normal file
16
pyasic/device/algorithm/hashrate/unit/scrypt.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from enum import IntEnum
|
||||||
|
|
||||||
|
|
||||||
|
class ScryptUnit(IntEnum):
|
||||||
|
H = 1
|
||||||
|
KH = int(H) * 1000
|
||||||
|
MH = int(KH) * 1000
|
||||||
|
GH = int(MH) * 1000
|
||||||
|
TH = int(GH) * 1000
|
||||||
|
PH = int(TH) * 1000
|
||||||
|
EH = int(PH) * 1000
|
||||||
|
ZH = int(EH) * 1000
|
||||||
|
|
||||||
|
default = GH
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user