Compare commits

...

190 Commits

Author SHA1 Message Date
UpstreamData
87016670d4 version: bump version number. 2023-11-28 10:50:56 -07:00
JP Compagnone
8701bbe4e2 Feature - Add initial ePIC UMC support (#71)
* prelim support of ePIC UMC

* slowly adding things

* add most api calls

* add some guards

* fix post commands

* remove print

* catch when API returns error

* missing guard

* remove semicolon

* recommended changes

* add docs and changes

* respect ignore_errors
2023-11-28 10:49:49 -07:00
UpstreamData
7d1f125b0b docs: update settings docs to list. 2023-11-27 11:07:43 -07:00
UpstreamData
e433902bd5 docs: update settings docs. 2023-11-27 10:57:13 -07:00
UpstreamData
a653772968 docs: update network docs. 2023-11-27 10:53:40 -07:00
UpstreamData
d8b938cd5b version: bump version number. 2023-11-27 10:39:10 -07:00
UpstreamData
47d76e325a docs: update docs to include new information. 2023-11-27 10:37:38 -07:00
UpstreamData
7ee7868094 feature: change so_linger_time to socket_linger_time. 2023-11-27 10:19:30 -07:00
UpstreamData
3f1183a4f9 feature: add so_linger option to settings. 2023-11-27 09:24:28 -07:00
Upstream Data
2b443497ea bug: improve handling of whatsminers in get_miner. 2023-11-25 12:48:45 -07:00
Upstream Data
c3972f9524 feature: add default ssl ctx to all httpx clients to speed up initialization. 2023-11-25 01:08:04 -07:00
Upstream Data
92bbb21c11 bug: handle OSError as ConnectionError, and handle Vnish Msg bug because of missing id key. 2023-11-25 00:05:03 -07:00
Upstream Data
1980ff2563 bug: do additional checks on refused connection when scanning. 2023-11-24 23:32:22 -07:00
Upstream Data
93d09a1483 bug: handle unhandled error in pings. 2023-11-24 23:28:16 -07:00
Upstream Data
690d0d99df feature: added new setting for api command timeouts. 2023-11-24 23:19:14 -07:00
Upstream Data
78f689eb2c feature: update scan method to use port 80 when possible, and add .scan() method. 2023-11-24 23:13:56 -07:00
Upstream Data
e68f188e8f bug: fix timeout references in MinerFactory and fix MinerNetwork instantiation. 2023-11-24 23:00:06 -07:00
Upstream Data
7eda611fe9 bug: fix scanning size being too large. 2023-11-24 22:50:43 -07:00
Upstream Data
1d12817942 feature: improve network parsing and implementation. 2023-11-24 22:38:43 -07:00
UpstreamData
b24efd4c69 bug: fix miner network not working with lists. 2023-11-24 13:27:09 -07:00
UpstreamData
5533135b05 docs: update supported miners. 2023-11-23 11:54:01 -07:00
UpstreamData
475054fbe0 feature: finish support for most whatsminer subtypes. 2023-11-23 11:52:44 -07:00
Daniel Sokil
06bad1bbe0 Add More Whatsminer Models, and Additional Config For Existing Models (#70) 2023-11-23 11:35:18 -07:00
UpstreamData
f3746ff756 version: bump version number. 2023-11-20 11:19:45 -07:00
UpstreamData
9f16d37c8b feature: hide GRPC and GQL if BOSer is not found. 2023-11-20 11:19:13 -07:00
UpstreamData
8a13c7940a docs: update pyproject.toml description. 2023-11-20 10:33:25 -07:00
UpstreamData
8bea76ff67 feature: add chip count for M30S+VG50. 2023-11-20 10:32:51 -07:00
Upstream Data
1504bd744c version: bump version number. 2023-11-18 22:45:38 -07:00
Upstream Data
6449f10615 feature: implement GPRC set commands properly. 2023-11-18 22:45:09 -07:00
UpstreamData
d79509bda7 version: bump version number. Pin httpx to 0.25.0 min. 2023-11-12 18:36:45 -07:00
UpstreamData
630b847466 version: bump version number. Pin httpx to 0.25.0 min. 2023-11-12 18:35:52 -07:00
Colin Crossman
ed11611919 Bump version number
Note: some issues with HTTPX may be resolved by using 1.0.0b, but I did not bump the requirement at this time to the beta.
2023-11-11 13:59:14 -07:00
Colin Crossman
e2431c938d Address unknown password issue on Whatsminers
When a whatsminer had an unknown password (not the default one), it would result in a timeout error. By moving the password check to before the data pull step, the timeout issue can be caught and addressed efficiently.
2023-11-11 13:52:04 -07:00
Colin Crossman
60f4b4a5ed Address a situation which causes many asyncio errors 2023-11-11 13:49:51 -07:00
UpstreamData
d41097af20 version: bump vbersion number. 2023-11-08 11:13:24 -07:00
UpstreamData
8a5d505731 bug: fix anyio stream error on some linux distros when getting miner. 2023-11-08 11:12:46 -07:00
UpstreamData
36e76c6f41 Add support for the grpc set_performance_mode command. 2023-11-07 08:54:06 -07:00
UpstreamData
717b9421dd Merge branch 'dev_grpc'
# Conflicts:
#	pyasic/web/bosminer.py
#	pyproject.toml
2023-10-30 16:36:06 -06:00
UpstreamData
d2f71e8c94 version: bump version number. 2023-10-30 16:34:05 -06:00
UpstreamData
697991f28f bug: fix some cases where a warning could still be passed when it was unexpected. 2023-10-30 16:33:01 -06:00
UpstreamData
b0e18ab766 feature: implement most of the GRPC functions for BOS, except for some configuration options which will require complex enums. 2023-10-27 16:35:09 -06:00
UpstreamData
e39a6921d0 refactor: improve settings handling to not use a dataclass, and not use singleton. 2023-10-26 10:28:59 -06:00
UpstreamData
aac1be0565 feature: refactor BOS web class into multiple classes. 2023-10-26 10:28:57 -06:00
UpstreamData
683fcb2138 version: bump version number. 2023-10-26 10:28:56 -06:00
UpstreamData
9fbbef9b18 bug: fix an issue with bosminer not responding correctly on older models with fans. 2023-10-26 10:28:56 -06:00
UpstreamData
6e0b9a0a7b version: bump version number. 2023-10-26 10:28:56 -06:00
UpstreamData
7f472f6f4f bug: fix possible missing value for bitmain work mode when checking is_mining. 2023-10-26 10:28:55 -06:00
UpstreamData
b7d7b33ab9 bug: round hashrate data in MinerData, and remove some unused imports. 2023-10-26 10:28:55 -06:00
UpstreamData
da11c0bb1f version: bump version number. 2023-10-26 10:28:55 -06:00
UpstreamData
eae433d2bd bug: update get_miner to work with latest whatsminer version. 2023-10-26 10:28:54 -06:00
UpstreamData
c16bc37aff refactor: improve settings handling to not use a dataclass, and not use singleton. 2023-10-26 10:28:53 -06:00
UpstreamData
255b06ac9e version: bump version number. 2023-10-23 13:01:44 -06:00
UpstreamData
29ec619126 bug: fix an issue with bosminer not responding correctly on older models with fans. 2023-10-23 12:59:52 -06:00
UpstreamData
247def04ff version: bump version number. 2023-10-12 13:19:38 -06:00
UpstreamData
4600e7d953 bug: fix possible missing value for bitmain work mode when checking is_mining. 2023-10-12 13:19:11 -06:00
UpstreamData
850c266555 bug: round hashrate data in MinerData, and remove some unused imports. 2023-10-10 13:59:28 -06:00
UpstreamData
ad374fe2fb version: bump version number. 2023-10-05 10:18:10 -06:00
UpstreamData
5ca39b6fe7 bug: update get_miner to work with latest whatsminer version. 2023-10-05 10:17:45 -06:00
UpstreamData
b50dd26e6f feature: refactor BOS web class into multiple classes. 2023-10-03 15:07:39 -06:00
UpstreamData
53eaccaa9b docs: update documentation. 2023-10-03 15:07:39 -06:00
UpstreamData
91f207316a version: bump version number. 2023-10-03 15:07:39 -06:00
UpstreamData
1e37418909 bug: fix some issues with early version of whatsminers, and handle some possible errors with BOS. 2023-10-03 15:07:38 -06:00
UpstreamData
4c09ba5529 version: bump version number. 2023-10-03 15:07:38 -06:00
UpstreamData
7bab4747ad refactor: improve settings handling to not use a dataclass, and not use singleton. 2023-10-03 15:07:37 -06:00
UpstreamData
fd8cc7378c version: bump version number. 2023-10-03 15:07:33 -06:00
UpstreamData
8aeef4d5e7 feature: add support for M20P, and add chips for M20SV30. 2023-10-03 15:07:33 -06:00
UpstreamData
4bafde9da7 docs: update documentation. 2023-10-03 14:59:25 -06:00
UpstreamData
5a3107aecf version: bump version number. 2023-10-03 11:12:11 -06:00
UpstreamData
7e758720f0 bug: fix some issues with early version of whatsminers, and handle some possible errors with BOS. 2023-10-03 11:11:32 -06:00
UpstreamData
39e3e249f8 version: bump version number. 2023-10-02 13:14:21 -06:00
UpstreamData
118c5b056e refactor: improve settings handling to not use a dataclass, and not use singleton. 2023-10-02 13:13:31 -06:00
UpstreamData
2c3b5599fe version: bump version number. 2023-10-02 09:20:24 -06:00
UpstreamData
e421eaa324 feature: add support for M20P, and add chips for M20SV30. 2023-10-02 09:20:01 -06:00
UpstreamData
75d6bc6808 version: bump version number. 2023-09-28 15:49:23 -06:00
UpstreamData
98c547e416 bug: fAdd new commands added in whatsminer API 2.0.5. 2023-09-28 15:49:23 -06:00
UpstreamData
45250e36e4 bug: fix whatsminer identification to work with backwards incompatible changes in API 2.0.5. 2023-09-28 15:49:23 -06:00
UpstreamData
fa7544d052 Update README.md 2023-09-28 15:49:22 -06:00
UpstreamData
53f3fc5ee9 version: bump version number. 2023-09-28 15:47:49 -06:00
UpstreamData
1b36de4131 bug: fAdd new commands added in whatsminer API 2.0.5. 2023-09-28 15:47:20 -06:00
UpstreamData
6f0c6f6284 bug: fix whatsminer identification to work with backwards incompatible changes in API 2.0.5. 2023-09-28 15:42:12 -06:00
UpstreamData
b7dda5bf87 Update README.md 2023-09-26 11:50:56 -06:00
UpstreamData
14f33a40c3 feature: add grpc BOS class and add grpc requests to requirements. 2023-09-22 09:44:25 -06:00
UpstreamData
5c904aced0 feature: refactor BOS web class into multiple classes. 2023-09-22 09:32:59 -06:00
UpstreamData
53a3bbf531 version: bump version number. 2023-09-19 13:59:56 -06:00
UpstreamData
50586f1ce7 feature: add S19+. 2023-09-19 13:59:03 -06:00
UpstreamData
9f6235a0fc feature: add S19i. 2023-09-19 13:56:40 -06:00
UpstreamData
4d21f150ce version: bump version number. 2023-09-18 09:35:38 -06:00
UpstreamData
7c0dfc49dd bug: fix wrong fault light setting when setting fault light to off. 2023-09-18 09:35:19 -06:00
UpstreamData
269b13f6c1 version: bump version number. 2023-09-15 08:57:56 -06:00
Elias Kunnas
a9bb7d2e5a Fix btminer pre_power_on (#62) 2023-09-15 08:56:29 -06:00
Upstream Data
11295f27a7 version: bump version number. 2023-09-12 19:21:04 -06:00
Upstream Data
55aa3dd85b bug: handle edge cases where a missed get_config on bosminer can cause an empty config to be applied to a miner. 2023-09-12 19:20:48 -06:00
UpstreamData
20272d4360 version: bump version number. 2023-09-11 13:45:52 -06:00
UpstreamData
623dc92ef2 feature: Add MinerData.as_dict(). 2023-09-11 13:45:23 -06:00
Upstream Data
2d59394b1e version: bump version number. 2023-09-07 19:07:11 -06:00
Upstream Data
26c2095ff1 bug: fix uncaught error in get_hashboards with BMMiner if a key doesnt exist. 2023-09-07 19:06:51 -06:00
Upstream Data
ec7d241caa version: bump version number. 2023-09-05 17:22:23 -06:00
Upstream Data
d0432ed1aa bug: handle for some weird edge cases with boards plugged into the wrong slots on X19. 2023-09-05 17:22:02 -06:00
Upstream Data
8c5503d002 version: bump version number. 2023-08-30 17:47:20 -06:00
Upstream Data
6d6f950c95 bug: add modified changed from [Issue 57](https://github.com/UpstreamData/pyasic/issues/57#issuecomment-1699984187) 2023-08-30 17:46:23 -06:00
UpstreamData
30745e54ba feature: add chip count for M30S+VE50 2023-08-30 11:18:25 -06:00
UpstreamData
c3fd94e79e version: bump version number. 2023-08-28 08:53:59 -06:00
UpstreamData
2924a8d67b feature: add more whatsminer error codes. 2023-08-28 08:53:27 -06:00
UpstreamData
9f4c4bb9cf feature: add exclude to get_data, and change data_to_get to include. 2023-08-28 08:32:29 -06:00
UpstreamData
3d6eebf06e bug: fix a bug with hostname gathering on some Avalons. 2023-08-28 08:31:54 -06:00
Upstream Data
b3d9b6ff7e version: bump version number. 2023-08-26 11:21:21 -06:00
Upstream Data
60facacc48 bug: fix a bug with bosminer commands. 2023-08-26 11:21:10 -06:00
Upstream Data
b8a6063838 version: bumnp version number. 2023-08-26 10:57:40 -06:00
Upstream Data
bcba2be524 bug: remove bad await calls to httpx response.json(). 2023-08-26 10:56:53 -06:00
UpstreamData
f7187d2017 bug: add chip count for M29V10. 2023-08-25 08:58:34 -06:00
Upstream Data
d91b7c4406 version: bump version number. 2023-08-07 17:02:50 -06:00
Upstream Data
248a7e6d69 bug: fix some WM models reporting https first and being identified as BOS+. 2023-08-07 17:02:26 -06:00
Upstream Data
4f2c3e772a version: bump version number. 2023-08-06 17:25:21 -06:00
Upstream Data
95f7146eef feature: add VNish pause/resume commands. 2023-08-06 17:24:36 -06:00
UpstreamData
9d5d19cc6b version: bump version number. 2023-07-27 20:45:42 -06:00
UpstreamData
cc38129571 bug: add back pwd for ssh connections. 2023-07-27 20:45:08 -06:00
UpstreamData
3dfd9f237d version: bump version number. 2023-07-27 20:18:58 -06:00
UpstreamData
f3fe478dbb feature: add support for S19J Pro No PIC. 2023-07-27 20:18:36 -06:00
UpstreamData
e10f32ae3d feature: speed up getting older antminer types with concurrent web and api requests. 2023-07-24 21:05:07 -06:00
UpstreamData
4e0924aa0e feature: add support for AML vnish miners. 2023-07-24 20:45:30 -06:00
UpstreamData
d0d3fd3117 bug: fix failed verification of SSL cert on whatsminer. 2023-07-24 20:19:00 -06:00
UpstreamData
4de950d8f4 feature: revert miner_factory to use httpx, as it now seems to be the same speed, and aiohttp doesnt support digest auth. 2023-07-24 13:09:30 -06:00
UpstreamData
03f2a1f9ba feature: optimize multicommand on new X19 models. 2023-07-24 11:34:16 -06:00
UpstreamData
2653db90e3 feature: optimize the way multicommand is handled on BTMiner. 2023-07-24 09:44:23 -06:00
UpstreamData
ddc8c53eb9 feature: add chip count for M50 VH60. 2023-07-13 10:59:27 -06:00
UpstreamData
eb5d1a24ea version: bump version number. 2023-07-12 08:56:59 -06:00
UpstreamData
6c0e80265b bug: revert X19 miner mode to string. 2023-07-12 08:56:23 -06:00
UpstreamData
ad3a4ae414 docs: update some bad code, and add references to new miner types and API types. 2023-07-11 11:18:28 -06:00
UpstreamData
3484d43510 version: bump version number. 2023-07-07 14:09:22 -06:00
UpstreamData
dd7e352391 bug: fix some addition issues with MinerData sums. 2023-07-07 14:09:08 -06:00
UpstreamData
a32b61fe5d version: bump version number. 2023-07-07 12:37:34 -06:00
UpstreamData
597a178009 feature: Update MinerData to use None. 2023-07-07 12:37:20 -06:00
Michael Schmid
409b2527f0 use None instead of -1 for temps and wattages (#55)
* use `None` instead of `-1` for temps and wattages
this way it's easier for other tools like HomeAssistant to understand if the temperature is really negative or not available

* also handle cases where we look for `-1`
2023-07-07 12:06:24 -06:00
UpstreamData
58234fcf7f version: bump version number. 2023-07-07 12:03:28 -06:00
UpstreamData
1bf863cca8 bug: set miner_mode to int instead of str to fix some issues with some X19 models. 2023-07-07 12:03:00 -06:00
UpstreamData
6482d04185 version: bump version number. 2023-07-07 11:56:41 -06:00
UpstreamData
3b58b11501 bug: remove 0 frequency level when setting sleep mode on X19, as it seems to bug some types. 2023-07-07 11:56:06 -06:00
UpstreamData
7485b8ef77 version: bump version number. 2023-07-04 10:04:20 -06:00
UpstreamData
d2bea227db bug: fix an issue with a possible SSH command in BOS+. 2023-07-04 10:01:24 -06:00
UpstreamData
1b7afaaf7e version: bump version number. 2023-06-30 08:49:31 -06:00
UpstreamData
96898d639c bug: fix some handling errors with graphql. 2023-06-30 08:49:08 -06:00
UpstreamData
eb439f4dcf version: bump version number. 2023-06-30 08:44:01 -06:00
UpstreamData
69f4349393 feature: create pwd and username property in miner object that sets web and api passwords and usernames. 2023-06-30 08:43:30 -06:00
UpstreamData
e371bb577c version: bump version number. 2023-06-29 18:10:35 -06:00
UpstreamData
2500ec3869 bug: fix possible None return from some bosminer webcommands. 2023-06-29 18:10:10 -06:00
UpstreamData
5be3187eec version: bump version number. 2023-06-29 16:51:29 -06:00
UpstreamData
be1e9127b0 bug: fix weird pool info when multiple groups are defined. 2023-06-29 16:51:15 -06:00
UpstreamData
13572c4770 version: bump version number. 2023-06-29 16:48:09 -06:00
UpstreamData
08fa3961fe bug: fix bosminer on X19 not reporting pause mode correctly. 2023-06-29 16:47:27 -06:00
UpstreamData
b5d2809e9c format: remove random print statements. 2023-06-29 15:53:53 -06:00
UpstreamData
aa538d3079 docs: add miner docs generation file. 2023-06-28 11:21:19 -06:00
UpstreamData
e1500bb75c docs: update docs. 2023-06-28 11:20:22 -06:00
UpstreamData
7f00a65598 version: bump version number. 2023-06-27 16:23:46 -06:00
UpstreamData
64c473a7d4 bug: fix improper stats key when getting uptime. 2023-06-27 16:23:21 -06:00
UpstreamData
96d9fe8e6c version: bump version number. 2023-06-27 14:56:11 -06:00
UpstreamData
0b27400d27 feature: add set_static_ip and set_dhcp for bosminer. 2023-06-27 14:55:05 -06:00
UpstreamData
666b9dfe94 version: bump version number. 2023-06-27 09:36:06 -06:00
UpstreamData
df3a080c9d feature: add uptime check for some miners, and fix a bug with get_mac on BOS. 2023-06-27 09:35:07 -06:00
UpstreamData
bf3bd7c2b9 feature: add basic support for LuxOS 2023-06-26 15:35:52 -06:00
UpstreamData
37fd60b462 version: bump version number. 2023-06-26 09:53:21 -06:00
UpstreamData
2245904740 feature: remove ssh references when getting MAC on bosminer. 2023-06-26 09:52:30 -06:00
UpstreamData
7b1b23016e feature: add support for VNish S19 No PIC. 2023-06-26 08:20:45 -06:00
UpstreamData
b5fcd62e23 version: bump version number. 2023-06-23 14:50:14 -06:00
UpstreamData
9057cde274 docs: add is_mining to docs. 2023-06-23 14:49:38 -06:00
UpstreamData
f6d35888fe feature: add is_mining to MinerData and get_data. 2023-06-23 14:47:12 -06:00
UpstreamData
f2abe9fd9e feature: add is_mining to all miner types. 2023-06-23 14:38:38 -06:00
UpstreamData
7d1a702804 feature: make is_mining abstract method. 2023-06-23 14:34:44 -06:00
UpstreamData
65d1695ce4 bug: fix is_mining for some miners. 2023-06-23 14:33:32 -06:00
UpstreamData
65fd66b8bf feature: add is_mining for antminer. 2023-06-23 14:08:54 -06:00
UpstreamData
5db52c46f3 feature: add is_mining for btminer, and fix some minor bugs. 2023-06-23 13:38:45 -06:00
UpstreamData
d06cb19da3 feature: add is_mining for bosminers. 2023-06-23 12:39:00 -06:00
UpstreamData
4530d086da bug: fix some cases where web command data can fail. 2023-06-23 11:23:20 -06:00
UpstreamData
0bd679f259 version: bump version number. 2023-06-22 15:07:25 -06:00
UpstreamData
1ce5bd0566 Update miner data and fix various bugs related to the fix. (#47)
* feature: fix influxdb data.

* bug: fix an issue with some avalon stats parsing.

* bug: add chip count for 1166 Pro.

* bug: fix some issues with bosminer scanning and some data bugs.

* bug: remove print statement.

* bug: fix failed data gathering multicommand via graphql.

* feature: add partial support for M50S+VK20

* version: bump version number.

* bug: add chip count for M50S+VK20.

* version: bump version number.

* bug: attempt to fix offset check issue on BOS+.

* bug: fix NoneType subscription on BOS+.

* bug: add support for Vnish S17+.

* bug: remove web references for Avalons.

* bug: add support for VNish S17Pro.

* bug: Try secondary identification method for antminers.

* feature: fix a bunch of functionality for avalonminers.

* bug: fix avalonminer fan speed being set as str.

* bug: fix fans speeds being represented as strings.

* bug: fix some get_fan formatting.

* docs: update supported miners list, and fix A10X model name.

* docs: update MinerData docstrings.

* docs: update factory documentation.
2023-06-22 15:06:30 -06:00
UpstreamData
67c3d05ac3 version: bump version number. 2023-06-20 12:11:43 -06:00
UpstreamData
c691868e9b bug: add chip count for M50S+VK20. 2023-06-20 12:11:05 -06:00
UpstreamData
f5e15b4046 version: bump version number. 2023-06-19 16:10:34 -06:00
UpstreamData
e14df696ee feature: add partial support for M50S+VK20 2023-06-19 16:10:00 -06:00
UpstreamData
ce5dfad850 version: bump version number. 2023-06-12 13:04:11 -06:00
UpstreamData
5cb45390be bug: add chip count for avalon 1246. 2023-06-12 13:03:41 -06:00
UpstreamData
b5216a24a6 version: bump version number. 2023-06-12 12:47:58 -06:00
UpstreamData
dd175ff3a2 bug: fix an issue with 2020 versions of Braiins OS not identifying correctly. 2023-06-12 12:47:38 -06:00
UpstreamData
9b504a3157 version: bump version number. 2023-06-12 12:42:16 -06:00
UpstreamData
0bc3bf20ee bug: fix possible missing models. 2023-06-12 12:41:50 -06:00
UpstreamData
de5380715c version: bump version number. 2023-06-12 11:06:20 -06:00
UpstreamData
00a108252d version: bump version number. 2023-06-12 11:04:22 -06:00
UpstreamData
e446176922 refactor: refactor miner types. 2023-06-12 11:02:51 -06:00
UpstreamData
134c44aedc Improve get_miner (#43)
* feature: Start refactor to new style of get_miner.  Needs testing and stability fixes.

* feature: refactor to aiohttp and fix a lot of bugs with factory.  Still needs support for some miners.

* feature: refactor miner class list to be much more readable.

* bug: remove some redundant .upper() calls.

* bug: remove some redundant .upper() calls.

* feature: add Avalonminer support in update miner factory, and add support for A1166 and A1246.

* feature: refactor get_miner to allow models to be selected as strings then selected in the top level get_miner function.

* bug: fix some naming issues, and add timeout to getting miner model.

* bug: fix not instantiating some web sessions properly.
2023-06-12 09:09:51 -06:00
UpstreamData
a2bb8b5d9b version: bump version number. 2023-06-02 09:29:42 -06:00
UpstreamData
62aaf36fd7 bug: re-order config sent to S19 to be consistent with stock. 2023-06-02 09:28:50 -06:00
435 changed files with 8336 additions and 6485 deletions

View File

@@ -1,5 +1,5 @@
# pyasic # pyasic
*A set of modules for interfacing with many common types of ASIC bitcoin miners, using both their API and SSH.* *A simplified and standardized interface for Bitcoin ASICs.*
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![pypi](https://img.shields.io/pypi/v/pyasic.svg)](https://pypi.org/project/pyasic/) [![pypi](https://img.shields.io/pypi/v/pyasic.svg)](https://pypi.org/project/pyasic/)

View File

@@ -15,6 +15,7 @@ Use these instead -
#### [BOSMiner API][pyasic.API.bosminer.BOSMinerAPI] #### [BOSMiner API][pyasic.API.bosminer.BOSMinerAPI]
#### [BTMiner API][pyasic.API.btminer.BTMinerAPI] #### [BTMiner API][pyasic.API.btminer.BTMinerAPI]
#### [CGMiner API][pyasic.API.cgminer.CGMinerAPI] #### [CGMiner API][pyasic.API.cgminer.CGMinerAPI]
#### [LUXMiner API][pyasic.API.luxminer.LUXMinerAPI]
#### [Unknown API][pyasic.API.unknown.UnknownAPI] #### [Unknown API][pyasic.API.unknown.UnknownAPI]
<br> <br>

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

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

165
docs/generate_miners.py Normal file
View File

@@ -0,0 +1,165 @@
import asyncio
import importlib
import os
import warnings
from pyasic.miners.miner_factory import MINER_CLASSES, MinerTypes
warnings.filterwarnings("ignore")
def path(cls):
module = importlib.import_module(cls.__module__)
return module.__name__ + "." + cls.__name__
def make(cls):
p = path(cls)
return p.split(".")[2]
def model_type(cls):
p = path(cls)
return p.split(".")[4]
def backend_str(backend: MinerTypes) -> str:
match backend:
case MinerTypes.ANTMINER:
return "Stock Firmware Antminers"
case MinerTypes.AVALONMINER:
return "Stock Firmware Avalonminers"
case MinerTypes.VNISH:
return "Vnish Firmware Miners"
case MinerTypes.EPIC:
return "ePIC Firmware Miners"
case MinerTypes.BRAIINS_OS:
return "BOS+ Firmware Miners"
case MinerTypes.HIVEON:
return "HiveOS Firmware Miners"
case MinerTypes.INNOSILICON:
return "Stock Firmware Innosilicons"
case MinerTypes.WHATSMINER:
return "Stock Firmware Whatsminers"
case MinerTypes.GOLDSHELL:
return "Stock Firmware Goldshells"
case MinerTypes.LUX_OS:
return "LuxOS Firmware Miners"
def create_url_str(mtype: str):
return (
mtype.lower()
.replace(" ", "-")
.replace("(", "")
.replace(")", "")
.replace("+", "_1")
)
HEADER_FORMAT = "# pyasic\n## {} Models\n\n"
MINER_HEADER_FORMAT = "## {}\n"
DATA_FORMAT = """::: {}
handler: python
options:
show_root_heading: false
heading_level: 4
"""
SUPPORTED_TYPES_HEADER = """# pyasic
## Supported Miners
Supported miner types are here on this list. If your miner (or miner version) is not on this list, please feel free to [open an issue on GitHub](https://github.com/UpstreamData/pyasic/issues) to get it added.
##### pyasic currently supports the following miners and subtypes:
<style>
details {
margin:0px;
padding-top:0px;
padding-bottom:0px;
}
</style>
"""
BACKEND_TYPE_HEADER = """
<details>
<summary>{}:</summary>
<ul>"""
MINER_TYPE_HEADER = """
<details>
<summary>{} Series:</summary>
<ul>"""
MINER_DETAILS = """
<li><a href="../{}/{}#{}">{}</a></li>"""
MINER_TYPE_CLOSER = """
</ul>
</details>"""
BACKEND_TYPE_CLOSER = """
</ul>
</details>"""
m_data = {}
for m in MINER_CLASSES:
for t in MINER_CLASSES[m]:
if t is not None:
miner = MINER_CLASSES[m][t]
if make(miner) not in m_data:
m_data[make(miner)] = {}
if model_type(miner) not in m_data[make(miner)]:
m_data[make(miner)][model_type(miner)] = []
m_data[make(miner)][model_type(miner)].append(miner)
async def create_directory_structure(directory, data):
if not os.path.exists(directory):
os.makedirs(directory)
for key, value in data.items():
subdirectory = os.path.join(directory, key)
if isinstance(value, dict):
await create_directory_structure(subdirectory, value)
elif isinstance(value, list):
file_path = os.path.join(subdirectory + ".md")
with open(file_path, "w") as file:
file.write(HEADER_FORMAT.format(key))
for item in value:
header = await item("1.1.1.1").get_model()
file.write(MINER_HEADER_FORMAT.format(header))
file.write(DATA_FORMAT.format(path(item)))
async def create_supported_types(directory):
with open(os.path.join(directory, "supported_types.md"), "w") as file:
file.write(SUPPORTED_TYPES_HEADER)
for mback in MINER_CLASSES:
backend_types = {}
file.write(BACKEND_TYPE_HEADER.format(backend_str(mback)))
for mtype in MINER_CLASSES[mback]:
if mtype is None:
continue
m = MINER_CLASSES[mback][mtype]
if model_type(m) not in backend_types:
backend_types[model_type(m)] = []
backend_types[model_type(m)].append(m)
for mtype in backend_types:
file.write(MINER_TYPE_HEADER.format(mtype))
for minstance in backend_types[mtype]:
model = await minstance("1.1.1.1").get_model()
file.write(
MINER_DETAILS.format(
make(minstance), mtype, create_url_str(model), model
)
)
file.write(MINER_TYPE_CLOSER)
file.write(BACKEND_TYPE_CLOSER)
root_directory = os.path.join(os.getcwd(), "miners")
asyncio.run(create_directory_structure(root_directory, m_data))
asyncio.run(create_supported_types(root_directory))

View File

@@ -19,7 +19,7 @@ Getting started with pyasic is easy. First, find your miner (or miners) on the
## Scanning for miners ## Scanning for miners
To scan for miners in pyasic, we use the class [`MinerNetwork`][pyasic.network.MinerNetwork], which abstracts the search, communication, identification, setup, and return of a miner to 1 command. To scan for miners in pyasic, we use the class [`MinerNetwork`][pyasic.network.MinerNetwork], which abstracts the search, communication, identification, setup, and return of a miner to 1 command.
The command [`MinerNetwork().scan_network_for_miners()`][pyasic.network.MinerNetwork.scan_network_for_miners] returns a list that contains any miners found. The command [`MinerNetwork.scan()`][pyasic.network.MinerNetwork.scan] returns a list that contains any miners found.
```python ```python
import asyncio # asyncio for handling the async part import asyncio # asyncio for handling the async part
from pyasic.network import MinerNetwork # miner network handles the scanning from pyasic.network import MinerNetwork # miner network handles the scanning
@@ -28,7 +28,7 @@ from pyasic.network import MinerNetwork # miner network handles the scanning
async def scan_miners(): # define async scan function to allow awaiting async def scan_miners(): # define async scan function to allow awaiting
# create a miner network # create a miner network
# you can pass in any IP and it will use that in a subnet with a /24 mask (255 IPs). # you can pass in any IP and it will use that in a subnet with a /24 mask (255 IPs).
network = MinerNetwork("192.168.1.50") # this uses the 192.168.1.0-255 network network = MinerNetwork.from_subnet("192.168.1.50/24") # this uses the 192.168.1.0-255 network
# scan for miners asynchronously # scan for miners asynchronously
# this will return the correct type of miners if they are supported with all functionality. # this will return the correct type of miners if they are supported with all functionality.
@@ -42,8 +42,8 @@ if __name__ == "__main__":
<br> <br>
## Creating miners based on IP ## Creating miners based on IP
If you already know the IP address of your miner or miners, you can use the [`MinerFactory`][pyasic.miners.miner_factory.MinerFactory] to communicate and identify the miners, or an abstraction of its functionality, [`get_miner()`][pyasic.miners.miner_factory.MinerFactory.get_miner]. If you already know the IP address of your miner or miners, you can use the [`MinerFactory`][pyasic.miners.miner_factory.MinerFactory] to communicate and identify the miners, or an abstraction of its functionality, [`get_miner()`][pyasic.miners.get_miner].
The function [`get_miner()`][pyasic.miners.miner_factory.MinerFactory.get_miner] will return any miner it found at the IP address specified, or an `UnknownMiner` if it cannot identify the miner. The function [`get_miner()`][pyasic.miners.get_miner] will return any miner it found at the IP address specified, or an `UnknownMiner` if it cannot identify the miner.
```python ```python
import asyncio # asyncio for handling the async part import asyncio # asyncio for handling the async part
from pyasic import get_miner # handles miner creation from pyasic import get_miner # handles miner creation
@@ -76,13 +76,14 @@ This function will return an instance of the dataclass [`MinerData`][pyasic.data
Each piece of data in a [`MinerData`][pyasic.data.MinerData] instance can be referenced by getting it as an attribute, such as [`MinerData().hashrate`][pyasic.data.MinerData]. Each piece of data in a [`MinerData`][pyasic.data.MinerData] instance can be referenced by getting it as an attribute, such as [`MinerData().hashrate`][pyasic.data.MinerData].
```python ```python
import asyncio import asyncio
from pyasic.miners.miner_factory import MinerFactory from pyasic import get_miner
async def gather_miner_data(): async def gather_miner_data():
miner = await MinerFactory().get_miner("192.168.1.75") miner = await get_miner("192.168.1.75")
miner_data = await miner.get_data() if miner is not None:
print(miner_data) # all data from the dataclass miner_data = await miner.get_data()
print(miner_data.hashrate) # hashrate of the miner in TH/s print(miner_data) # all data from the dataclass
print(miner_data.hashrate) # hashrate of the miner in TH/s
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(gather_miner_data()) asyncio.run(gather_miner_data())
@@ -126,6 +127,7 @@ These functions are
[`restart_backend`](#restart-backend), [`restart_backend`](#restart-backend),
[`stop_mining`](#stop-mining), [`stop_mining`](#stop-mining),
[`resume_mining`](#resume-mining), [`resume_mining`](#resume-mining),
[`is_mining`](#is-mining),
[`send_config`](#send-config), and [`send_config`](#send-config), and
[`set_power_limit`](#set-power-limit). [`set_power_limit`](#set-power-limit).
@@ -227,6 +229,14 @@ These functions are
<br> <br>
### Is Mining
::: pyasic.miners.BaseMiner.is_mining
handler: python
options:
heading_level: 4
<br>
### Send Config ### Send Config
::: pyasic.miners.BaseMiner.send_config ::: pyasic.miners.BaseMiner.send_config
handler: python handler: python
@@ -253,7 +263,7 @@ Pyasic implements a few dataclasses as helpers to make data return types consist
[`MinerData`][pyasic.data.MinerData] is a return from the [`get_data()`](#get-data) function, and is used to have a consistent dataset across all returns. [`MinerData`][pyasic.data.MinerData] is a return from the [`get_data()`](#get-data) function, and is used to have a consistent dataset across all returns.
You can call [`MinerData.asdict()`][pyasic.data.MinerData.asdict] to get the dataclass as a dictionary, and there are many other helper functions contained in the class to convert to different data formats. You can call [`MinerData.as_dict()`][pyasic.data.MinerData.as_dict] to get the dataclass as a dictionary, and there are many other helper functions contained in the class to convert to different data formats.
[`MinerData`][pyasic.data.MinerData] instances can also be added to each other to combine their data and can be divided by a number to divide all their data, allowing you to get average data from many miners by doing - [`MinerData`][pyasic.data.MinerData] instances can also be added to each other to combine their data and can be divided by a number to divide all their data, allowing you to get average data from many miners by doing -
```python ```python
@@ -278,3 +288,28 @@ It is the return from [`get_config()`](#get-config).
Each miner has a unique way to convert the [`MinerConfig`][pyasic.config.MinerConfig] to their specific type, there are helper functions in the class. Each miner has a unique way to convert the [`MinerConfig`][pyasic.config.MinerConfig] to their specific type, there are helper functions in the class.
In most cases these helper functions should not be used, as [`send_config()`](#send-config) takes a [`MinerConfig`][pyasic.config.MinerConfig] and will do the conversion to the right type for you. In most cases these helper functions should not be used, as [`send_config()`](#send-config) takes a [`MinerConfig`][pyasic.config.MinerConfig] and will do the conversion to the right type for you.
## Settings
`pyasic` has settings designed to make using large groups of miners easier. You can set the default password for all types of miners using the [`pyasic.settings`][pyasic.settings] module, used as follows:
```python
from pyasic import settings
settings.update("default_antminer_password", "my_pwd")
```
Here are of all the settings, and their default values:
```
"network_ping_retries": 1,
"network_ping_timeout": 3,
"network_scan_threads": 300,
"factory_get_retries": 1,
"get_data_retries": 1,
"default_whatsminer_password": "admin",
"default_innosilicon_password": "admin",
"default_antminer_password": "root",
"default_bosminer_password": "root",
"default_vnish_password": "admin",
"default_epic_password": "letmein",
"default_goldshell_password": "123456789",
```

View File

@@ -1,11 +1,10 @@
# pyasic # pyasic
## X15 Models ## X15 Models
## Z15 ## Z15
::: pyasic.miners.antminer.cgminer.X15.Z15.CGMinerZ15
::: pyasic.miners.zec.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

View File

@@ -2,116 +2,114 @@
## X17 Models ## X17 Models
## S17 ## S17
::: pyasic.miners.antminer.bmminer.X17.S17.BMMinerS17
::: pyasic.miners.btc.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+
::: pyasic.miners.antminer.bmminer.X17.S17.BMMinerS17Plus
::: pyasic.miners.btc.antminer.bmminer.X17.S17_Plus.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
::: pyasic.miners.antminer.bmminer.X17.S17.BMMinerS17Pro
::: pyasic.miners.btc.antminer.bmminer.X17.S17_Pro.BMMinerS17Pro
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## S17e ## S17e
::: pyasic.miners.antminer.bmminer.X17.S17.BMMinerS17e
::: pyasic.miners.btc.antminer.bmminer.X17.S17e.BMMinerS17e
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## T17 ## T17
::: pyasic.miners.antminer.bmminer.X17.T17.BMMinerT17
::: pyasic.miners.btc.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+
::: pyasic.miners.antminer.bmminer.X17.T17.BMMinerT17Plus
::: pyasic.miners.btc.antminer.bmminer.X17.T17_Plus.BMMinerT17Plus
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## T17e ## T17e
::: pyasic.miners.antminer.bmminer.X17.T17.BMMinerT17e
::: pyasic.miners.btc.antminer.bmminer.X17.T17e.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.btc.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.btc.antminer.bosminer.X17.S17_Plus.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.btc.antminer.bosminer.X17.S17_Pro.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.btc.antminer.bosminer.X17.S17e.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.btc.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.btc.antminer.bosminer.X17.T17_Plus.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.btc.antminer.bosminer.X17.T17e.BOSMinerT17e
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## S17+ (VNish)
::: pyasic.miners.antminer.vnish.X17.S17.VNishS17Plus
handler: python
options:
show_root_heading: false
heading_level: 4
## S17 Pro (VNish)
::: pyasic.miners.antminer.vnish.X17.S17.VNishS17Pro
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -2,109 +2,233 @@
## X19 Models ## X19 Models
## S19 ## S19
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19
::: pyasic.miners.btc.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
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19L
::: pyasic.miners.btc.antminer.bmminer.X19.S19L.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
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19Pro
::: pyasic.miners.btc.antminer.bmminer.X19.S19_Pro.BMMinerS19Pro
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## S19a
::: pyasic.miners.btc.antminer.bmminer.X19.S19a.BMMinerS19a
handler: python
options:
show_root_heading: false
heading_level: 4
## S19j ## S19j
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19j
handler: python
options:
show_root_heading: false
heading_level: 4
::: pyasic.miners.btc.antminer.bmminer.X19.S19j.BMMinerS19j ## S19i
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19i
handler: python
options:
show_root_heading: false
heading_level: 4
## S19+
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19Plus
handler: python
options:
show_root_heading: false
heading_level: 4
## S19j No PIC
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19jNoPIC
handler: python
options:
show_root_heading: false
heading_level: 4
## S19 Pro+
::: 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
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19jPro
::: pyasic.miners.btc.antminer.bmminer.X19.S19j_Pro.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
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19XP
handler: python
options:
show_root_heading: false
heading_level: 4
::: pyasic.miners.btc.antminer.bmminer.X19.S19_XP.BMMinerS19XP ## S19a
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19a
handler: python
options:
show_root_heading: false
heading_level: 4
## S19a Pro
::: 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 ## T19
::: pyasic.miners.antminer.bmminer.X19.T19.BMMinerT19
::: pyasic.miners.btc.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.btc.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 Pro (BOS)
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19Pro
::: pyasic.miners.btc.antminer.bosminer.X19.S19_Pro.BOSMinerS19Pro
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## S19j (BOS) ## S19j (BOS)
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19j
handler: python
options:
show_root_heading: false
heading_level: 4
::: pyasic.miners.btc.antminer.bosminer.X19.S19j.BOSMinerS19j ## S19j No PIC (BOS)
::: 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
handler: python
options:
show_root_heading: false
heading_level: 4
::: pyasic.miners.btc.antminer.bosminer.X19.S19j_Pro.BOSMinerS19jPro ## S19j Pro (BOS)
::: 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
## T19 (BOS) ## T19 (BOS)
::: pyasic.miners.antminer.bosminer.X19.T19.BOSMinerT19
::: pyasic.miners.btc.antminer.bosminer.X19.T19.BOSMinerT19
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## S19 (VNish)
::: pyasic.miners.antminer.vnish.X19.S19.VNishS19
handler: python
options:
show_root_heading: false
heading_level: 4
## S19 No PIC (VNish)
::: pyasic.miners.antminer.vnish.X19.S19.VNishS19NoPIC
handler: python
options:
show_root_heading: false
heading_level: 4
## S19 Pro (VNish)
::: pyasic.miners.antminer.vnish.X19.S19.VNishS19Pro
handler: python
options:
show_root_heading: false
heading_level: 4
## S19j (VNish)
::: pyasic.miners.antminer.vnish.X19.S19.VNishS19j
handler: python
options:
show_root_heading: false
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)
::: pyasic.miners.antminer.vnish.X19.S19.VNishS19a
handler: python
options:
show_root_heading: false
heading_level: 4
## S19a Pro (VNish)
::: pyasic.miners.antminer.vnish.X19.S19.VNishS19aPro
handler: python
options:
show_root_heading: false
heading_level: 4
## T19 (VNish)
::: pyasic.miners.antminer.vnish.X19.T19.VNishT19
handler: python
options:
show_root_heading: false
heading_level: 4
## S19 (ePIC)
::: pyasic.miners.antminer.epic.X19.S19.ePICS19
handler: python
options:
show_root_heading: false
heading_level: 4
## S19 Pro (ePIC)
::: pyasic.miners.antminer.epic.X19.S19.ePICS19Pro
handler: python
options:
show_root_heading: false
heading_level: 4
## S19j (ePIC)
::: pyasic.miners.antminer.epic.X19.S19.ePICS19j
handler: python
options:
show_root_heading: false
heading_level: 4
## S19j Pro (ePIC)
::: pyasic.miners.antminer.epic.X19.S19.ePICS19jPro
handler: python
options:
show_root_heading: false
heading_level: 4
## S19 XP (ePIC)
::: pyasic.miners.antminer.epic.X19.S19.ePICS19XP
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -1,11 +1,31 @@
# pyasic # pyasic
## X3 Models ## X3 Models
## D3
## HS3 ::: pyasic.miners.antminer.cgminer.X3.D3.CGMinerD3
::: pyasic.miners.hns.antminer.cgminer.X3.HS3.CGMinerHS3
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## HS3
::: pyasic.miners.antminer.bmminer.X3.HS3.BMMinerHS3
handler: python
options:
show_root_heading: false
heading_level: 4
## L3+
::: pyasic.miners.antminer.bmminer.X3.L3.BMMinerL3Plus
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

View File

@@ -1,11 +1,10 @@
# pyasic # pyasic
## X5 Models ## X5 Models
## DR5 ## DR5
::: pyasic.miners.antminer.cgminer.X5.DR5.CGMinerDR5
::: pyasic.miners.dcr.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

View File

@@ -1,11 +1,10 @@
# pyasic # pyasic
## X7 Models ## X7 Models
## L7 ## L7
::: pyasic.miners.antminer.bmminer.X7.L7.BMMinerL7
::: pyasic.miners.ltc.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

View File

@@ -1,44 +1,59 @@
# pyasic # pyasic
## X9 Models ## X9 Models
## E9Pro
## X9 (BOS) ::: pyasic.miners.antminer.bmminer.X9.E9.BMMinerE9Pro
::: pyasic.miners.btc.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
## S9 ## S9
::: pyasic.miners.antminer.bmminer.X9.S9.BMMinerS9
::: pyasic.miners.btc.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
::: pyasic.miners.antminer.bmminer.X9.S9.BMMinerS9i
handler: python
options:
show_root_heading: false
heading_level: 4
::: pyasic.miners.btc.antminer.bmminer.X9.S9i.BMMinerS9i ## S9j
::: 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
::: pyasic.miners.antminer.bmminer.X9.T9.BMMinerT9
::: pyasic.miners.btc.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
## E9 Pro ## S9 (BOS)
::: pyasic.miners.antminer.bosminer.X9.S9.BOSMinerS9
::: pyasic.miners.etc.antminer.cgminer.X9.E9_Pro.CGMinerE9Pro
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## T9 (Hiveon)
::: pyasic.miners.antminer.hiveon.X9.T9.HiveonT9
handler: python
options:
show_root_heading: false
heading_level: 4
## S9 (LuxOS)
::: pyasic.miners.antminer.luxos.X9.S9.LUXMinerS9
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -1,26 +1,24 @@
# pyasic # pyasic
## A10X Models ## A10X Models
## A1026 ## Avalon 1026
::: pyasic.miners.avalonminer.cgminer.A10X.A1026.CGMinerAvalon1026
::: pyasic.miners.btc.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
## A1047 ## Avalon 1047
::: pyasic.miners.avalonminer.cgminer.A10X.A1047.CGMinerAvalon1047
::: pyasic.miners.btc.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
## A1066 ## Avalon 1066
::: pyasic.miners.avalonminer.cgminer.A10X.A1066.CGMinerAvalon1066
::: pyasic.miners.btc.avalonminer.cgminer.A10X.A1066.CGMinerAvalon1066
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4

View File

@@ -0,0 +1,10 @@
# pyasic
## A11X Models
## Avalon 1166 Pro
::: pyasic.miners.avalonminer.cgminer.A11X.A1166.CGMinerAvalon1166Pro
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -0,0 +1,10 @@
# pyasic
## A12X Models
## Avalon 1246
::: pyasic.miners.avalonminer.cgminer.A12X.A1246.CGMinerAvalon1246
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -1,26 +1,24 @@
# pyasic # pyasic
## A7X Models ## A7X Models
## A721 ## Avalon 721
::: pyasic.miners.avalonminer.cgminer.A7X.A721.CGMinerAvalon721
::: pyasic.miners.btc.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
## A741 ## Avalon 741
::: pyasic.miners.avalonminer.cgminer.A7X.A741.CGMinerAvalon741
::: pyasic.miners.btc.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
## A761 ## Avalon 761
::: pyasic.miners.avalonminer.cgminer.A7X.A761.CGMinerAvalon761
::: pyasic.miners.btc.avalonminer.cgminer.A7X.A761.CGMinerAvalon761
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4

View File

@@ -1,26 +1,24 @@
# pyasic # pyasic
## A8X Models ## A8X Models
## A821 ## Avalon 821
::: pyasic.miners.avalonminer.cgminer.A8X.A821.CGMinerAvalon821
::: pyasic.miners.btc.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
## A841 ## Avalon 841
::: pyasic.miners.avalonminer.cgminer.A8X.A841.CGMinerAvalon841
::: pyasic.miners.btc.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
## A851 ## Avalon 851
::: pyasic.miners.avalonminer.cgminer.A8X.A851.CGMinerAvalon851
::: pyasic.miners.btc.avalonminer.cgminer.A8X.A851.CGMinerAvalon851
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4

View File

@@ -1,10 +1,10 @@
# pyasic # pyasic
## A9X Models ## A9X Models
## A921 ## Avalon 921
::: pyasic.miners.avalonminer.cgminer.A9X.A921.CGMinerAvalon921
::: pyasic.miners.btc.avalonminer.cgminer.A9X.A921.CGMinerAvalon921
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4

View File

@@ -1,9 +1,7 @@
# pyasic # pyasic
## CKX Models ## ePIC Backend
## CK5 ::: pyasic.miners.backends.epic.ePIC
::: pyasic.miners.ckb.goldshell.bfgminer.CKX.CK5.BFGMinerCK5
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false

View File

@@ -1,9 +1,7 @@
# pyasic # pyasic
## HSX Models ## LUXMiner Backend
## HS5 ::: pyasic.miners.backends.luxminer.LUXMiner
::: pyasic.miners.hns.goldshell.bfgminer.HSX.HS5.BFGMinerHS5
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false

View File

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

View File

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

View File

@@ -0,0 +1,24 @@
# pyasic
## X5 Models
## CK5
::: pyasic.miners.goldshell.bfgminer.X5.CK5.BFGMinerCK5
handler: python
options:
show_root_heading: false
heading_level: 4
## HS5
::: pyasic.miners.goldshell.bfgminer.X5.HS5.BFGMinerHS5
handler: python
options:
show_root_heading: false
heading_level: 4
## KD5
::: pyasic.miners.goldshell.bfgminer.X5.KD5.BFGMinerKD5
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -0,0 +1,10 @@
# pyasic
## XMax Models
## KD Max
::: pyasic.miners.goldshell.bfgminer.XMax.KDMax.BFGMinerKDMax
handler: python
options:
show_root_heading: false
heading_level: 4

View File

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

View File

@@ -2,9 +2,9 @@
## T3X Models ## T3X Models
## T3H+ ## T3H+
::: pyasic.miners.innosilicon.cgminer.T3X.T3H.CGMinerT3HPlus
::: pyasic.miners.btc.innosilicon.cgminer.T3X.T3H_Plus.CGMinerInnosiliconT3HPlus
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4

View File

@@ -1,6 +1,14 @@
# pyasic # pyasic
## Miner Factory ## Miner Factory
[`MinerFactory`][pyasic.miners.miner_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`.
[`MinerFactory`][pyasic.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()`.
::: pyasic.miners.miner_factory.MinerFactory ::: pyasic.miners.miner_factory.MinerFactory
handler: python handler: python
options: options:
@@ -8,6 +16,14 @@
heading_level: 4 heading_level: 4
<br> <br>
## Get Miner
::: pyasic.miners.get_miner
handler: python
options:
show_root_heading: false
heading_level: 4
<br>
## AnyMiner ## AnyMiner
::: pyasic.miners.miner_factory.AnyMiner ::: pyasic.miners.miner_factory.AnyMiner
handler: python handler: python

View File

@@ -11,37 +11,74 @@ details {
padding-bottom:0px; padding-bottom:0px;
} }
</style> </style>
<details style="margin:0px; padding-top:0px; padding-bottom:0px;">
<summary>Braiins OS+ Devices:</summary> <details>
<summary>Stock Firmware Antminers:</summary>
<ul> <ul>
<details> <details>
<summary>X19 Series:</summary> <summary>X3 Series:</summary>
<ul> <ul>
<li><a href="../antminer/X19#s19-bos">S19</a></li> <li><a href="../antminer/X3#d3">D3</a></li>
<li><a href="../antminer/X19#s19-pro-bos">S19 Pro</a></li> <li><a href="../antminer/X3#hs3">HS3</a></li>
<li><a href="../antminer/X19#s19j-bos">S19j</a></li> <li><a href="../antminer/X3#l3_1">L3+</a></li>
<li><a href="../antminer/X19#s19j-pro-bos">S19j Pro</a></li>
<li><a href="../antminer/X19#t19-bos">T19</a></li>
</ul> </ul>
</details> </details>
<details> <details>
<summary>X17 Series:</summary> <summary>X5 Series:</summary>
<ul> <ul>
<li><a href="../antminer/X17#s17-bos">S17</a></li> <li><a href="../antminer/X5#dr5">DR5</a></li>
<li><a href="../antminer/X17#s17-plus-bos">S17+</a></li> </ul>
<li><a href="../antminer/X17#s17-pro-bos">S17 Pro</a></li> </details>
<li><a href="../antminer/X17#s17e-bos">S17e</a></li> <details>
<li><a href="../antminer/X17#t17-bos">T17</a></li> <summary>X7 Series:</summary>
<li><a href="../antminer/X17#t17-plus-bos">T17+</a></li> <ul>
<li><a href="../antminer/X17#t17e-bos">T17e</a></li> <li><a href="../antminer/X7#l7">L7</a></li>
</ul> </ul>
</details> </details>
<details> <details>
<summary>X9 Series:</summary> <summary>X9 Series:</summary>
<ul> <ul>
<li><a href="../antminer/X9#s9-bos">S9</a></li> <li><a href="../antminer/X9#e9pro">E9Pro</a></li>
<li><a href="../antminer/X9#s9-bos">S9i</a></li> <li><a href="../antminer/X9#s9">S9</a></li>
<li><a href="../antminer/X9#s9-bos">S9j</a></li> <li><a href="../antminer/X9#s9i">S9i</a></li>
<li><a href="../antminer/X9#s9j">S9j</a></li>
<li><a href="../antminer/X9#t9">T9</a></li>
</ul>
</details>
<details>
<summary>X15 Series:</summary>
<ul>
<li><a href="../antminer/X15#z15">Z15</a></li>
</ul>
</details>
<details>
<summary>X17 Series:</summary>
<ul>
<li><a href="../antminer/X17#s17">S17</a></li>
<li><a href="../antminer/X17#s17_1">S17+</a></li>
<li><a href="../antminer/X17#s17-pro">S17 Pro</a></li>
<li><a href="../antminer/X17#s17e">S17e</a></li>
<li><a href="../antminer/X17#t17">T17</a></li>
<li><a href="../antminer/X17#t17_1">T17+</a></li>
<li><a href="../antminer/X17#t17e">T17e</a></li>
</ul>
</details>
<details>
<summary>X19 Series:</summary>
<ul>
<li><a href="../antminer/X19#s19">S19</a></li>
<li><a href="../antminer/X19#s19l">S19L</a></li>
<li><a href="../antminer/X19#s19-pro">S19 Pro</a></li>
<li><a href="../antminer/X19#s19j">S19j</a></li>
<li><a href="../antminer/X19#s19i">S19i</a></li>
<li><a href="../antminer/X19#s19_1">S19+</a></li>
<li><a href="../antminer/X19#s19j-no-pic">S19j No PIC</a></li>
<li><a href="../antminer/X19#s19-pro_1">S19 Pro+</a></li>
<li><a href="../antminer/X19#s19j-pro">S19j Pro</a></li>
<li><a href="../antminer/X19#s19-xp">S19 XP</a></li>
<li><a href="../antminer/X19#s19a">S19a</a></li>
<li><a href="../antminer/X19#s19a-pro">S19a Pro</a></li>
<li><a href="../antminer/X19#t19">T19</a></li>
</ul> </ul>
</details> </details>
</ul> </ul>
@@ -51,440 +88,210 @@ details {
<ul> <ul>
<details> <details>
<summary>M2X Series:</summary> <summary>M2X Series:</summary>
<ul> <ul>
<details> <li><a href="../whatsminer/M2X#m20-v10">M20 V10</a></li>
<summary><a href='../whatsminer/M2X/#M20'>M20</a></summary> <li><a href="../whatsminer/M2X#m20s-v10">M20S V10</a></li>
<ul> <li><a href="../whatsminer/M2X#m20s-v20">M20S V20</a></li>
<li><a href='../whatsminer/M2X/#M20V10'>M20V10</a></li> <li><a href="../whatsminer/M2X#m20s-v30">M20S V30</a></li>
</ul> <li><a href="../whatsminer/M2X#m20p-v10">M20P V10</a></li>
</details> <li><a href="../whatsminer/M2X#m20p-v30">M20P V30</a></li>
<details> <li><a href="../whatsminer/M2X#m20s_1-v30">M20S+ V30</a></li>
<summary><a href='../whatsminer/M2X/#M20S'>M20S</a></summary> <li><a href="../whatsminer/M2X#m21-v10">M21 V10</a></li>
<ul> <li><a href="../whatsminer/M2X#m21s-v20">M21S V20</a></li>
<li><a href='../whatsminer/M2X/#M20SV10'>M20SV10</a></li> <li><a href="../whatsminer/M2X#m21s-v60">M21S V60</a></li>
<li><a href='../whatsminer/M2X/#M20SV20'>M20SV20</a></li> <li><a href="../whatsminer/M2X#m21s-v70">M21S V70</a></li>
<li><a href='../whatsminer/M2X/#M20SV30'>M20SV30</a></li> <li><a href="../whatsminer/M2X#m21s_1-v20">M21S+ V20</a></li>
</ul> <li><a href="../whatsminer/M2X#m29-v10">M29 V10</a></li>
</details> </ul>
<details>
<summary><a href='../whatsminer/M2X/#M20S_1'>M20S+</a></summary>
<ul>
<li><a href='../whatsminer/M2X/#M20S_1V30'>M20S+V30</a></li>
</ul>
</details>
<details>
<summary><a href='../whatsminer/M2X/#M21'>M21</a></summary>
<ul>
<li><a href='../whatsminer/M2X/#M21V10'>M21V10</a></li>
</ul>
</details>
<details>
<summary><a href='../whatsminer/M2X/#M21S'>M21S</a></summary>
<ul>
<li><a href='../whatsminer/M2X/#M21SV20'>M21SV20</a></li>
<li><a href='../whatsminer/M2X/#M21SV60'>M21SV60</a></li>
<li><a href='../whatsminer/M2X/#M21SV70'>M21SV70</a></li>
</ul>
</details>
<details>
<summary><a href='../whatsminer/M2X/#M21S_1'>M21S+</a></summary>
<ul>
<li><a href='../whatsminer/M2X/#M21S_1V20'>M21S+V20</a></li>
</ul>
</details>
<details>
<summary><a href='../whatsminer/M2X/#M29'>M29</a></summary>
<ul>
<li><a href='../whatsminer/M2X/#M29V10'>M29V10</a></li>
</ul>
</details>
</ul>
</details> </details>
<details> <details>
<summary>M3X Series:</summary> <summary>M3X Series:</summary>
<ul> <ul>
<details> <li><a href="../whatsminer/M3X#m30-v10">M30 V10</a></li>
<summary><a href='../whatsminer/M3X/#M30'>M30</a></summary> <li><a href="../whatsminer/M3X#m30-v20">M30 V20</a></li>
<ul> <li><a href="../whatsminer/M3X#m30k-v10">M30K V10</a></li>
<li><a href='../whatsminer/M3X/#M30V10'>M30V10</a></li> <li><a href="../whatsminer/M3X#m30l-v10">M30L V10</a></li>
<li><a href='../whatsminer/M3X/#M30V20'>M30V20</a></li> <li><a href="../whatsminer/M3X#m30s-v10">M30S V10</a></li>
</ul> <li><a href="../whatsminer/M3X#m30s-v20">M30S V20</a></li>
</details> <li><a href="../whatsminer/M3X#m30s-v30">M30S V30</a></li>
<details> <li><a href="../whatsminer/M3X#m30s-v40">M30S V40</a></li>
<summary><a href='../whatsminer/M3X/#M30S'>M30S</a></summary> <li><a href="../whatsminer/M3X#m30s-v50">M30S V50</a></li>
<ul> <li><a href="../whatsminer/M3X#m30s-v60">M30S V60</a></li>
<li><a href='../whatsminer/M3X/#M30SV10'>M30SV10</a></li> <li><a href="../whatsminer/M3X#m30s-v70">M30S V70</a></li>
<li><a href='../whatsminer/M3X/#M30SV20'>M30SV20</a></li> <li><a href="../whatsminer/M3X#m30s-v80">M30S V80</a></li>
<li><a href='../whatsminer/M3X/#M30SV30'>M30SV30</a></li> <li><a href="../whatsminer/M3X#m30s-ve10">M30S VE10</a></li>
<li><a href='../whatsminer/M3X/#M30SV40'>M30SV40</a></li> <li><a href="../whatsminer/M3X#m30s-ve20">M30S VE20</a></li>
<li><a href='../whatsminer/M3X/#M30SV50'>M30SV50</a></li> <li><a href="../whatsminer/M3X#m30s-ve30">M30S VE30</a></li>
<li><a href='../whatsminer/M3X/#M30SV60'>M30SV60</a></li> <li><a href="../whatsminer/M3X#m30s-ve40">M30S VE40</a></li>
<li><a href='../whatsminer/M3X/#M30SV70'>M30SV70</a></li> <li><a href="../whatsminer/M3X#m30s-ve50">M30S VE50</a></li>
<li><a href='../whatsminer/M3X/#M30SV80'>M30SV80</a></li> <li><a href="../whatsminer/M3X#m30s-ve60">M30S VE60</a></li>
<li><a href='../whatsminer/M3X/#M30SVE10'>M30SVE10</a></li> <li><a href="../whatsminer/M3X#m30s-ve70">M30S VE70</a></li>
<li><a href='../whatsminer/M3X/#M30SVE20'>M30SVE20</a></li> <li><a href="../whatsminer/M3X#m30s-vf10">M30S VF10</a></li>
<li><a href='../whatsminer/M3X/#M30SVE30'>M30SVE30</a></li> <li><a href="../whatsminer/M3X#m30s-vf20">M30S VF20</a></li>
<li><a href='../whatsminer/M3X/#M30SVE40'>M30SVE40</a></li> <li><a href="../whatsminer/M3X#m30s-vf30">M30S VF30</a></li>
<li><a href='../whatsminer/M3X/#M30SVE50'>M30SVE50</a></li> <li><a href="../whatsminer/M3X#m30s-vg10">M30S VG10</a></li>
<li><a href='../whatsminer/M3X/#M30SVE60'>M30SVE60</a></li> <li><a href="../whatsminer/M3X#m30s-vg20">M30S VG20</a></li>
<li><a href='../whatsminer/M3X/#M30SVE70'>M30SVE70</a></li> <li><a href="../whatsminer/M3X#m30s-vg30">M30S VG30</a></li>
<li><a href='../whatsminer/M3X/#M30SVF10'>M30SVF10</a></li> <li><a href="../whatsminer/M3X#m30s-vg40">M30S VG40</a></li>
<li><a href='../whatsminer/M3X/#M30SVF20'>M30SVF20</a></li> <li><a href="../whatsminer/M3X#m30s-vh10">M30S VH10</a></li>
<li><a href='../whatsminer/M3X/#M30SVF30'>M30SVF30</a></li> <li><a href="../whatsminer/M3X#m30s-vh20">M30S VH20</a></li>
<li><a href='../whatsminer/M3X/#M30SVG10'>M30SVG10</a></li> <li><a href="../whatsminer/M3X#m30s-vh30">M30S VH30</a></li>
<li><a href='../whatsminer/M3X/#M30SVG20'>M30SVG20</a></li> <li><a href="../whatsminer/M3X#m30s-vh40">M30S VH40</a></li>
<li><a href='../whatsminer/M3X/#M30SVG30'>M30SVG30</a></li> <li><a href="../whatsminer/M3X#m30s-vh50">M30S VH50</a></li>
<li><a href='../whatsminer/M3X/#M30SVG40'>M30SVG40</a></li> <li><a href="../whatsminer/M3X#m30s-vh60">M30S VH60</a></li>
<li><a href='../whatsminer/M3X/#M30SVH10'>M30SVH10</a></li> <li><a href="../whatsminer/M3X#m30s-vi20">M30S VI20</a></li>
<li><a href='../whatsminer/M3X/#M30SVH20'>M30SVH20</a></li> <li><a href="../whatsminer/M3X#m30s_1-v10">M30S+ V10</a></li>
<li><a href='../whatsminer/M3X/#M30SVH30'>M30SVH30</a></li> <li><a href="../whatsminer/M3X#m30s_1-v20">M30S+ V20</a></li>
<li><a href='../whatsminer/M3X/#M30SVH40'>M30SVH40</a></li> <li><a href="../whatsminer/M3X#m30s_1-v30">M30S+ V30</a></li>
<li><a href='../whatsminer/M3X/#M30SVH50'>M30SVH50</a></li> <li><a href="../whatsminer/M3X#m30s_1-v40">M30S+ V40</a></li>
<li><a href='../whatsminer/M3X/#M30SVH60'>M30SVH60</a></li> <li><a href="../whatsminer/M3X#m30s_1-v50">M30S+ V50</a></li>
<li><a href='../whatsminer/M3X/#M30SVI20'>M30SVI20</a></li> <li><a href="../whatsminer/M3X#m30s_1-v60">M30S+ V60</a></li>
</ul> <li><a href="../whatsminer/M3X#m30s_1-v70">M30S+ V70</a></li>
</details> <li><a href="../whatsminer/M3X#m30s_1-v80">M30S+ V80</a></li>
<details> <li><a href="../whatsminer/M3X#m30s_1-v90">M30S+ V90</a></li>
<summary><a href='../whatsminer/M3X/#M30S_1'>M30S+</a></summary> <li><a href="../whatsminer/M3X#m30s_1-v100">M30S+ V100</a></li>
<ul> <li><a href="../whatsminer/M3X#m30s_1-ve30">M30S+ VE30</a></li>
<li><a href='../whatsminer/M3X/#M30S_1V10'>M30S+V10</a></li> <li><a href="../whatsminer/M3X#m30s_1-ve40">M30S+ VE40</a></li>
<li><a href='../whatsminer/M3X/#M30S_1V20'>M30S+V20</a></li> <li><a href="../whatsminer/M3X#m30s_1-ve50">M30S+ VE50</a></li>
<li><a href='../whatsminer/M3X/#M30S_1V30'>M30S+V30</a></li> <li><a href="../whatsminer/M3X#m30s_1-ve60">M30S+ VE60</a></li>
<li><a href='../whatsminer/M3X/#M30S_1V40'>M30S+V40</a></li> <li><a href="../whatsminer/M3X#m30s_1-ve70">M30S+ VE70</a></li>
<li><a href='../whatsminer/M3X/#M30S_1V50'>M30S+V50</a></li> <li><a href="../whatsminer/M3X#m30s_1-ve80">M30S+ VE80</a></li>
<li><a href='../whatsminer/M3X/#M30S_1V60'>M30S+V60</a></li> <li><a href="../whatsminer/M3X#m30s_1-ve90">M30S+ VE90</a></li>
<li><a href='../whatsminer/M3X/#M30S_1V70'>M30S+V70</a></li> <li><a href="../whatsminer/M3X#m30s_1-ve100">M30S+ VE100</a></li>
<li><a href='../whatsminer/M3X/#M30S_1V80'>M30S+V80</a></li> <li><a href="../whatsminer/M3X#m30s_1-vf20">M30S+ VF20</a></li>
<li><a href='../whatsminer/M3X/#M30S_1V90'>M30S+V90</a></li> <li><a href="../whatsminer/M3X#m30s_1-vf30">M30S+ VF30</a></li>
<li><a href='../whatsminer/M3X/#M30S_1V100'>M30S+V100</a></li> <li><a href="../whatsminer/M3X#m30s_1-vg20">M30S+ VG20</a></li>
<li><a href='../whatsminer/M3X/#M30S_1VE30'>M30S+VE30</a></li> <li><a href="../whatsminer/M3X#m30s_1-vg30">M30S+ VG30</a></li>
<li><a href='../whatsminer/M3X/#M30S_1VE40'>M30S+VE40</a></li> <li><a href="../whatsminer/M3X#m30s_1-vg40">M30S+ VG40</a></li>
<li><a href='../whatsminer/M3X/#M30S_1VE50'>M30S+VE50</a></li> <li><a href="../whatsminer/M3X#m30s_1-vg50">M30S+ VG50</a></li>
<li><a href='../whatsminer/M3X/#M30S_1VE60'>M30S+VE60</a></li> <li><a href="../whatsminer/M3X#m30s_1-vg60">M30S+ VG60</a></li>
<li><a href='../whatsminer/M3X/#M30S_1VE70'>M30S+VE70</a></li> <li><a href="../whatsminer/M3X#m30s_1-vh10">M30S+ VH10</a></li>
<li><a href='../whatsminer/M3X/#M30S_1VE80'>M30S+VE80</a></li> <li><a href="../whatsminer/M3X#m30s_1-vh20">M30S+ VH20</a></li>
<li><a href='../whatsminer/M3X/#M30S_1VE90'>M30S+VE90</a></li> <li><a href="../whatsminer/M3X#m30s_1-vh30">M30S+ VH30</a></li>
<li><a href='../whatsminer/M3X/#M30S_1VE100'>M30S+VE100</a></li> <li><a href="../whatsminer/M3X#m30s_1-vh40">M30S+ VH40</a></li>
<li><a href='../whatsminer/M3X/#M30S_1VF20'>M30S+VF20</a></li> <li><a href="../whatsminer/M3X#m30s_1-vh50">M30S+ VH50</a></li>
<li><a href='../whatsminer/M3X/#M30S_1VF30'>M30S+VF30</a></li> <li><a href="../whatsminer/M3X#m30s_1-vh60">M30S+ VH60</a></li>
<li><a href='../whatsminer/M3X/#M36S_1VG30'>M36S+VG30</a></li> <li><a href="../whatsminer/M3X#m30s_1_1-v10">M30S++ V10</a></li>
<li><a href='../whatsminer/M3X/#M30S_1VG30'>M30S+VG30</a></li> <li><a href="../whatsminer/M3X#m30s_1_1-v20">M30S++ V20</a></li>
<li><a href='../whatsminer/M3X/#M30S_1VG40'>M30S+VG40</a></li> <li><a href="../whatsminer/M3X#m30s_1_1-ve30">M30S++ VE30</a></li>
<li><a href='../whatsminer/M3X/#M30S_1VG50'>M30S+VG50</a></li> <li><a href="../whatsminer/M3X#m30s_1_1-ve40">M30S++ VE40</a></li>
<li><a href='../whatsminer/M3X/#M30S_1VG60'>M30S+VG60</a></li> <li><a href="../whatsminer/M3X#m30s_1_1-ve50">M30S++ VE50</a></li>
<li><a href='../whatsminer/M3X/#M30S_1VH10'>M30S+VH10</a></li> <li><a href="../whatsminer/M3X#m30s_1_1-vf40">M30S++ VF40</a></li>
<li><a href='../whatsminer/M3X/#M30S_1VH20'>M30S+VH20</a></li> <li><a href="../whatsminer/M3X#m30s_1_1-vg30">M30S++ VG30</a></li>
<li><a href='../whatsminer/M3X/#M30S_1VH30'>M30S+VH30</a></li> <li><a href="../whatsminer/M3X#m30s_1_1-vg40">M30S++ VG40</a></li>
<li><a href='../whatsminer/M3X/#M30S_1VH40'>M30S+VH40</a></li> <li><a href="../whatsminer/M3X#m30s_1_1-vg50">M30S++ VG50</a></li>
<li><a href='../whatsminer/M3X/#M30S_1VH50'>M30S+VH50</a></li> <li><a href="../whatsminer/M3X#m30s_1_1-vh10">M30S++ VH10</a></li>
<li><a href='../whatsminer/M3X/#M30S_1VH60'>M30S+VH60</a></li> <li><a href="../whatsminer/M3X#m30s_1_1-vh20">M30S++ VH20</a></li>
</ul> <li><a href="../whatsminer/M3X#m30s_1_1-vh30">M30S++ VH30</a></li>
</details> <li><a href="../whatsminer/M3X#m30s_1_1-vh40">M30S++ VH40</a></li>
<details> <li><a href="../whatsminer/M3X#m30s_1_1-vh50">M30S++ VH50</a></li>
<summary><a href='../whatsminer/M3X/#M30S_2'>M30S++</a></summary> <li><a href="../whatsminer/M3X#m30s_1_1-vh60">M30S++ VH60</a></li>
<ul> <li><a href="../whatsminer/M3X#m30s_1_1-vh70">M30S++ VH70</a></li>
<li><a href='../whatsminer/M3X/#M30S_2V10'>M30S++V10</a></li> <li><a href="../whatsminer/M3X#m30s_1_1-vh80">M30S++ VH80</a></li>
<li><a href='../whatsminer/M3X/#M30S_2V20'>M30S++V20</a></li> <li><a href="../whatsminer/M3X#m30s_1_1-vh90">M30S++ VH90</a></li>
<li><a href='../whatsminer/M3X/#M30S_2VE30'>M30S++VE30</a></li> <li><a href="../whatsminer/M3X#m30s_1_1-vh100">M30S++ VH100</a></li>
<li><a href='../whatsminer/M3X/#M30S_2VE40'>M30S++VE40</a></li> <li><a href="../whatsminer/M3X#m30s_1_1-vj20">M30S++ VJ20</a></li>
<li><a href='../whatsminer/M3X/#M30S_2VE50'>M30S++VE50</a></li> <li><a href="../whatsminer/M3X#m30s_1_1-vj30">M30S++ VJ30</a></li>
<li><a href='../whatsminer/M3X/#M30S_2VF40'>M30S++VF40</a></li> <li><a href="../whatsminer/M3X#m31-v10">M31 V10</a></li>
<li><a href='../whatsminer/M3X/#M30S_2VG30'>M30S++VG30</a></li> <li><a href="../whatsminer/M3X#m31-v20">M31 V20</a></li>
<li><a href='../whatsminer/M3X/#M30S_2VG40'>M30S++VG40</a></li> <li><a href="../whatsminer/M3X#m31h-v10">M31H V10</a></li>
<li><a href='../whatsminer/M3X/#M30S_2VG50'>M30S++VG50</a></li> <li><a href="../whatsminer/M3X#m31h-v40">M31H V40</a></li>
<li><a href='../whatsminer/M3X/#M30S_2VH10'>M30S++VH10</a></li> <li><a href="../whatsminer/M3X#m30l-v10">M30L V10</a></li>
<li><a href='../whatsminer/M3X/#M30S_2VH20'>M30S++VH20</a></li> <li><a href="../whatsminer/M3X#m31s-v10">M31S V10</a></li>
<li><a href='../whatsminer/M3X/#M30S_2VH30'>M30S++VH30</a></li> <li><a href="../whatsminer/M3X#m31s-v20">M31S V20</a></li>
<li><a href='../whatsminer/M3X/#M30S_2VH40'>M30S++VH40</a></li> <li><a href="../whatsminer/M3X#m31s-v30">M31S V30</a></li>
<li><a href='../whatsminer/M3X/#M30S_2VH50'>M30S++VH50</a></li> <li><a href="../whatsminer/M3X#m31s-v40">M31S V40</a></li>
<li><a href='../whatsminer/M3X/#M30S_2VH60'>M30S++VH60</a></li> <li><a href="../whatsminer/M3X#m31s-v50">M31S V50</a></li>
<li><a href='../whatsminer/M3X/#M30S_2VH70'>M30S++VH70</a></li> <li><a href="../whatsminer/M3X#m31s-v60">M31S V60</a></li>
<li><a href='../whatsminer/M3X/#M30S_2VH80'>M30S++VH80</a></li> <li><a href="../whatsminer/M3X#m31s-v70">M31S V70</a></li>
<li><a href='../whatsminer/M3X/#M30S_2VH90'>M30S++VH90</a></li> <li><a href="../whatsminer/M3X#m31s-v80">M31S V80</a></li>
<li><a href='../whatsminer/M3X/#M30S_2VH100'>M30S++VH100</a></li> <li><a href="../whatsminer/M3X#m31s-v90">M31S V90</a></li>
<li><a href='../whatsminer/M3X/#M30S_2VJ20'>M30S++VJ20</a></li> <li><a href="../whatsminer/M3X#m31s-ve10">M31S VE10</a></li>
<li><a href='../whatsminer/M3X/#M30S_2VJ30'>M30S++VJ30</a></li> <li><a href="../whatsminer/M3X#m31s-ve20">M31S VE20</a></li>
</ul> <li><a href="../whatsminer/M3X#m31s-ve30">M31S VE30</a></li>
</details> <li><a href="../whatsminer/M3X#m31se-v10">M31SE V10</a></li>
<details> <li><a href="../whatsminer/M3X#m31se-v20">M31SE V20</a></li>
<summary><a href='../whatsminer/M3X/#M31'>M31</a></summary> <li><a href="../whatsminer/M3X#m31se-v30">M31SE V30</a></li>
<ul> <li><a href="../whatsminer/M3X#m31s_1-v10">M31S+ V10</a></li>
<li><a href='../whatsminer/M3X/#M31V10'>M31V10</a></li> <li><a href="../whatsminer/M3X#m31s_1-v20">M31S+ V20</a></li>
<li><a href='../whatsminer/M3X/#M31V20'>M31V20</a></li> <li><a href="../whatsminer/M3X#m31s_1-v30">M31S+ V30</a></li>
</ul> <li><a href="../whatsminer/M3X#m31s_1-v40">M31S+ V40</a></li>
</details> <li><a href="../whatsminer/M3X#m31s_1-v50">M31S+ V50</a></li>
<details> <li><a href="../whatsminer/M3X#m31s_1-v60">M31S+ V60</a></li>
<summary><a href='../whatsminer/M3X/#M31S'>M31S</a></summary> <li><a href="../whatsminer/M3X#m31s_1-v80">M31S+ V80</a></li>
<ul> <li><a href="../whatsminer/M3X#m31s_1-v90">M31S+ V90</a></li>
<li><a href='../whatsminer/M3X/#M31SV10'>M31SV10</a></li> <li><a href="../whatsminer/M3X#m31s_1-v100">M31S+ V100</a></li>
<li><a href='../whatsminer/M3X/#M31SV20'>M31SV20</a></li> <li><a href="../whatsminer/M3X#m31s_1-ve10">M31S+ VE10</a></li>
<li><a href='../whatsminer/M3X/#M31SV30'>M31SV30</a></li> <li><a href="../whatsminer/M3X#m31s_1-ve20">M31S+ VE20</a></li>
<li><a href='../whatsminer/M3X/#M31SV40'>M31SV40</a></li> <li><a href="../whatsminer/M3X#m31s_1-ve30">M31S+ VE30</a></li>
<li><a href='../whatsminer/M3X/#M31SV50'>M31SV50</a></li> <li><a href="../whatsminer/M3X#m31s_1-ve40">M31S+ VE40</a></li>
<li><a href='../whatsminer/M3X/#M31SV60'>M31SV60</a></li> <li><a href="../whatsminer/M3X#m31s_1-ve50">M31S+ VE50</a></li>
<li><a href='../whatsminer/M3X/#M31SV70'>M31SV70</a></li> <li><a href="../whatsminer/M3X#m31s_1-ve60">M31S+ VE60</a></li>
<li><a href='../whatsminer/M3X/#M31SV80'>M31SV80</a></li> <li><a href="../whatsminer/M3X#m31s_1-ve80">M31S+ VE80</a></li>
<li><a href='../whatsminer/M3X/#M31SV90'>M31SV90</a></li> <li><a href="../whatsminer/M3X#m31s_1-vf20">M31S+ VF20</a></li>
<li><a href='../whatsminer/M3X/#M31SVE10'>M31SVE10</a></li> <li><a href="../whatsminer/M3X#m31s_1-vf30">M31S+ VF30</a></li>
<li><a href='../whatsminer/M3X/#M31SVE20'>M31SVE20</a></li> <li><a href="../whatsminer/M3X#m31s_1-vg20">M31S+ VG20</a></li>
<li><a href='../whatsminer/M3X/#M31SVE30'>M31SVE30</a></li> <li><a href="../whatsminer/M3X#m31s_1-vg30">M31S+ VG30</a></li>
</ul> <li><a href="../whatsminer/M3X#m32-v10">M32 V10</a></li>
</details> <li><a href="../whatsminer/M3X#m32-v20">M32 V20</a></li>
<details> <li><a href="../whatsminer/M3X#m33-v10">M33 V10</a></li>
<summary><a href='../whatsminer/M3X/#M31SE'>M31SE</a></summary> <li><a href="../whatsminer/M3X#m33-v20">M33 V20</a></li>
<ul> <li><a href="../whatsminer/M3X#m33-v30">M33 V30</a></li>
<li><a href='../whatsminer/M3X/#M31SEV10'>M31SEV10</a></li> <li><a href="../whatsminer/M3X#m33s-vg30">M33S VG30</a></li>
<li><a href='../whatsminer/M3X/#M31SEV20'>M31SEV20</a></li> <li><a href="../whatsminer/M3X#m33s_1-vg20">M33S+ VG20</a></li>
<li><a href='../whatsminer/M3X/#M31SEV30'>M31SEV30</a></li> <li><a href="../whatsminer/M3X#m33s_1-vh20">M33S+ VH20</a></li>
</ul> <li><a href="../whatsminer/M3X#m33s_1-vh30">M33S+ VH30</a></li>
</details> <li><a href="../whatsminer/M3X#m33s_1_1-vh20">M33S++ VH20</a></li>
<details> <li><a href="../whatsminer/M3X#m33s_1_1-vh30">M33S++ VH30</a></li>
<summary><a href='../whatsminer/M3X/#M31H'>M31H</a></summary> <li><a href="../whatsminer/M3X#m33s_1_1-vg40">M33S++ VG40</a></li>
<ul> <li><a href="../whatsminer/M3X#m34s_1-ve10">M34S+ VE10</a></li>
<li><a href='../whatsminer/M3X/#M31HV40'>M31HV40</a></li> <li><a href="../whatsminer/M3X#m36s-ve10">M36S VE10</a></li>
</ul> <li><a href="../whatsminer/M3X#m36s_1-vg30">M36S+ VG30</a></li>
</details> <li><a href="../whatsminer/M3X#m36s_1_1-vh30">M36S++ VH30</a></li>
<details> <li><a href="../whatsminer/M3X#m39-v10">M39 V10</a></li>
<summary><a href='../whatsminer/M3X/#M31S_1'>M31S+</a></summary> <li><a href="../whatsminer/M3X#m39-v20">M39 V20</a></li>
<ul> <li><a href="../whatsminer/M3X#m39-v30">M39 V30</a></li>
<li><a href='../whatsminer/M3X/#M31S_1V10'>M31S+V10</a></li> </ul>
<li><a href='../whatsminer/M3X/#M31S_1V20'>M31S+V20</a></li>
<li><a href='../whatsminer/M3X/#M31S_1V30'>M31S+V30</a></li>
<li><a href='../whatsminer/M3X/#M31S_1V40'>M31S+V40</a></li>
<li><a href='../whatsminer/M3X/#M31S_1V50'>M31S+V50</a></li>
<li><a href='../whatsminer/M3X/#M31S_1V60'>M31S+V60</a></li>
<li><a href='../whatsminer/M3X/#M31S_1V80'>M31S+V80</a></li>
<li><a href='../whatsminer/M3X/#M31S_1V90'>M31S+V90</a></li>
<li><a href='../whatsminer/M3X/#M31S_1V100'>M31S+V100</a></li>
<li><a href='../whatsminer/M3X/#M31S_1VE10'>M31S+VE10</a></li>
<li><a href='../whatsminer/M3X/#M31S_1VE20'>M31S+VE20</a></li>
<li><a href='../whatsminer/M3X/#M31S_1VE30'>M31S+VE30</a></li>
<li><a href='../whatsminer/M3X/#M31S_1VE40'>M31S+VE40</a></li>
<li><a href='../whatsminer/M3X/#M31S_1VE50'>M31S+VE50</a></li>
<li><a href='../whatsminer/M3X/#M31S_1VE60'>M31S+VE60</a></li>
<li><a href='../whatsminer/M3X/#M31S_1VE80'>M31S+VE80</a></li>
<li><a href='../whatsminer/M3X/#M31S_1VF20'>M31S+VF20</a></li>
<li><a href='../whatsminer/M3X/#M31S_1VF30'>M31S+VF30</a></li>
<li><a href='../whatsminer/M3X/#M31S_1VG20'>M31S+VG20</a></li>
<li><a href='../whatsminer/M3X/#M31S_1VG30'>M31S+VG30</a></li>
</ul>
</details>
<details>
<summary><a href='../whatsminer/M3X/#M32'>M32</a></summary>
<ul>
<li><a href='../whatsminer/M3X/#M32V10'>M32V10</a></li>
<li><a href='../whatsminer/M3X/#M32V20'>M32V20</a></li>
</ul>
</details>
<details>
<summary><a href='../whatsminer/M3X/#M33'>M33</a></summary>
<ul>
<li><a href='../whatsminer/M3X/#M33V10'>M33V10</a></li>
<li><a href='../whatsminer/M3X/#M33V20'>M33V20</a></li>
<li><a href='../whatsminer/M3X/#M33V30'>M33V30</a></li>
</ul>
</details>
<details>
<summary><a href='../whatsminer/M3X/#M33S'>M33S</a></summary>
<ul>
<li><a href='../whatsminer/M3X/#M33SVG30'>M33SVG30</a></li>
</ul>
</details>
<details>
<summary><a href='../whatsminer/M3X/#M33S_1'>M33S+</a></summary>
<ul>
<li><a href='../whatsminer/M3X/#M33S_1VH20'>M33S+VH20</a></li>
<li><a href='../whatsminer/M3X/#M33S_1VH30'>M33S+VH30</a></li>
</ul>
</details>
<details>
<summary><a href='../whatsminer/M3X/#M33S_2'>M33S++</a></summary>
<ul>
<li><a href='../whatsminer/M3X/#M33S_2VH20'>M33S++VH20</a></li>
<li><a href='../whatsminer/M3X/#M33S_2VH30'>M33S++VH30</a></li>
<li><a href='../whatsminer/M3X/#M33S_2VG40'>M33S++VG40</a></li>
</ul>
</details>
<details>
<summary><a href='../whatsminer/M3X/#M34S_1'>M34S+</a></summary>
<ul>
<li><a href='../whatsminer/M3X/#M34S_1VE10'>M34S+VE10</a></li>
</ul>
</details>
<details>
<summary><a href='../whatsminer/M3X/#M36S'>M36S</a></summary>
<ul>
<li><a href='../whatsminer/M3X/#M36SVE10'>M36SVE10</a></li>
</ul>
</details>
<details>
<summary><a href='../whatsminer/M3X/#M36S_1'>M36S+</a></summary>
<ul>
<li><a href='../whatsminer/M3X/#M36S_1VG30'>M36S+VG30</a></li>
</ul>
</details>
<details>
<summary><a href='../whatsminer/M3X/#M36S_2'>M36S++</a></summary>
<ul>
<li><a href='../whatsminer/M3X/#M36S_2VH30'>M36S++VH30</a></li>
</ul>
</details>
<details>
<summary><a href='../whatsminer/M3X/#M39'>M39</a></summary>
<ul>
<li><a href='../whatsminer/M3X/#M39V20'>M39V20</a></li>
</ul>
</details>
</ul>
</details> </details>
<details> <details>
<summary>M5X Series:</summary> <summary>M5X Series:</summary>
<ul> <ul>
<details> <li><a href="../whatsminer/M5X#m50-ve30">M50 VE30</a></li>
<summary><a href='../whatsminer/M5X/#M50'>M50</a></summary> <li><a href="../whatsminer/M5X#m50-vg30">M50 VG30</a></li>
<ul> <li><a href="../whatsminer/M5X#m50-vh10">M50 VH10</a></li>
<li><a href='../whatsminer/M5X/#M50VG30'>M50VG30</a></li> <li><a href="../whatsminer/M5X#m50-vh20">M50 VH20</a></li>
<li><a href='../whatsminer/M5X/#M50VH10'>M50VH10</a></li> <li><a href="../whatsminer/M5X#m50-vh30">M50 VH30</a></li>
<li><a href='../whatsminer/M5X/#M50VH20'>M50VH20</a></li> <li><a href="../whatsminer/M5X#m50-vh40">M50 VH40</a></li>
<li><a href='../whatsminer/M5X/#M50VH30'>M50VH30</a></li> <li><a href="../whatsminer/M5X#m50-vh50">M50 VH50</a></li>
<li><a href='../whatsminer/M5X/#M50VH40'>M50VH40</a></li> <li><a href="../whatsminer/M5X#m50-vh60">M50 VH60</a></li>
<li><a href='../whatsminer/M5X/#M50VH50'>M50VH50</a></li> <li><a href="../whatsminer/M5X#m50-vh70">M50 VH70</a></li>
<li><a href='../whatsminer/M5X/#M50VH60'>M50VH60</a></li> <li><a href="../whatsminer/M5X#m50-vh80">M50 VH80</a></li>
<li><a href='../whatsminer/M5X/#M50VH70'>M50VH70</a></li> <li><a href="../whatsminer/M5X#m50-vj10">M50 VJ10</a></li>
<li><a href='../whatsminer/M5X/#M50VH80'>M50VH80</a></li> <li><a href="../whatsminer/M5X#m50-vj20">M50 VJ20</a></li>
<li><a href='../whatsminer/M5X/#M50VJ10'>M50VJ10</a></li> <li><a href="../whatsminer/M5X#m50-vj30">M50 VJ30</a></li>
<li><a href='../whatsminer/M5X/#M50VJ20'>M50VJ20</a></li> <li><a href="../whatsminer/M5X#m50s-vj10">M50S VJ10</a></li>
<li><a href='../whatsminer/M5X/#M50VJ30'>M50VJ30</a></li> <li><a href="../whatsminer/M5X#m50s-vj20">M50S VJ20</a></li>
</ul> <li><a href="../whatsminer/M5X#m50s-vj30">M50S VJ30</a></li>
</details> <li><a href="../whatsminer/M5X#m50s-vh10">M50S VH10</a></li>
<details> <li><a href="../whatsminer/M5X#m50s-vh20">M50S VH20</a></li>
<summary><a href='../whatsminer/M5X/#M50S'>M50S</a></summary> <li><a href="../whatsminer/M5X#m50s-vh30">M50S VH30</a></li>
<ul> <li><a href="../whatsminer/M5X#m50s-vh40">M50S VH40</a></li>
<li><a href='../whatsminer/M5X/#M50SVJ10'>M50SVJ10</a></li> <li><a href="../whatsminer/M5X#m50s-vh50">M50S VH50</a></li>
<li><a href='../whatsminer/M5X/#M50SVJ20'>M50SVJ20</a></li> <li><a href="../whatsminer/M5X#m50s_1-vh30">M50S+ VH30</a></li>
<li><a href='../whatsminer/M5X/#M50SVJ30'>M50SVJ30</a></li> <li><a href="../whatsminer/M5X#m50s_1-vh40">M50S+ VH40</a></li>
<li><a href='../whatsminer/M5X/#M50SVH10'>M50SVH10</a></li> <li><a href="../whatsminer/M5X#m50s_1-vj30">M50S+ VJ30</a></li>
<li><a href='../whatsminer/M5X/#M50SVH20'>M50SVH20</a></li> <li><a href="../whatsminer/M5X#m50s_1-vk20">M50S+ VK20</a></li>
<li><a href='../whatsminer/M5X/#M50SVH30'>M50SVH30</a></li> <li><a href="../whatsminer/M5X#m50s_1_1-vk10">M50S++ VK10</a></li>
<li><a href='../whatsminer/M5X/#M50SVH40'>M50SVH40</a></li> <li><a href="../whatsminer/M5X#m50s_1_1-vk20">M50S++ VK20</a></li>
<li><a href='../whatsminer/M5X/#M50SVH50'>M50SVH50</a></li> <li><a href="../whatsminer/M5X#m50s_1_1-vk30">M50S++ VK30</a></li>
</ul> <li><a href="../whatsminer/M5X#m53-vh30">M53 VH30</a></li>
</details> <li><a href="../whatsminer/M5X#m53s-vh30">M53S VH30</a></li>
<details> <li><a href="../whatsminer/M5X#m53s_1-vj30">M53S+ VJ30</a></li>
<summary><a href='../whatsminer/M5X/#M50S_1'>M50S+</a></summary> <li><a href="../whatsminer/M5X#m56-vh30">M56 VH30</a></li>
<ul> <li><a href="../whatsminer/M5X#m56s-vh30">M56S VH30</a></li>
<li><a href='../whatsminer/M5X/#M50S_1VH30'>M50S+VH30</a></li> <li><a href="../whatsminer/M5X#m56s_1-vj30">M56S+ VJ30</a></li>
<li><a href='../whatsminer/M5X/#M50S_1VH40'>M50S+VH40</a></li> <li><a href="../whatsminer/M5X#m59-vh30">M59 VH30</a></li>
<li><a href='../whatsminer/M5X/#M50S_1VJ30'>M50S+VJ30</a></li> </ul>
</ul>
</details>
<details>
<summary><a href='../whatsminer/M5X/#M53'>M53</a></summary>
<ul>
<li><a href='../whatsminer/M5X/#M53VH30'>M53VH30</a></li>
</ul>
</details>
<details>
<summary><a href='../whatsminer/M5X/#M53S'>M53S</a></summary>
<ul>
<li><a href='../whatsminer/M5X/#M53SVH30'>M53SVH30</a></li>
</ul>
</details>
<details>
<summary><a href='../whatsminer/M5X/#M53S_1'>M53S+</a></summary>
<ul>
<li><a href='../whatsminer/M5X/#M53S_1VJ30'>M53S+VJ30</a></li>
</ul>
</details>
<details>
<summary><a href='../whatsminer/M5X/#M56'>M56</a></summary>
<ul>
<li><a href='../whatsminer/M5X/#M56VH30'>M56VH30</a></li>
</ul>
</details>
<details>
<summary><a href='../whatsminer/M5X/#M56S'>M56S</a></summary>
<ul>
<li><a href='../whatsminer/M5X/#M56SVH30'>M56SVH30</a></li>
</ul>
</details>
<details>
<summary><a href='../whatsminer/M5X/#M56S_1'>M56S+</a></summary>
<ul>
<li><a href='../whatsminer/M5X/#M56S_1VJ30'>M56S+VJ30</a></li>
</ul>
</details>
<details>
<summary><a href='../whatsminer/M5X/#M59'>M59</a></summary>
<ul>
<li><a href='../whatsminer/M5X/#M59VH30'>M59VH30</a></li>
</ul>
</details>
</ul>
</details>
</ul>
</details>
<details>
<summary>Stock Firmware Antminers:</summary>
<ul>
<details>
<summary>X19 Series:</summary>
<ul>
<li><a href="../antminer/X19/#s19">S19</a></li>
<li><a href="../antminer/X19/#s19l">S19L</a></li>
<li><a href="../antminer/X19/#s19-pro">S19 Pro</a></li>
<li><a href="../antminer/X19/#s19a">S19a</a></li>
<li><a href="../antminer/X19/#s19j">S19j</a></li>
<li><a href="../antminer/X19/#s19j-pro">S19j Pro</a></li>
<li><a href="../antminer/X19/#s19-xp">S19 XP</a></li>
<li><a href="../antminer/X19/#t19">T19</a></li>
</ul>
</details>
<details>
<summary>X17 Series:</summary>
<ul>
<li><a href="../antminer/X17/#s17">S17</a></li>
<li><a href="../antminer/X17/#s17_1">S17+</a></li>
<li><a href="../antminer/X17/#s17-pro">S17 Pro</a></li>
<li><a href="../antminer/X17/#s17e">S17e</a></li>
<li><a href="../antminer/X17/#t17">T17</a></li>
<li><a href="../antminer/X17/#t17_1">T17+</a></li>
<li><a href="../antminer/X17/#t17e">T17e</a></li>
</ul>
</details>
<details>
<summary>X15 Series:</summary>
<ul>
<li><a href="../antminer/X15/#z15">Z15</a></li>
</ul>
</details>
<details>
<summary>X9 Series:</summary>
<ul>
<li><a href="../antminer/X9/#s9">S9</a></li>
<li><a href="../antminer/X9/#s9i">S9i</a></li>
<li><a href="../antminer/X9/#t9">T9</a></li>
<li><a href="../antminer/X9/#e9-pro">E9 Pro</a></li>
</ul>
</details>
<details>
<summary>X7 Series:</summary>
<ul>
<li><a href="../antminer/X7/#l7">L7</a></li>
</ul>
</details>
<details>
<summary>X5 Series:</summary>
<ul>
<li><a href="../antminer/X5/#dr5">DR5</a></li>
</ul>
</details>
<details>
<summary>X3 Series:</summary>
<ul>
<li><a href="../antminer/X3/#hs3">HS3</a></li>
</ul>
</details> </details>
</ul> </ul>
</details> </details>
@@ -492,75 +299,185 @@ details {
<summary>Stock Firmware Avalonminers:</summary> <summary>Stock Firmware Avalonminers:</summary>
<ul> <ul>
<details> <details>
<summary>A7X Series:</summary> <summary>A7X Series:</summary>
<ul> <ul>
<li><a href="../avalonminer/A7X/#a721">A721</a></li> <li><a href="../avalonminer/A7X#avalon-721">Avalon 721</a></li>
<li><a href="../avalonminer/A7X/#a741">A741</a></li> <li><a href="../avalonminer/A7X#avalon-741">Avalon 741</a></li>
<li><a href="../avalonminer/A7X/#a761">A761</a></li> <li><a href="../avalonminer/A7X#avalon-761">Avalon 761</a></li>
</ul> </ul>
</details> </details>
<details> <details>
<summary>A8X Series:</summary> <summary>A8X Series:</summary>
<ul> <ul>
<li><a href="../avalonminer/A8X/#a821">A821</a></li> <li><a href="../avalonminer/A8X#avalon-821">Avalon 821</a></li>
<li><a href="../avalonminer/A8X/#a841">A841</a></li> <li><a href="../avalonminer/A8X#avalon-841">Avalon 841</a></li>
<li><a href="../avalonminer/A8X/#a851">A851</a></li> <li><a href="../avalonminer/A8X#avalon-851">Avalon 851</a></li>
</ul> </ul>
</details> </details>
<details> <details>
<summary>A9X Series:</summary> <summary>A9X Series:</summary>
<ul> <ul>
<li><a href="../avalonminer/A9X/#a921">A921</a></li> <li><a href="../avalonminer/A9X#avalon-921">Avalon 921</a></li>
</ul> </ul>
</details> </details>
<details> <details>
<summary>A10X Series:</summary> <summary>A10X Series:</summary>
<ul> <ul>
<li><a href="../avalonminer/A10X/#a1026">A1026</a></li> <li><a href="../avalonminer/A10X#avalon-1026">Avalon 1026</a></li>
<li><a href="../avalonminer/A10X/#a1047">A1047</a></li> <li><a href="../avalonminer/A10X#avalon-1047">Avalon 1047</a></li>
<li><a href="../avalonminer/A10X/#a1066">A1066</a></li> <li><a href="../avalonminer/A10X#avalon-1066">Avalon 1066</a></li>
</ul> </ul>
</details>
<details>
<summary>A11X Series:</summary>
<ul>
<li><a href="../avalonminer/A11X#avalon-1166-pro">Avalon 1166 Pro</a></li>
</ul>
</details>
<details>
<summary>A12X Series:</summary>
<ul>
<li><a href="../avalonminer/A12X#avalon-1246">Avalon 1246</a></li>
</ul>
</details> </details>
</ul> </ul>
</details> </details>
<details> <details>
<summary>Stock Firmware Innosilicon Miners:</summary> <summary>Stock Firmware Innosilicons:</summary>
<ul> <ul>
<details> <details>
<summary>T3X Series:</summary> <summary>T3X Series:</summary>
<ul> <ul>
<li><a href="../innosilicon/T3X/#t3h">T3H+</a></li> <li><a href="../innosilicon/T3X#t3h_1">T3H+</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">A10X</a></li>
</ul> </ul>
</details> </details>
</ul> </ul>
</details> </details>
<details> <details>
<summary>Stock Firmware BFGMinerGoldshell Miners:</summary> <summary>Stock Firmware Goldshells:</summary>
<ul> <ul>
<details> <details>
<summary>CKX Series:</summary> <summary>X5 Series:</summary>
<ul> <ul>
<li><a href="../goldshell/CKX/#ck5">CK5</a></li> <li><a href="../goldshell/X5#ck5">CK5</a></li>
</ul> <li><a href="../goldshell/X5#hs5">HS5</a></li>
<li><a href="../goldshell/X5#kd5">KD5</a></li>
</ul>
</details> </details>
<details> <details>
<summary>HSX Series:</summary> <summary>XMax Series:</summary>
<ul> <ul>
<li><a href="../goldshell/HSX/#hs5">HS5</a></li> <li><a href="../goldshell/XMax#kd-max">KD Max</a></li>
</ul> </ul>
</details>
<details>
<summary>KDX Series:</summary>
<ul>
<li><a href="../goldshell/KDX/#kd5">KD5</a></li>
<li><a href="../goldshell/KDX/#kd-max">KD Max</a></li>
</ul>
</details> </details>
</ul> </ul>
</details> </details>
<details>
<summary>BOS+ Firmware Miners:</summary>
<ul>
<details>
<summary>X9 Series:</summary>
<ul>
<li><a href="../antminer/X9#s9-bos">S9 (BOS)</a></li>
</ul>
</details>
<details>
<summary>X17 Series:</summary>
<ul>
<li><a href="../antminer/X17#s17-bos">S17 (BOS)</a></li>
<li><a href="../antminer/X17#s17_1-bos">S17+ (BOS)</a></li>
<li><a href="../antminer/X17#s17-pro-bos">S17 Pro (BOS)</a></li>
<li><a href="../antminer/X17#s17e-bos">S17e (BOS)</a></li>
<li><a href="../antminer/X17#t17-bos">T17 (BOS)</a></li>
<li><a href="../antminer/X17#t17_1-bos">T17+ (BOS)</a></li>
<li><a href="../antminer/X17#t17e-bos">T17e (BOS)</a></li>
</ul>
</details>
<details>
<summary>X19 Series:</summary>
<ul>
<li><a href="../antminer/X19#s19-bos">S19 (BOS)</a></li>
<li><a href="../antminer/X19#s19-pro-bos">S19 Pro (BOS)</a></li>
<li><a href="../antminer/X19#s19j-bos">S19j (BOS)</a></li>
<li><a href="../antminer/X19#s19j-no-pic-bos">S19j No PIC (BOS)</a></li>
<li><a href="../antminer/X19#s19j-pro-bos">S19j Pro (BOS)</a></li>
<li><a href="../antminer/X19#s19j-pro-bos">S19j Pro (BOS)</a></li>
<li><a href="../antminer/X19#t19-bos">T19 (BOS)</a></li>
</ul>
</details>
</ul>
</details>
<details>
<summary>Vnish Firmware Miners:</summary>
<ul>
<details>
<summary>X3 Series:</summary>
<ul>
<li><a href="../antminer/X3#l3_1-vnish">L3+ (VNish)</a></li>
</ul>
</details>
<details>
<summary>X17 Series:</summary>
<ul>
<li><a href="../antminer/X17#s17_1-vnish">S17+ (VNish)</a></li>
<li><a href="../antminer/X17#s17-pro-vnish">S17 Pro (VNish)</a></li>
</ul>
</details>
<details>
<summary>X19 Series:</summary>
<ul>
<li><a href="../antminer/X19#s19-vnish">S19 (VNish)</a></li>
<li><a href="../antminer/X19#s19-no-pic-vnish">S19 No PIC (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-pro-vnish">S19j Pro (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#t19-vnish">T19 (VNish)</a></li>
</ul>
</details>
</ul>
</details>
<details>
<summary>ePIC Firmware Miners:</summary>
<ul>
<details>
<summary>X19 Series:</summary>
<ul>
<li><a href="../antminer/X19#s19-epic">S19 (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-pro-epic">S19j Pro (ePIC)</a></li>
<li><a href="../antminer/X19#s19-xp-epic">S19 XP (ePIC)</a></li>
</ul>
</details>
</ul>
</details>
<details>
<summary>HiveOS Firmware Miners:</summary>
<ul>
<details>
<summary>X9 Series:</summary>
<ul>
<li><a href="../antminer/X9#t9-hiveon">T9 (Hiveon)</a></li>
</ul>
</details>
</ul>
</details>
<details>
<summary>LuxOS Firmware Miners:</summary>
<ul>
<details>
<summary>X9 Series:</summary>
<ul>
<li><a href="../antminer/X9#s9-luxos">S9 (LuxOS)</a></li>
</ul>
</details>
</ul>
</details>

View File

@@ -1,90 +1,94 @@
# pyasic # pyasic
## M2X Models ## M2X Models
## M20V10 ## M20 V10
::: pyasic.miners.whatsminer.btminer.M2X.M20.BTMinerM20V10
::: pyasic.miners.btc.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
## M20SV10 ## M20S V10
::: pyasic.miners.whatsminer.btminer.M2X.M20S.BTMinerM20SV10
::: pyasic.miners.btc.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
## M20SV20 ## M20S V20
::: pyasic.miners.whatsminer.btminer.M2X.M20S.BTMinerM20SV20
::: pyasic.miners.btc.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
## M20SV30 ## M20S V30
::: pyasic.miners.whatsminer.btminer.M2X.M20S.BTMinerM20SV30
::: pyasic.miners.btc.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
## M20S+V30 ## M20P V10
::: pyasic.miners.whatsminer.btminer.M2X.M20P.BTMinerM20PV10
::: pyasic.miners.btc.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
## M21V10 ## M20P V30
::: pyasic.miners.whatsminer.btminer.M2X.M20P.BTMinerM20PV30
::: pyasic.miners.btc.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
## M21SV20 ## M20S+ V30
::: pyasic.miners.whatsminer.btminer.M2X.M20S_Plus.BTMinerM20SPlusV30
::: pyasic.miners.btc.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
## M21SV60 ## M21 V10
::: pyasic.miners.whatsminer.btminer.M2X.M21.BTMinerM21V10
::: pyasic.miners.btc.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
## M21SV70 ## M21S V20
::: pyasic.miners.whatsminer.btminer.M2X.M21S.BTMinerM21SV20
::: pyasic.miners.btc.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 V60
::: pyasic.miners.whatsminer.btminer.M2X.M21S.BTMinerM21SV60
::: pyasic.miners.btc.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
## M29V10 ## M21S V70
::: pyasic.miners.whatsminer.btminer.M2X.M21S.BTMinerM21SV70
::: pyasic.miners.btc.whatsminer.btminer.M2X.M29.BTMinerM29V10
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## M21S+ V20
::: pyasic.miners.whatsminer.btminer.M2X.M21S_Plus.BTMinerM21SPlusV20
handler: python
options:
show_root_heading: false
heading_level: 4
## M29 V10
::: pyasic.miners.whatsminer.btminer.M2X.M29.BTMinerM29V10
handler: python
options:
show_root_heading: false
heading_level: 4

File diff suppressed because it is too large Load Diff

View File

@@ -1,242 +1,248 @@
# pyasic # pyasic
## M5X Models ## M5X Models
## M50VG30 ## M50 VE30
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VE30
::: pyasic.miners.btc.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
## M50VH10 ## M50 VG30
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VG30
::: pyasic.miners.btc.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
## M50VH20 ## M50 VH10
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH10
::: pyasic.miners.btc.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
## M50VH30 ## M50 VH20
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH20
::: pyasic.miners.btc.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
## M50VH40 ## M50 VH30
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH30
::: pyasic.miners.btc.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
## M50VH50 ## M50 VH40
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH40
::: pyasic.miners.btc.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
## M50VH60 ## M50 VH50
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH50
::: pyasic.miners.btc.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
## M50VH70 ## M50 VH60
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH60
::: pyasic.miners.btc.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
## M50VH80 ## M50 VH70
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH70
::: pyasic.miners.btc.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
## M50VJ10 ## M50 VH80
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH80
::: pyasic.miners.btc.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
## M50VJ20 ## M50 VJ10
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VJ10
::: pyasic.miners.btc.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
## M50VJ30 ## M50 VJ20
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VJ20
::: pyasic.miners.btc.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
## M50SVJ10 ## M50 VJ30
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VJ30
::: pyasic.miners.btc.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
## M50SVJ20 ## M50S VJ10
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVJ10
::: pyasic.miners.btc.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
## M50SVJ30 ## M50S VJ20
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVJ20
::: pyasic.miners.btc.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
## M50SVH10 ## M50S VJ30
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVJ30
::: pyasic.miners.btc.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
## M50SVH20 ## M50S VH10
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH10
::: pyasic.miners.btc.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
## M50SVH30 ## M50S VH20
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH20
::: pyasic.miners.btc.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
## M50SVH40 ## M50S VH30
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH30
::: pyasic.miners.btc.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
## M50SVH50 ## M50S VH40
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH40
::: pyasic.miners.btc.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 VH50
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH50
::: pyasic.miners.btc.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+ VH30
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVH30
::: pyasic.miners.btc.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+ VH40
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVH40
::: pyasic.miners.btc.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
## M53VH30 ## M50S+ VJ30
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVJ30
::: pyasic.miners.btc.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
## M53SVH30 ## M50S+ VK20
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVK20
::: pyasic.miners.btc.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 ## M50S++ VK10
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus_Plus.BTMinerM50SPlusPlusVK10
::: pyasic.miners.btc.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
## M56VH30 ## M50S++ VK20
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus_Plus.BTMinerM50SPlusPlusVK20
::: pyasic.miners.btc.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
## M56SVH30 ## M50S++ VK30
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus_Plus.BTMinerM50SPlusPlusVK30
::: pyasic.miners.btc.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 ## M53 VH30
::: pyasic.miners.whatsminer.btminer.M5X.M53.BTMinerM53VH30
::: pyasic.miners.btc.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
## M59VH30 ## M53S VH30
::: pyasic.miners.whatsminer.btminer.M5X.M53S.BTMinerM53SVH30
::: pyasic.miners.btc.whatsminer.btminer.M5X.M59.BTMinerM59VH30
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## M53S+ VJ30
::: pyasic.miners.whatsminer.btminer.M5X.M53S_Plus.BTMinerM53SPlusVJ30
handler: python
options:
show_root_heading: false
heading_level: 4
## M56 VH30
::: pyasic.miners.whatsminer.btminer.M5X.M56.BTMinerM56VH30
handler: python
options:
show_root_heading: false
heading_level: 4
## M56S VH30
::: pyasic.miners.whatsminer.btminer.M5X.M56S.BTMinerM56SVH30
handler: python
options:
show_root_heading: false
heading_level: 4
## M56S+ VJ30
::: pyasic.miners.whatsminer.btminer.M5X.M56S_Plus.BTMinerM56SPlusVJ30
handler: python
options:
show_root_heading: false
heading_level: 4
## M59 VH30
::: pyasic.miners.whatsminer.btminer.M5X.M59.BTMinerM59VH30
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -1,12 +0,0 @@
# pyasic
## Miner Network Range
[`MinerNetworkRange`][pyasic.network.net_range.MinerNetworkRange] is a class used by [`MinerNetwork`][pyasic.network.MinerNetwork] to handle any constructor stings.
The goal is to emulate what is produced by `ipaddress.ip_network` by allowing [`MinerNetwork`][pyasic.network.MinerNetwork] to get a list of hosts.
This allows this class to be the [`MinerNetwork.network`][pyasic.network.MinerNetwork] and hence be used for scanning.
::: pyasic.network.net_range.MinerNetworkRange
handler: python
options:
show_root_heading: false
heading_level: 4

35
docs/settings/settings.md Normal file
View File

@@ -0,0 +1,35 @@
# pyasic
## settings
All settings here are global settings for all of pyasic. Set these settings with `update(key, value)`.
Settings options:
- `network_ping_retries`
- `network_ping_timeout`
- `network_scan_threads`
- `factory_get_retries`
- `factory_get_timeout`
- `get_data_retries`
- `api_function_timeout`
- `default_whatsminer_password`
- `default_innosilicon_password`
- `default_antminer_password`
- `default_bosminer_password`
- `default_vnish_password`
- `default_goldshell_password`
- `socket_linger_time`
### get
::: pyasic.settings.get
handler: python
options:
show_root_heading: false
heading_level: 4
### update
::: pyasic.settings.update
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -7,7 +7,6 @@ nav:
- Miner Factory: "miners/miner_factory.md" - Miner Factory: "miners/miner_factory.md"
- Network: - Network:
- Miner Network: "network/miner_network.md" - Miner Network: "network/miner_network.md"
- Miner Network Range: "network/miner_network_range.md"
- Dataclasses: - Dataclasses:
- Miner Data: "data/miner_data.md" - Miner Data: "data/miner_data.md"
- Error Codes: "data/error_codes.md" - Error Codes: "data/error_codes.md"
@@ -20,6 +19,7 @@ nav:
- BOSMiner: "API/bosminer.md" - BOSMiner: "API/bosminer.md"
- BTMiner: "API/btminer.md" - BTMiner: "API/btminer.md"
- CGMiner: "API/cgminer.md" - CGMiner: "API/cgminer.md"
- LUXMiner: "API/luxminer.md"
- Unknown: "API/unknown.md" - Unknown: "API/unknown.md"
- Backends: - Backends:
- BMMiner: "miners/backends/bmminer.md" - BMMiner: "miners/backends/bmminer.md"
@@ -27,6 +27,9 @@ nav:
- BFGMiner: "miners/backends/bfgminer.md" - BFGMiner: "miners/backends/bfgminer.md"
- BTMiner: "miners/backends/btminer.md" - BTMiner: "miners/backends/btminer.md"
- CGMiner: "miners/backends/cgminer.md" - CGMiner: "miners/backends/cgminer.md"
- LUXMiner: "miners/backends/luxminer.md"
- VNish: "miners/backends/vnish.md"
- ePIC: "miners/backends/epic.md"
- Hiveon: "miners/backends/hiveon.md" - Hiveon: "miners/backends/hiveon.md"
- Classes: - Classes:
- Antminer X3: "miners/antminer/X3.md" - Antminer X3: "miners/antminer/X3.md"
@@ -40,16 +43,18 @@ nav:
- Avalon 8X: "miners/avalonminer/A8X.md" - Avalon 8X: "miners/avalonminer/A8X.md"
- Avalon 9X: "miners/avalonminer/A9X.md" - Avalon 9X: "miners/avalonminer/A9X.md"
- Avalon 10X: "miners/avalonminer/A10X.md" - Avalon 10X: "miners/avalonminer/A10X.md"
- Avalon 11X: "miners/avalonminer/A11X.md"
- Avalon 12X: "miners/avalonminer/A12X.md"
- 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"
- 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 CKX: "miners/goldshell/CKX.md" - Goldshell X5: "miners/goldshell/X5.md"
- Goldshell HSX: "miners/goldshell/HSX.md" - Goldshell XMax: "miners/goldshell/XMax.md"
- Goldshell KDX: "miners/goldshell/KDX.md"
- Base Miner: "miners/base_miner.md" - Base Miner: "miners/base_miner.md"
- Settings:
- Settings: "settings/settings.md"
plugins: plugins:
- mkdocstrings - mkdocstrings

View File

@@ -32,6 +32,8 @@ class BaseMinerAPI:
# ip address of the miner # ip address of the miner
self.ip = ipaddress.ip_address(ip) self.ip = ipaddress.ip_address(ip)
self.pwd = "admin"
def __new__(cls, *args, **kwargs): def __new__(cls, *args, **kwargs):
if cls is BaseMinerAPI: if cls is BaseMinerAPI:
raise TypeError(f"Only children of '{cls.__name__}' may be instantiated") raise TypeError(f"Only children of '{cls.__name__}' may be instantiated")
@@ -73,18 +75,23 @@ class BaseMinerAPI:
# send the command # send the command
data = await self._send_bytes(json.dumps(cmd).encode("utf-8")) data = await self._send_bytes(json.dumps(cmd).encode("utf-8"))
if data == b"Socket connect failed: Connection refused\n":
if not ignore_errors:
raise APIError(data.decode("utf-8"))
return {}
data = self._load_api_data(data) data = self._load_api_data(data)
# check for if the user wants to allow errors to return # check for if the user wants to allow errors to return
if not ignore_errors: validation = self._validate_command_output(data)
# validate the command succeeded if not validation[0]:
validation = self._validate_command_output(data) if not ignore_errors:
if not validation[0]: # validate the command succeeded
if allow_warning:
logging.warning(
f"{self.ip}: API Command Error: {command}: {validation[1]}"
)
raise APIError(validation[1]) raise APIError(validation[1])
if allow_warning:
logging.warning(
f"{self.ip}: API Command Error: {command}: {validation[1]}"
)
logging.debug(f"{self} - (Send Command) - Received data.") logging.debug(f"{self} - (Send Command) - Received data.")
return data return data
@@ -111,16 +118,29 @@ class BaseMinerAPI:
data = await self.send_command(command, allow_warning=allow_warning) data = await self.send_command(command, allow_warning=allow_warning)
except APIError as e: except APIError as e:
# try to identify the error # try to identify the error
if ":" in e.message: if e.message is not None:
err_command = e.message.split(":")[0] if ":" in e.message:
if err_command in commands: err_command = e.message.split(":")[0]
commands.remove(err_command) if err_command in commands:
continue commands.remove(err_command)
continue
return {command: [{}] for command in commands} return {command: [{}] for command in commands}
logging.debug(f"{self} - (Multicommand) - Received data") logging.debug(f"{self} - (Multicommand) - Received data")
data["multicommand"] = True data["multicommand"] = True
return data return data
async def _handle_multicommand(self, command: str, allow_warning: bool = True):
try:
data = await self.send_command(command, allow_warning=allow_warning)
if not "+" in command:
return {command: [data]}
return data
except APIError:
if "+" in command:
return {command: [{}] for command in command.split("+")}
return {command: [{}]}
@property @property
def commands(self) -> list: def commands(self) -> list:
return self.get_commands() return self.get_commands()
@@ -164,7 +184,11 @@ If you are sure you want to use this command please use API.send_command("{comma
) )
return return_commands return return_commands
async def _send_bytes(self, data: bytes, timeout: int = 100) -> bytes: async def _send_bytes(
self,
data: bytes,
timeout: int = 100,
) -> bytes:
logging.debug(f"{self} - ([Hidden] Send Bytes) - Sending") logging.debug(f"{self} - ([Hidden] Send Bytes) - Sending")
try: try:
# get reader and writer streams # get reader and writer streams
@@ -183,16 +207,18 @@ If you are sure you want to use this command please use API.send_command("{comma
logging.debug(f"{self} - ([Hidden] Send Bytes) - Draining") logging.debug(f"{self} - ([Hidden] Send Bytes) - Draining")
await writer.drain() await writer.drain()
try: try:
ret_data = await asyncio.wait_for(reader.read(4096), timeout=timeout) # TO address a situation where a whatsminer has an unknown PW -AND-
except ConnectionAbortedError:
return b"{}"
try:
# Fix for stupid whatsminer bug, reboot/restart seem to not load properly in the loop # Fix for stupid whatsminer bug, reboot/restart seem to not load properly in the loop
# have to receive, save the data, check if there is more data by reading with a short timeout # have to receive, save the data, check if there is more data by reading with a short timeout
# append that data if there is more, and then onto the main loop. # append that data if there is more, and then onto the main loop.
ret_data += await asyncio.wait_for(reader.read(1), timeout=1) # the password timeout might need to be longer than 1, but it seems to work for now.
except asyncio.TimeoutError: ret_data = await asyncio.wait_for(reader.read(1), timeout=1)
return ret_data except (asyncio.TimeoutError):
return b"{}"
try:
ret_data += await asyncio.wait_for(reader.read(4096), timeout=timeout)
except (ConnectionAbortedError):
return b"{}"
# loop to receive all the data # loop to receive all the data
logging.debug(f"{self} - ([Hidden] Send Bytes) - Receiving") logging.debug(f"{self} - ([Hidden] Send Bytes) - Receiving")
@@ -231,13 +257,22 @@ If you are sure you want to use this command please use API.send_command("{comma
# this is an error # this is an error
return False, f"{key}: " + data[key][0]["STATUS"][0]["Msg"] return False, f"{key}: " + data[key][0]["STATUS"][0]["Msg"]
elif "id" not in data.keys(): elif "id" not in data.keys():
if isinstance(data["STATUS"], list):
if data["STATUS"][0].get("STATUS", None) in ["S", "I"]:
return True, None
else:
return False, data["STATUS"][0]["Msg"]
if data["STATUS"] not in ["S", "I"]: if data["STATUS"] not in ["S", "I"]:
return False, data["Msg"] return False, data["Msg"]
else: else:
# make sure the command succeeded # make sure the command succeeded
if type(data["STATUS"]) == str: if isinstance(data["STATUS"], str):
if data["STATUS"] in ["RESTART"]: if data["STATUS"] in ["RESTART"]:
return True, None return True, None
elif isinstance(data["STATUS"], dict):
if data["STATUS"].get("STATUS") in ["S", "I"]:
return True, None
elif data["STATUS"][0]["STATUS"] not in ("S", "I"): elif data["STATUS"][0]["STATUS"] not in ("S", "I"):
# this is an error # this is an error
if data["STATUS"][0]["STATUS"] not in ("S", "I"): if data["STATUS"][0]["STATUS"] not in ("S", "I"):

View File

@@ -13,7 +13,7 @@
# 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. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
import asyncio
import logging import logging
from pyasic.API import APIError, BaseMinerAPI from pyasic.API import APIError, BaseMinerAPI
@@ -56,19 +56,19 @@ class BFGMinerAPI(BaseMinerAPI):
return data return data
async def _x19_multicommand(self, *commands) -> dict: async def _x19_multicommand(self, *commands) -> dict:
data = None tasks = []
try: # send all commands individually
data = {} for cmd in commands:
# send all commands individually tasks.append(
for cmd in commands: asyncio.create_task(self._handle_multicommand(cmd, allow_warning=True))
data[cmd] = []
data[cmd].append(await self.send_command(cmd, allow_warning=True))
except APIError:
pass
except Exception as e:
logging.warning(
f"{self} - ([Hidden] X19 Multicommand) - API Command Error {e}"
) )
all_data = await asyncio.gather(*tasks)
data = {}
for item in all_data:
data.update(item)
return data return data
async def version(self) -> dict: async def version(self) -> dict:

View File

@@ -13,6 +13,7 @@
# 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. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
import asyncio
import logging import logging
from pyasic.API import APIError, BaseMinerAPI from pyasic.API import APIError, BaseMinerAPI
@@ -57,21 +58,19 @@ class BMMinerAPI(BaseMinerAPI):
return data return data
async def _x19_multicommand(self, *commands, allow_warning: bool = True) -> dict: async def _x19_multicommand(self, *commands, allow_warning: bool = True) -> dict:
data = None tasks = []
try: # send all commands individually
data = {} for cmd in commands:
# send all commands individually tasks.append(
for cmd in commands: asyncio.create_task(self._handle_multicommand(cmd, allow_warning=True))
data[cmd] = []
data[cmd].append(
await self.send_command(cmd, allow_warning=allow_warning)
)
except APIError:
pass
except Exception as e:
logging.warning(
f"{self} - ([Hidden] X19 Multicommand) - API Command Error {e}"
) )
all_data = await asyncio.gather(*tasks)
data = {}
for item in all_data:
data.update(item)
return data return data
async def version(self) -> dict: async def version(self) -> dict:

View File

@@ -22,15 +22,15 @@ import hashlib
import json import json
import logging import logging
import re import re
from typing import Union from typing import Literal, Union
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from passlib.handlers.md5_crypt import md5_crypt from passlib.handlers.md5_crypt import md5_crypt
from pyasic import settings
from pyasic.API import BaseMinerAPI from pyasic.API import BaseMinerAPI
from pyasic.errors import APIError from pyasic.errors import APIError
from pyasic.misc import api_min_version from pyasic.misc import api_min_version
from pyasic.settings import PyasicSettings
### IMPORTANT ### ### IMPORTANT ###
# you need to change the password of the miners using the Whatsminer # you need to change the password of the miners using the Whatsminer
@@ -40,6 +40,12 @@ from pyasic.settings import PyasicSettings
# you change the password, you can pass that to this class as pwd, # you change the password, you can pass that to this class as pwd,
# or add it as the Whatsminer_pwd in the settings.toml file. # or add it as the Whatsminer_pwd in the settings.toml file.
PrePowerOnMessage = Union[
Literal["wait for adjust temp"],
Literal["adjust complete"],
Literal["adjust continue"],
]
def _crypt(word: str, salt: str) -> str: def _crypt(word: str, salt: str) -> str:
"""Encrypts a word with a salt, using a standard salt format. """Encrypts a word with a salt, using a standard salt format.
@@ -186,7 +192,7 @@ class BTMinerAPI(BaseMinerAPI):
ip: str, ip: str,
api_ver: str = "0.0.0", api_ver: str = "0.0.0",
port: int = 4028, port: int = 4028,
pwd: str = PyasicSettings().global_whatsminer_password, pwd: str = settings.get("default_whatsminer_password", "admin"),
): ):
super().__init__(ip, port) super().__init__(ip, port)
self.pwd = pwd self.pwd = pwd
@@ -203,27 +209,35 @@ class BTMinerAPI(BaseMinerAPI):
# make sure we can actually run each command, otherwise they will fail # make sure we can actually run each command, otherwise they will fail
commands = self._check_commands(*commands) commands = self._check_commands(*commands)
# standard multicommand format is "command1+command2" # standard multicommand format is "command1+command2"
# commands starting with "get_" aren't supported, but we can fake that # commands starting with "get_" and the "status" command aren't supported, but we can fake that
get_commands_data = {}
tasks = []
for command in list(commands): for command in list(commands):
if command.startswith("get_"): if command.startswith("get_") or command == "status":
commands.remove(command) commands.remove(command)
# send seperately and append later # send seperately and append later
try: tasks.append(
get_commands_data[command] = [ asyncio.create_task(
await self.send_command(command, allow_warning=allow_warning) self._handle_multicommand(command, allow_warning=allow_warning)
] )
except APIError: )
get_commands_data[command] = [{}]
command = "+".join(commands) command = "+".join(commands)
try: tasks.append(
main_data = await self.send_command(command, allow_warning=allow_warning) asyncio.create_task(
except APIError: self._handle_multicommand(command, allow_warning=allow_warning)
main_data = {command: [{}] for command in commands} )
)
all_data = await asyncio.gather(*tasks)
logging.debug(f"{self} - (Multicommand) - Received data") logging.debug(f"{self} - (Multicommand) - Received data")
data = dict(**main_data, **get_commands_data) data = {}
for item in all_data:
data.update(item)
data["multicommand"] = True data["multicommand"] = True
return data return data
@@ -685,7 +699,7 @@ class BTMinerAPI(BaseMinerAPI):
) )
return await self.send_privileged_command("set_power_pct", percent=str(percent)) return await self.send_privileged_command("set_power_pct", percent=str(percent))
async def pre_power_on(self, complete: bool, msg: str) -> dict: async def pre_power_on(self, complete: bool, msg: PrePowerOnMessage) -> dict:
"""Configure or check status of pre power on. """Configure or check status of pre power on.
<details> <details>
@@ -705,7 +719,7 @@ class BTMinerAPI(BaseMinerAPI):
</details> </details>
""" """
if not msg == "wait for adjust temp" or "adjust complete" or "adjust continue": if msg not in ("wait for adjust temp", "adjust complete", "adjust continue"):
raise APIError( raise APIError(
"Message is incorrect, please choose one of " "Message is incorrect, please choose one of "
'["wait for adjust temp", ' '["wait for adjust temp", '
@@ -721,6 +735,34 @@ class BTMinerAPI(BaseMinerAPI):
) )
### ADDED IN V2.0.5 Whatsminer API ### ### ADDED IN V2.0.5 Whatsminer API ###
@api_min_version("2.0.5")
async def set_power_pct_v2(self, percent: int) -> dict:
"""Set the power percentage of the miner based on current power. Used for temporary adjustment. Added in API v2.0.5.
<details>
<summary>Expand</summary>
Set the power percentage of the miner, only works after changing
the password of the miner using the Whatsminer tool.
Parameters:
percent: The power percentage to set.
Returns:
A reply informing of the status of setting the power percentage.
</details>
"""
if not 0 < percent < 100:
raise APIError(
f"Power PCT % is outside of the allowed "
f"range. Please set a % between 0 and "
f"100"
)
return await self.send_privileged_command(
"set_power_pct_v2", percent=str(percent)
)
@api_min_version("2.0.5") @api_min_version("2.0.5")
async def set_temp_offset(self, temp_offset: int) -> dict: async def set_temp_offset(self, temp_offset: int) -> dict:
"""Set the offset of miner hash board target temperature. """Set the offset of miner hash board target temperature.

View File

@@ -13,7 +13,7 @@
# 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. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
import asyncio
import logging import logging
from pyasic.API import APIError, BaseMinerAPI from pyasic.API import APIError, BaseMinerAPI
@@ -56,19 +56,19 @@ class CGMinerAPI(BaseMinerAPI):
return data return data
async def _x19_multicommand(self, *commands) -> dict: async def _x19_multicommand(self, *commands) -> dict:
data = None tasks = []
try: # send all commands individually
data = {} for cmd in commands:
# send all commands individually tasks.append(
for cmd in commands: asyncio.create_task(self._handle_multicommand(cmd, allow_warning=True))
data[cmd] = []
data[cmd].append(await self.send_command(cmd, allow_warning=True))
except APIError:
pass
except Exception as e:
logging.warning(
f"{self} - ([Hidden] X19 Multicommand) - API Command Error {e}"
) )
all_data = await asyncio.gather(*tasks)
data = {}
for item in all_data:
data.update(item)
return data return data
async def version(self) -> dict: async def version(self) -> dict:

759
pyasic/API/luxminer.py Normal file
View File

@@ -0,0 +1,759 @@
# ------------------------------------------------------------------------------
# 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 typing import Literal
from pyasic.API import BaseMinerAPI
class LUXMinerAPI(BaseMinerAPI):
"""An abstraction of the LUXMiner API.
Each method corresponds to an API command in LUXMiner.
[LUXMiner API documentation](https://docs.firmware.luxor.tech/API/intro)
This class abstracts use of the LUXMiner API, as well as the
methods for sending commands to it. The `self.send_command()`
function handles sending a command to the miner asynchronously, and
as such is the base for many of the functions in this class, which
rely on it to send the command for them.
Parameters:
ip: The IP of the miner to reference the API on.
port: The port to reference the API on. Default is 4028.
"""
def __init__(self, ip: str, api_ver: str = "0.0.0", port: int = 4028) -> None:
super().__init__(ip, port=port)
self.api_ver = api_ver
async def addgroup(self, name: str, quota: int) -> dict:
"""Add a pool group.
<details>
<summary>Expand</summary>
Parameters:
name: The group name.
quota: The group quota.
Returns:
Confirmation of adding a pool group.
</details>
"""
return await self.send_command("addgroup", parameters=f"{name},{quota}")
async def addpool(
self, url: str, user: str, pwd: str = "", group_id: str = None
) -> dict:
"""Add a pool.
<details>
<summary>Expand</summary>
Parameters:
url: The pool url.
user: The pool username.
pwd: The pool password.
group_id: The group ID to use.
Returns:
Confirmation of adding a pool.
</details>
"""
pool_data = [url, user, pwd]
if group_id is not None:
pool_data.append(group_id)
return await self.send_command("addpool", parameters=",".join(pool_data))
async def asc(self, n: int) -> dict:
"""Get data for ASC device n.
<details>
<summary>Expand</summary>
Parameters:
n: The device to get data for.
Returns:
The data for ASC device n.
</details>
"""
return await self.send_command("asc", parameters=n)
async def asccount(self) -> dict:
"""Get data on the number of ASC devices and their info.
<details>
<summary>Expand</summary>
Returns:
Data on all ASC devices.
</details>
"""
return await self.send_command("asccount")
async def check(self, command: str) -> dict:
"""Check if the command `command` exists in LUXMiner.
<details>
<summary>Expand</summary>
Parameters:
command: The command to check.
Returns:
## Information about a command:
* Exists (Y/N) <- the command exists in this version
* Access (Y/N) <- you have access to use the command
</details>
"""
return await self.send_command("check", parameters=command)
async def coin(self) -> dict:
"""Get information on the current coin.
<details>
<summary>Expand</summary>
Returns:
## Information about the current coin being mined:
* Hash Method <- the hashing algorithm
* Current Block Time <- blocktime as a float, 0 means none
* Current Block Hash <- the hash of the current block, blank means none
* LP <- whether LP is in use on at least 1 pool
* Network Difficulty: the current network difficulty
</details>
"""
return await self.send_command("coin")
async def config(self) -> dict:
"""Get some basic configuration info.
<details>
<summary>Expand</summary>
Returns:
Miner configuration information.
</details>
"""
return await self.send_command("config")
async def curtail(self, session_id: str) -> dict:
"""Put the miner into sleep mode. Requires a session_id from logon.
<details>
<summary>Expand</summary>
Parameters:
session_id: Session id from the logon command.
Returns:
A confirmation of putting the miner to sleep.
</details>
"""
return await self.send_command("curtail", parameters=session_id)
async def devdetails(self) -> dict:
"""Get data on all devices with their static details.
<details>
<summary>Expand</summary>
Returns:
Data on all devices with their static details.
</details>
"""
return await self.send_command("devdetails")
async def devs(self) -> dict:
"""Get data on each PGA/ASC with their details.
<details>
<summary>Expand</summary>
Returns:
Data on each PGA/ASC with their details.
</details>
"""
return await self.send_command("devs")
async def disablepool(self, n: int) -> dict:
"""Disable a pool.
<details>
<summary>Expand</summary>
Parameters:
n: Pool to disable.
Returns:
A confirmation of diabling the pool.
</details>
"""
return await self.send_command("disablepool", parameters=n)
async def edevs(self) -> dict:
"""Alias for devs"""
return await self.devs()
async def enablepool(self, n: int) -> dict:
"""Enable pool n.
<details>
<summary>Expand</summary>
Parameters:
n: The pool to enable.
Returns:
A confirmation of enabling pool n.
</details>
"""
return await self.send_command("enablepool", parameters=n)
async def estats(self) -> dict:
"""Alias for stats"""
return await self.stats()
async def fans(self) -> dict:
"""Get fan data.
<details>
<summary>Expand</summary>
Returns:
Data on the fans of the miner.
</details>
"""
return await self.send_command("fans")
async def fanset(self, session_id: str, speed: int, min_fans: int = None) -> dict:
"""Set fan control. Requires a session_id from logon.
<details>
<summary>Expand</summary>
Parameters:
session_id: Session id from the logon command.
speed: The fan speed to set. Use -1 to set automatically.
min_fans: The minimum number of fans to use. Optional.
Returns:
A confirmation of setting fan control values.
</details>
"""
fanset_data = [str(session_id), str(speed)]
if min_fans is not None:
fanset_data.append(str(min_fans))
return await self.send_command("fanset", parameters=",".join(fanset_data))
async def frequencyget(self, board_n: int, chip_n: int = None) -> dict:
"""Get frequency data for a board and chips.
<details>
<summary>Expand</summary>
Parameters:
board_n: The board number to get frequency info from.
chip_n: The chip number to get frequency info from. Optional.
Returns:
Board and/or chip frequency values.
</details>
"""
frequencyget_data = [str(board_n)]
if chip_n is not None:
frequencyget_data.append(str(chip_n))
return await self.send_command(
"frequencyget", parameters=",".join(frequencyget_data)
)
async def frequencyset(self, session_id: str, board_n: int, freq: int) -> dict:
"""Set frequency. Requires a session_id from logon.
<details>
<summary>Expand</summary>
Parameters:
session_id: Session id from the logon command.
board_n: The board number to set frequency on.
freq: The frequency to set.
Returns:
A confirmation of setting frequency values.
</details>
"""
return await self.send_command(
"frequencyset", parameters=f"{session_id},{board_n},{freq}"
)
async def frequencystop(self, session_id: str, board_n: int) -> dict:
"""Stop set frequency. Requires a session_id from logon.
<details>
<summary>Expand</summary>
Parameters:
session_id: Session id from the logon command.
board_n: The board number to set frequency on.
Returns:
A confirmation of stopping frequencyset value.
</details>
"""
return await self.send_command(
"frequencystop", parameters=f"{session_id},{board_n}"
)
async def groupquota(self, group_n: int, quota: int) -> dict:
"""Set a group's quota.
<details>
<summary>Expand</summary>
Parameters:
group_n: The group number to set quota on.
quota: The quota to use.
Returns:
A confirmation of setting quota value.
</details>
"""
return await self.send_command("groupquota", parameters=f"{group_n},{quota}")
async def groups(self) -> dict:
"""Get pool group data.
<details>
<summary>Expand</summary>
Returns:
Data on the pool groups on the miner.
</details>
"""
return await self.send_command("groups")
async def healthchipget(self, board_n: int, chip_n: int = None) -> dict:
"""Get chip health.
<details>
<summary>Expand</summary>
Parameters:
board_n: The board number to get chip health of.
chip_n: The chip number to get chip health of. Optional.
Returns:
Chip health data.
</details>
"""
healthchipget_data = [str(board_n)]
if chip_n is not None:
healthchipget_data.append(str(chip_n))
return await self.send_command(
"healthchipget", parameters=",".join(healthchipget_data)
)
async def healthchipset(
self, session_id: str, board_n: int, chip_n: int = None
) -> dict:
"""Select the next chip to have its health checked. Requires a session_id from logon.
<details>
<summary>Expand</summary>
Parameters:
session_id: Session id from the logon command.
board_n: The board number to next get chip health of.
chip_n: The chip number to next get chip health of. Optional.
Returns:
Confirmation of selecting the next health check chip.
</details>
"""
healthchipset_data = [session_id, str(board_n)]
if chip_n is not None:
healthchipset_data.append(str(chip_n))
return await self.send_command(
"healthchipset", parameters=",".join(healthchipset_data)
)
async def healthctrl(self) -> dict:
"""Get health check config.
<details>
<summary>Expand</summary>
Returns:
Health check config.
</details>
"""
return await self.send_command("healthctrl")
async def healthctrlset(
self, session_id: str, num_readings: int, amplified_factor: float
) -> dict:
"""Set health control config. Requires a session_id from logon.
<details>
<summary>Expand</summary>
Parameters:
session_id: Session id from the logon command.
num_readings: The minimum number of readings for evaluation.
amplified_factor: Performance factor of the evaluation.
Returns:
A confirmation of setting health control config.
</details>
"""
return await self.send_command(
"healthctrlset",
parameters=f"{session_id},{num_readings},{amplified_factor}",
)
async def kill(self) -> dict:
"""Forced session kill. Use logoff instead.
<details>
<summary>Expand</summary>
Returns:
A confirmation of killing the active session.
</details>
"""
return await self.send_command("kill")
async def lcd(self) -> dict:
"""Get a general all-in-one status summary of the miner. Always zeros on LUXMiner.
<details>
<summary>Expand</summary>
Returns:
An all-in-one status summary of the miner.
</details>
"""
return await self.send_command("lcd")
async def ledset(
self,
session_id: str,
color: Literal["red"],
state: Literal["on", "off", "blink"],
) -> dict:
"""Set led. Requires a session_id from logon.
<details>
<summary>Expand</summary>
Parameters:
session_id: Session id from the logon command.
color: The color LED to set. Can be "red".
state: The state to set the LED to. Can be "on", "off", or "blink".
Returns:
A confirmation of setting LED.
</details>
"""
return await self.send_command(
"ledset", parameters=f"{session_id},{color},{state}"
)
async def limits(self) -> dict:
"""Get max and min values of config parameters.
<details>
<summary>Expand</summary>
Returns:
Data on max and min values of config parameters.
</details>
"""
return await self.send_command("limits")
async def logoff(self, session_id: str) -> dict:
"""Log off of a session. Requires a session id from an active session.
<details>
<summary>Expand</summary>
Parameters:
session_id: Session id from the logon command.
Returns:
Confirmation of logging off a session.
</details>
"""
return await self.send_command("logoff", parameters=session_id)
async def logon(self) -> dict:
"""Get or create a session.
<details>
<summary>Expand</summary>
Returns:
The Session ID to be used.
</details>
"""
return await self.send_command("logon")
async def pools(self) -> dict:
"""Get pool information.
<details>
<summary>Expand</summary>
Returns:
Miner pool information.
</details>
"""
return await self.send_command("pools")
async def power(self) -> dict:
"""Get the estimated power usage in watts.
<details>
<summary>Expand</summary>
Returns:
Estimated power usage in watts.
</details>
"""
return await self.send_command("power")
async def profiles(self) -> dict:
"""Get the available profiles.
<details>
<summary>Expand</summary>
Returns:
Data on available profiles.
</details>
"""
return await self.send_command("profiles")
async def profileset(self, session_id: str, board_n: int, profile: str) -> dict:
"""Set active profile for a board. Requires a session_id from logon.
<details>
<summary>Expand</summary>
Parameters:
session_id: Session id from the logon command.
board_n: The board to set the profile on.
profile: The profile name to use.
Returns:
A confirmation of setting the profile on board_n.
</details>
"""
return await self.send_command(
"profileset", parameters=f"{session_id},{board_n},{profile}"
)
async def reboot(self, session_id: str, board_n: int, delay_s: int = None) -> dict:
"""Reboot a board. Requires a session_id from logon.
<details>
<summary>Expand</summary>
Parameters:
session_id: Session id from the logon command.
board_n: The board to reboot.
delay_s: The number of seconds to delay until startup. If it is 0, the board will just stop. Optional.
Returns:
A confirmation of rebooting board_n.
</details>
"""
reboot_data = [session_id, str(board_n)]
if delay_s is not None:
reboot_data.append(str(delay_s))
return await self.send_command("reboot", parameters=",".join(reboot_data))
async def rebootdevice(self, session_id: str) -> dict:
"""Reboot the miner. Requires a session_id from logon.
<details>
<summary>Expand</summary>
Parameters:
session_id: Session id from the logon command.
Returns:
A confirmation of rebooting the miner.
</details>
"""
return await self.send_command("rebootdevice", parameters=session_id)
async def removegroup(self, group_id: str) -> dict:
"""Remove a pool group.
<details>
<summary>Expand</summary>
Parameters:
group_id: Group id to remove.
Returns:
A confirmation of removing the pool group.
</details>
"""
return await self.send_command("removegroup", parameters=group_id)
async def resetminer(self, session_id: str) -> dict:
"""Restart the mining process. Requires a session_id from logon.
<details>
<summary>Expand</summary>
Parameters:
session_id: Session id from the logon command.
Returns:
A confirmation of restarting the mining process.
</details>
"""
return await self.send_command("resetminer", parameters=session_id)
async def removepool(self, pool_id: int) -> dict:
"""Remove a pool.
<details>
<summary>Expand</summary>
Parameters:
pool_id: Pool to remove.
Returns:
A confirmation of removing the pool.
</details>
"""
return await self.send_command("removepool", parameters=str(pool_id))
async def session(self) -> dict:
"""Get the current session.
<details>
<summary>Expand</summary>
Returns:
Data on the current session.
</details>
"""
return await self.send_command("session")
async def tempctrlset(self, target: int, hot: int, dangerous: int) -> dict:
"""Set temp control values.
<details>
<summary>Expand</summary>
Parameters:
target: Target temp.
hot: Hot temp.
dangerous: Dangerous temp.
Returns:
A confirmation of setting the temp control config.
</details>
"""
return await self.send_command(
"tempctrlset", parameters=f"{target},{hot},{dangerous}"
)
async def stats(self) -> dict:
"""Get stats of each device/pool with more than 1 getwork.
<details>
<summary>Expand</summary>
Returns:
Stats of each device/pool with more than 1 getwork.
</details>
"""
return await self.send_command("stats")
async def summary(self) -> dict:
"""Get the status summary of the miner.
<details>
<summary>Expand</summary>
Returns:
The status summary of the miner.
</details>
"""
return await self.send_command("summary")
async def switchpool(self, pool_id: int) -> dict:
"""Switch to a pool.
<details>
<summary>Expand</summary>
Parameters:
pool_id: Pool to switch to.
Returns:
A confirmation of switching to the pool.
</details>
"""
return await self.send_command("switchpool", parameters=str(pool_id))
async def tempctrl(self) -> dict:
"""Get temperature control data.
<details>
<summary>Expand</summary>
Returns:
Data about the temp control settings of the miner.
</details>
"""
return await self.send_command("tempctrl")
async def temps(self) -> dict:
"""Get temperature data.
<details>
<summary>Expand</summary>
Returns:
Data on the temps of the miner.
</details>
"""
return await self.send_command("temps")
async def version(self) -> dict:
"""Get miner version info.
<details>
<summary>Expand</summary>
Returns:
Miner version information.
</details>
"""
return await self.send_command("version")
async def voltageget(self, board_n: int) -> dict:
"""Get voltage data for a board.
<details>
<summary>Expand</summary>
Parameters:
board_n: The board number to get voltage info from.
Returns:
Board voltage values.
</details>
"""
return await self.send_command("frequencyget", parameters=str(board_n))
async def voltageset(self, session_id: str, board_n: int, voltage: float) -> dict:
"""Set voltage values.
<details>
<summary>Expand</summary>
Parameters:
session_id: Session id from the logon command.
board_n: The board to set the voltage on.
voltage: The voltage to use.
Returns:
A confirmation of setting the voltage.
</details>
"""
return await self.send_command(
"voltageset", parameters=f"{session_id},{board_n},{voltage}"
)
async def wakeup(self, session_id: str) -> dict:
"""Take the miner out of sleep mode. Requires a session_id from logon.
<details>
<summary>Expand</summary>
Parameters:
session_id: Session id from the logon command.
Returns:
A confirmation of resuming mining.
</details>
"""
return await self.send_command("wakeup", parameters=session_id)

View File

@@ -13,6 +13,7 @@
# 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 import settings
from pyasic.API.bmminer import BMMinerAPI from pyasic.API.bmminer import BMMinerAPI
from pyasic.API.bosminer import BOSMinerAPI from pyasic.API.bosminer import BOSMinerAPI
from pyasic.API.btminer import BTMinerAPI from pyasic.API.btminer import BTMinerAPI
@@ -29,10 +30,9 @@ from pyasic.data import (
from pyasic.errors import APIError, APIWarning from pyasic.errors import APIError, APIWarning
from pyasic.miners import get_miner from pyasic.miners import get_miner
from pyasic.miners.base import AnyMiner from pyasic.miners.base import AnyMiner
from pyasic.miners.miner_factory import MinerFactory from pyasic.miners.miner_factory import MinerFactory, miner_factory
from pyasic.miners.miner_listener import MinerListener from pyasic.miners.miner_listener import MinerListener
from pyasic.network import MinerNetwork from pyasic.network import MinerNetwork
from pyasic.settings import PyasicSettings
__all__ = [ __all__ = [
"BMMinerAPI", "BMMinerAPI",
@@ -51,7 +51,8 @@ __all__ = [
"get_miner", "get_miner",
"AnyMiner", "AnyMiner",
"MinerFactory", "MinerFactory",
"miner_factory",
"MinerListener", "MinerListener",
"MinerNetwork", "MinerNetwork",
"PyasicSettings", "settings",
] ]

View File

@@ -215,7 +215,7 @@ class _PoolGroup:
return pools return pools
def as_x17(self, user_suffix: str = None) -> dict: def as_x17(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a list usable by an X5 device. """Convert the data in this class to a list usable by an X17 device.
Parameters: Parameters:
user_suffix: The suffix to append to username. user_suffix: The suffix to append to username.
@@ -547,11 +547,11 @@ class MinerConfig:
""" """
logging.debug(f"MinerConfig - (As X19) - Generating X19 config") logging.debug(f"MinerConfig - (As X19) - Generating X19 config")
cfg = { cfg = {
"pools": self.pool_groups[0].as_x19(user_suffix=user_suffix),
"bitmain-fan-ctrl": False, "bitmain-fan-ctrl": False,
"bitmain-fan-pwn": "100", "bitmain-fan-pwn": "100",
"freq-level": "100",
"miner-mode": str(self.miner_mode.value), "miner-mode": str(self.miner_mode.value),
"freq-level": "100" "pools": self.pool_groups[0].as_x19(user_suffix=user_suffix),
} }
if not self.temp_mode == "auto": if not self.temp_mode == "auto":
@@ -560,9 +560,6 @@ class MinerConfig:
if self.fan_speed: if self.fan_speed:
cfg["bitmain-fan-pwn"] = str(self.fan_speed) cfg["bitmain-fan-pwn"] = str(self.fan_speed)
if self.miner_mode == X19PowerMode.Sleep:
cfg["freq-level"] = "0"
return cfg return cfg
def as_x17(self, user_suffix: str = None) -> dict: def as_x17(self, user_suffix: str = None) -> dict:

View File

@@ -20,7 +20,7 @@ import logging
import time import time
from dataclasses import asdict, dataclass, field, fields from dataclasses import asdict, dataclass, field, fields
from datetime import datetime, timezone from datetime import datetime, timezone
from typing import List, Union from typing import Any, List, Union
from .error_codes import BraiinsOSError, InnosiliconError, WhatsminerError, X19Error from .error_codes import BraiinsOSError, InnosiliconError, WhatsminerError, X19Error
@@ -40,13 +40,28 @@ class HashBoard:
""" """
slot: int = 0 slot: int = 0
hashrate: float = 0.0 hashrate: float = None
temp: int = -1 temp: int = None
chip_temp: int = -1 chip_temp: int = None
chips: int = 0 chips: int = None
expected_chips: int = 0 expected_chips: int = None
missing: bool = True missing: bool = True
def get(self, __key: str, default: Any = None):
try:
val = self.__getitem__(__key)
if val is None:
return default
return val
except KeyError:
return default
def __getitem__(self, item: str):
try:
return getattr(self, item)
except AttributeError:
raise KeyError(f"{item}")
@dataclass @dataclass
class Fan: class Fan:
@@ -56,7 +71,22 @@ class Fan:
speed: The speed of the fan. speed: The speed of the fan.
""" """
speed: int = -1 speed: int = None
def get(self, __key: str, default: Any = None):
try:
val = self.__getitem__(__key)
if val is None:
return default
return val
except KeyError:
return default
def __getitem__(self, item: str):
try:
return getattr(self, item)
except AttributeError:
raise KeyError(f"{item}")
@dataclass @dataclass
@@ -66,34 +96,23 @@ class MinerData:
Attributes: Attributes:
ip: The IP of the miner as a str. ip: The IP of the miner as a str.
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.
mac: The MAC address of the miner as a str.
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.
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. hashrate: The hashrate of the miner in TH/s as a float. Calculated automatically.
_hashrate: Backup for hashrate found via API instead of hashboards.
nominal_hashrate: The factory nominal hashrate of the miner in TH/s as a float. nominal_hashrate: The factory nominal hashrate of the miner in TH/s as a float.
left_board_hashrate: The hashrate of the left board of the miner in TH/s as a float. hashboards: A list of hashboards on the miner with their statistics.
center_board_hashrate: The hashrate of the center board of the miner in TH/s as a float.
right_board_hashrate: The hashrate of the right board of the miner in TH/s as a float.
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.
left_board_temp: The temp of the left PCB as an int.
left_board_chip_temp: The temp of the left board chips as an int.
center_board_temp: The temp of the center PCB as an int.
center_board_chip_temp: The temp of the center board chips as an int.
right_board_temp: The temp of the right PCB as an int.
right_board_chip_temp: The temp of the right board chips as an int.
wattage: Current power draw of the miner as an int. wattage: Current power draw of the miner as an int.
wattage_limit: Power limit of the miner as an int. wattage_limit: Power limit of the miner as an int.
fan_1: The speed of the first fan as an int. fans: A list of fans on the miner with their speeds.
fan_2: The speed of the second fan as an int.
fan_3: The speed of the third fan as an int.
fan_4: The speed of the fourth fan as an int.
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.
left_chips: The number of chips online in the left board as an int.
center_chips: The number of chips online in the left board as an int.
right_chips: The number of chips online in the left board as an int.
total_chips: The total number of chips on all boards. Calculated automatically. total_chips: The total number of chips on all boards. Calculated automatically.
ideal_chips: The ideal number of chips in the miner as an int. ideal_chips: The ideal number of chips in the miner as an int.
percent_ideal_chips: The percent of total chips out of the ideal count. Calculated automatically. percent_ideal_chips: The percent of total chips out of the ideal count. Calculated automatically.
@@ -106,51 +125,37 @@ class MinerData:
pool_2_url: The second pool url on the miner as a str. pool_2_url: The second pool url on the miner as a str.
pool_2_user: The second pool user on the miner as a str. pool_2_user: The second pool user on the miner as a str.
errors: A list of errors on the miner. errors: A list of errors on the miner.
fault_light: Whether or not 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.
""" """
ip: str ip: str
datetime: datetime = None datetime: datetime = None
mac: str = "00:00:00:00:00:00" uptime: int = None
model: str = "Unknown" mac: str = None
make: str = "Unknown" model: str = None
api_ver: str = "Unknown" make: str = None
fw_ver: str = "Unknown" api_ver: str = None
hostname: str = "Unknown" fw_ver: str = None
hostname: str = None
hashrate: float = field(init=False) hashrate: float = field(init=False)
_hashrate: float = 0 _hashrate: float = None
nominal_hashrate: float = 0 nominal_hashrate: float = None
hashboards: List[HashBoard] = field(default_factory=list) hashboards: List[HashBoard] = field(default_factory=list)
ideal_hashboards: int = 1 ideal_hashboards: int = None
left_board_hashrate: float = field(init=False)
center_board_hashrate: float = field(init=False)
right_board_hashrate: float = field(init=False)
temperature_avg: int = field(init=False) temperature_avg: int = field(init=False)
env_temp: float = -1.0 env_temp: float = None
left_board_temp: int = field(init=False) wattage: int = None
left_board_chip_temp: int = field(init=False) wattage_limit: int = None
center_board_temp: int = field(init=False)
center_board_chip_temp: int = field(init=False)
right_board_temp: int = field(init=False)
right_board_chip_temp: int = field(init=False)
wattage: int = -1
wattage_limit: int = -1
fans: List[Fan] = field(default_factory=list) fans: List[Fan] = field(default_factory=list)
fan_1: int = field(init=False) fan_psu: int = None
fan_2: int = field(init=False)
fan_3: int = field(init=False)
fan_4: int = field(init=False)
fan_psu: int = -1
left_chips: int = field(init=False)
center_chips: int = field(init=False)
right_chips: int = field(init=False)
total_chips: int = field(init=False) total_chips: int = field(init=False)
ideal_chips: int = 1 ideal_chips: int = None
percent_ideal_chips: float = field(init=False) percent_ideal_chips: float = field(init=False)
percent_ideal_hashrate: float = field(init=False) percent_ideal_hashrate: float = field(init=False)
percent_ideal_wattage: float = field(init=False) percent_ideal_wattage: float = field(init=False)
nominal: int = field(init=False) nominal: bool = field(init=False)
pool_split: str = "0" pool_split: str = "0"
pool_1_url: str = "Unknown" pool_1_url: str = "Unknown"
pool_1_user: str = "Unknown" pool_1_user: str = "Unknown"
@@ -161,6 +166,7 @@ class MinerData:
] = field(default_factory=list) ] = field(default_factory=list)
fault_light: Union[bool, None] = None fault_light: Union[bool, None] = None
efficiency: int = field(init=False) efficiency: int = field(init=False)
is_mining: bool = True
@classmethod @classmethod
def fields(cls): def fields(cls):
@@ -169,7 +175,16 @@ class MinerData:
def __post_init__(self): def __post_init__(self):
self.datetime = datetime.now(timezone.utc).astimezone() self.datetime = datetime.now(timezone.utc).astimezone()
def __getitem__(self, item): def get(self, __key: str, default: Any = None):
try:
val = self.__getitem__(__key)
if val is None:
return default
return val
except KeyError:
return default
def __getitem__(self, item: str):
try: try:
return getattr(self, item) return getattr(self, item)
except AttributeError: except AttributeError:
@@ -221,204 +236,37 @@ class MinerData:
@property @property
def hashrate(self): # noqa - Skip PyCharm inspection def hashrate(self): # noqa - Skip PyCharm inspection
if len(self.hashboards) > 0: if len(self.hashboards) > 0:
return round(sum(map(lambda x: x.hashrate, self.hashboards)), 2) hr_data = []
for item in self.hashboards:
if item.hashrate is not None:
hr_data.append(item.hashrate)
if len(hr_data) > 0:
return round(sum(hr_data), 2)
return self._hashrate return self._hashrate
@hashrate.setter @hashrate.setter
def hashrate(self, val): def hashrate(self, val):
self._hashrate = val self._hashrate = val
@property
def fan_1(self): # noqa - Skip PyCharm inspection
if len(self.fans) > 0:
return self.fans[0].speed
@fan_1.setter
def fan_1(self, val):
pass
@property
def fan_2(self): # noqa - Skip PyCharm inspection
if len(self.fans) > 1:
return self.fans[1].speed
@fan_2.setter
def fan_2(self, val):
pass
@property
def fan_3(self): # noqa - Skip PyCharm inspection
if len(self.fans) > 2:
return self.fans[2].speed
@fan_3.setter
def fan_3(self, val):
pass
@property
def fan_4(self): # noqa - Skip PyCharm inspection
if len(self.fans) > 3:
return self.fans[3].speed
@fan_4.setter
def fan_4(self, val):
pass
@property @property
def total_chips(self): # noqa - Skip PyCharm inspection def total_chips(self): # noqa - Skip PyCharm inspection
return sum([hb.chips for hb in self.hashboards]) if len(self.hashboards) > 0:
chip_data = []
for item in self.hashboards:
if item.chips is not None:
chip_data.append(item.chips)
if len(chip_data) > 0:
return sum(chip_data)
return None
@total_chips.setter @total_chips.setter
def total_chips(self, val): def total_chips(self, val):
pass pass
@property
def left_chips(self): # noqa - Skip PyCharm inspection
if len(self.hashboards) in [2, 3, 4]:
return self.hashboards[0].chips
return 0
@left_chips.setter
def left_chips(self, val):
pass
@property
def center_chips(self): # noqa - Skip PyCharm inspection
if len(self.hashboards) == 1:
return self.hashboards[0].chips
if len(self.hashboards) in [2, 3, 4]:
return self.hashboards[1].chips
return 0
@center_chips.setter
def center_chips(self, val):
pass
@property
def right_chips(self): # noqa - Skip PyCharm inspection
if len(self.hashboards) == 2:
return self.hashboards[1].chips
if len(self.hashboards) == 3:
return self.hashboards[2].chips
if len(self.hashboards) > 3:
return self.hashboards[-1:][0].chips
return 0
@right_chips.setter
def right_chips(self, val):
pass
@property
def left_board_hashrate(self): # noqa - Skip PyCharm inspection
if len(self.hashboards) in [2, 3, 4]:
return self.hashboards[0].hashrate
return 0
@left_board_hashrate.setter
def left_board_hashrate(self, val):
pass
@property
def center_board_hashrate(self): # noqa - Skip PyCharm inspection
if len(self.hashboards) == 1:
return self.hashboards[0].hashrate
if len(self.hashboards) in [2, 3, 4]:
return self.hashboards[1].hashrate
return 0
@center_board_hashrate.setter
def center_board_hashrate(self, val):
pass
@property
def right_board_hashrate(self): # noqa - Skip PyCharm inspection
if len(self.hashboards) == 2:
return self.hashboards[1].hashrate
if len(self.hashboards) == 3:
return self.hashboards[2].hashrate
if len(self.hashboards) > 3:
return self.hashboards[-1:][0].hashrate
return 0
@right_board_hashrate.setter
def right_board_hashrate(self, val):
pass
@property
def left_board_temp(self): # noqa - Skip PyCharm inspection
if len(self.hashboards) in [2, 3, 4]:
return self.hashboards[0].temp
return 0
@left_board_temp.setter
def left_board_temp(self, val):
pass
@property
def center_board_temp(self): # noqa - Skip PyCharm inspection
if len(self.hashboards) == 1:
return self.hashboards[0].temp
if len(self.hashboards) in [2, 3, 4]:
return self.hashboards[1].temp
return 0
@center_board_temp.setter
def center_board_temp(self, val):
pass
@property
def right_board_temp(self): # noqa - Skip PyCharm inspection
if len(self.hashboards) == 2:
return self.hashboards[1].temp
if len(self.hashboards) == 3:
return self.hashboards[2].temp
if len(self.hashboards) > 3:
return self.hashboards[-1:][0].temp
return 0
@right_board_temp.setter
def right_board_temp(self, val):
pass
@property
def left_board_chip_temp(self): # noqa - Skip PyCharm inspection
if len(self.hashboards) in [2, 3, 4]:
return self.hashboards[0].chip_temp
return 0
@left_board_chip_temp.setter
def left_board_chip_temp(self, val):
pass
@property
def center_board_chip_temp(self): # noqa - Skip PyCharm inspection
if len(self.hashboards) == 1:
return self.hashboards[0].chip_temp
if len(self.hashboards) in [2, 3, 4]:
return self.hashboards[1].chip_temp
return 0
@center_board_chip_temp.setter
def center_board_chip_temp(self, val):
pass
@property
def right_board_chip_temp(self): # noqa - Skip PyCharm inspection
if len(self.hashboards) == 2:
return self.hashboards[1].chip_temp
if len(self.hashboards) == 3:
return self.hashboards[2].chip_temp
if len(self.hashboards) > 3:
return self.hashboards[-1:][0].chip_temp
return 0
@right_board_chip_temp.setter
def right_board_chip_temp(self, val):
pass
@property @property
def nominal(self): # noqa - Skip PyCharm inspection def nominal(self): # noqa - Skip PyCharm inspection
if self.total_chips is None or self.ideal_chips is None:
return None
return self.ideal_chips == self.total_chips return self.ideal_chips == self.total_chips
@nominal.setter @nominal.setter
@@ -427,6 +275,8 @@ class MinerData:
@property @property
def percent_ideal_chips(self): # noqa - Skip PyCharm inspection def percent_ideal_chips(self): # noqa - Skip PyCharm inspection
if self.total_chips is None or self.ideal_chips is None:
return None
if self.total_chips == 0 or self.ideal_chips == 0: if self.total_chips == 0 or self.ideal_chips == 0:
return 0 return 0
return round((self.total_chips / self.ideal_chips) * 100) return round((self.total_chips / self.ideal_chips) * 100)
@@ -437,6 +287,8 @@ class MinerData:
@property @property
def percent_ideal_hashrate(self): # noqa - Skip PyCharm inspection def percent_ideal_hashrate(self): # noqa - Skip PyCharm inspection
if self.hashrate is None or self.nominal_hashrate is None:
return None
if self.hashrate == 0 or self.nominal_hashrate == 0: if self.hashrate == 0 or self.nominal_hashrate == 0:
return 0 return 0
return round((self.hashrate / self.nominal_hashrate) * 100) return round((self.hashrate / self.nominal_hashrate) * 100)
@@ -447,6 +299,8 @@ class MinerData:
@property @property
def percent_ideal_wattage(self): # noqa - Skip PyCharm inspection def percent_ideal_wattage(self): # noqa - Skip PyCharm inspection
if self.wattage_limit is None or self.wattage is None:
return None
if self.wattage_limit == 0 or self.wattage == 0: if self.wattage_limit == 0 or self.wattage == 0:
return 0 return 0
return round((self.wattage / self.wattage_limit) * 100) return round((self.wattage / self.wattage_limit) * 100)
@@ -460,11 +314,11 @@ class MinerData:
total_temp = 0 total_temp = 0
temp_count = 0 temp_count = 0
for hb in self.hashboards: for hb in self.hashboards:
if hb.temp and not hb.temp == -1: if hb.temp is not None:
total_temp += hb.temp total_temp += hb.temp
temp_count += 1 temp_count += 1
if not temp_count > 0: if not temp_count > 0:
return 0 return None
return round(total_temp / temp_count) return round(total_temp / temp_count)
@temperature_avg.setter @temperature_avg.setter
@@ -473,7 +327,9 @@ class MinerData:
@property @property
def efficiency(self): # noqa - Skip PyCharm inspection def efficiency(self): # noqa - Skip PyCharm inspection
if self.hashrate == 0 or self.wattage == -1: if self.hashrate is None or self.wattage is None:
return None
if self.hashrate == 0 or self.wattage == 0:
return 0 return 0
return round(self.wattage / self.hashrate) return round(self.wattage / self.hashrate)
@@ -482,13 +338,16 @@ class MinerData:
pass pass
def asdict(self) -> dict: def asdict(self) -> dict:
logging.debug(f"MinerData - (To Dict) - Dumping Dict data")
return asdict(self)
def as_dict(self) -> dict:
"""Get this dataclass as a dictionary. """Get this dataclass as a dictionary.
Returns: Returns:
A dictionary version of this class. A dictionary version of this class.
""" """
logging.debug(f"MinerData - (To Dict) - Dumping Dict data") return self.asdict()
return asdict(self)
def as_json(self) -> str: def as_json(self) -> str:
"""Get this dataclass as JSON. """Get this dataclass as JSON.
@@ -533,27 +392,45 @@ class MinerData:
tags = ["ip", "mac", "model", "hostname"] tags = ["ip", "mac", "model", "hostname"]
for attribute in self: for attribute in self:
if attribute in tags: if attribute in tags:
escaped_data = self[attribute].replace(" ", "\\ ") escaped_data = self.get(attribute, "Unknown").replace(" ", "\\ ")
tag_data.append(f"{attribute}={escaped_data}") tag_data.append(f"{attribute}={escaped_data}")
continue continue
if isinstance(self[attribute], str): elif str(attribute).startswith("_"):
continue
elif isinstance(self[attribute], str):
field_data.append(f'{attribute}="{self[attribute]}"') field_data.append(f'{attribute}="{self[attribute]}"')
continue continue
if isinstance(self[attribute], bool): elif isinstance(self[attribute], bool):
field_data.append(f"{attribute}={str(self[attribute]).lower()}") field_data.append(f"{attribute}={str(self[attribute]).lower()}")
continue continue
if isinstance(self[attribute], int): elif isinstance(self[attribute], int):
field_data.append(f"{attribute}={self[attribute]}") field_data.append(f"{attribute}={self[attribute]}")
continue continue
if isinstance(self[attribute], float): elif isinstance(self[attribute], float):
field_data.append(f"{attribute}={self[attribute]}") field_data.append(f"{attribute}={self[attribute]}")
continue continue
if attribute == "fault_light" and not self[attribute]: elif attribute == "errors":
field_data.append(f"{attribute}=false")
continue
if attribute == "errors":
for idx, item in enumerate(self[attribute]): for idx, item in enumerate(self[attribute]):
field_data.append(f'error_{idx+1}="{item.error_message}"') field_data.append(f'error_{idx+1}="{item.error_message}"')
elif attribute == "hashboards":
for idx, item in enumerate(self[attribute]):
field_data.append(
f"hashboard_{idx+1}_hashrate={item.get('hashrate', 0.0)}"
)
field_data.append(
f"hashboard_{idx+1}_temperature={item.get('temp', 0)}"
)
field_data.append(
f"hashboard_{idx+1}_chip_temperature={item.get('chip_temp', 0)}"
)
field_data.append(f"hashboard_{idx+1}_chips={item.get('chips', 0)}")
field_data.append(
f"hashboard_{idx+1}_expected_chips={item.get('expected_chips', 0)}"
)
elif attribute == "fans":
for idx, item in enumerate(self[attribute]):
if item.speed is not None:
field_data.append(f"fan_{idx+1}={item.speed}")
tags_str = ",".join(tag_data) tags_str = ",".join(tag_data)
field_str = ",".join(field_data) field_str = ",".join(field_data)

View File

@@ -16,8 +16,6 @@
from dataclasses import asdict, dataclass, field, fields from dataclasses import asdict, dataclass, field, fields
C_N_CODES = ["52", "53", "54", "55", "56"]
@dataclass @dataclass
class WhatsminerError: class WhatsminerError:
@@ -37,10 +35,8 @@ class WhatsminerError:
@property @property
def error_message(self): # noqa - Skip PyCharm inspection def error_message(self): # noqa - Skip PyCharm inspection
if len(str(self.error_code)) > 3 and str(self.error_code)[:2] in C_N_CODES: if len(str(self.error_code)) == 6 and not str(self.error_code)[:1] == "1":
# 55 error code base has chip numbers, so the format is err_type = int(str(self.error_code)[:2])
# 55 -> board num len 1 -> chip num len 3
err_type = 55
err_subtype = int(str(self.error_code)[2:3]) err_subtype = int(str(self.error_code)[2:3])
err_value = int(str(self.error_code)[3:]) err_value = int(str(self.error_code)[3:])
else: else:
@@ -88,7 +84,9 @@ class WhatsminerError:
ERROR_CODES = { ERROR_CODES = {
1: { # Fan error 1: { # Fan error
0: {0: "Fan unknown."}, 0: {
0: "Fan unknown.",
},
1: { # Fan speed error of 1000+ 1: { # Fan speed error of 1000+
0: "Intake fan speed error.", 0: "Intake fan speed error.",
1: "Exhaust fan speed error.", 1: "Exhaust fan speed error.",
@@ -101,7 +99,9 @@ ERROR_CODES = {
0: "Intake fan speed error. Fan speed deviates by more than 3000.", 0: "Intake fan speed error. Fan speed deviates by more than 3000.",
1: "Exhaust fan speed error. Fan speed deviates by more than 3000.", 1: "Exhaust fan speed error. Fan speed deviates by more than 3000.",
}, },
4: {0: "Fan speed too high."}, # High speed 4: {
0: "Fan speed too high.",
}, # High speed
}, },
2: { # Power error 2: { # Power error
0: { 0: {
@@ -126,6 +126,7 @@ ERROR_CODES = {
6: "Power remained unchanged for a long time.", 6: "Power remained unchanged for a long time.",
7: "Power set enable error.", 7: "Power set enable error.",
8: "Power input voltage is lower than 230V for high power mode.", 8: "Power input voltage is lower than 230V for high power mode.",
9: "Power input current is incorrect.",
}, },
3: { 3: {
3: "Power output high temperature protection error.", 3: "Power output high temperature protection error.",
@@ -159,6 +160,8 @@ ERROR_CODES = {
6: { 6: {
3: "Power communication warning.", 3: "Power communication warning.",
4: "Power communication error.", 4: "Power communication error.",
5: "Power unknown error.",
6: "Power unknown error.",
7: "Power watchdog protection.", 7: "Power watchdog protection.",
8: "Power output high current protection.", 8: "Power output high current protection.",
9: "Power input high current protection.", 9: "Power input high current protection.",
@@ -170,57 +173,134 @@ ERROR_CODES = {
3: "Power input too high warning.", 3: "Power input too high warning.",
4: "Power fan warning.", 4: "Power fan warning.",
5: "Power high temperature warning.", 5: "Power high temperature warning.",
6: "Power unknown error.",
7: "Power unknown error.",
8: "Power unknown error.",
9: "Power unknown error.",
},
8: {
0: "Power unknown error.",
1: "Power vendor status 1 bit 0 error.",
2: "Power vendor status 1 bit 1 error.",
3: "Power vendor status 1 bit 2 error.",
4: "Power vendor status 1 bit 3 error.",
5: "Power vendor status 1 bit 4 error.",
6: "Power vendor status 1 bit 5 error.",
7: "Power vendor status 1 bit 6 error.",
8: "Power vendor status 1 bit 7 error.",
9: "Power vendor status 2 bit 0 error.",
},
9: {
0: "Power vendor status 2 bit 1 error.",
1: "Power vendor status 2 bit 2 error.",
2: "Power vendor status 2 bit 3 error.",
3: "Power vendor status 2 bit 4 error.",
4: "Power vendor status 2 bit 5 error.",
5: "Power vendor status 2 bit 6 error.",
6: "Power vendor status 2 bit 7 error.",
}, },
}, },
3: { # temperature error 3: { # temperature error
0: { # sensor detection error 0: { # sensor detection error
"n": "Slot {n} temperature sensor detection error." "n": "Slot {n} temperature sensor detection error.",
}, },
2: { # temperature reading error 2: { # temperature reading error
"n": "Slot {n} temperature reading error.", "n": "Slot {n} temperature reading error.",
9: "Control board temperature sensor communication error.", 9: "Control board temperature sensor communication error.",
}, },
5: {"n": "Slot {n} temperature protecting."}, # temperature protection 5: {
6: {0: "Hashboard high temperature error."}, # high temp "n": "Slot {n} temperature protecting.",
}, # temperature protection
6: {
0: "Hashboard high temperature error.",
1: "Hashboard high temperature error.",
2: "Hashboard high temperature error.",
3: "Hashboard high temperature error.",
}, # high temp
7: {
0: "The environment temperature fluctuates too much.",
}, # env temp
8: { 8: {
0: "Humidity sensor not found.", 0: "Humidity sensor not found.",
1: "Humidity sensor read error.", 1: "Humidity sensor read error.",
2: "Humidity sensor read error.", 2: "Humidity sensor read error.",
3: "Humidity sensor protecting.", 3: "Humidity sensor protecting.",
}, }, # humidity
}, },
4: { # EEPROM error 4: { # EEPROM error
0: {0: "Eeprom unknown error."}, 0: {
1: {"n": "Slot {n} eeprom detection error."}, # EEPROM detection error 0: "Eeprom unknown error.",
2: {"n": "Slot {n} eeprom parsing error."}, # EEPROM parsing error },
3: {"n": "Slot {n} chip bin type error."}, # chip bin error 1: {
4: {"n": "Slot {n} eeprom chip number X error."}, # EEPROM chip number error "n": "Slot {n} eeprom detection error.",
5: {"n": "Slot {n} eeprom xfer error."}, # EEPROM xfer error }, # EEPROM detection error
2: {
"n": "Slot {n} eeprom parsing error.",
}, # EEPROM parsing error
3: {
"n": "Slot {n} chip bin type error.",
}, # chip bin error
4: {
"n": "Slot {n} eeprom chip number X error.",
}, # EEPROM chip number error
5: {
"n": "Slot {n} eeprom xfer error.",
}, # EEPROM xfer error
}, },
5: { # hashboard error 5: { # hashboard error
0: {0: "Board unknown error."}, 0: {
1: {"n": "Slot {n} miner type error."}, # board miner type error 0: "Board unknown error.",
2: {"n": "Slot {n} bin type error."}, # chip bin type error },
3: {"n": "Slot {n} not found."}, # board not found error 1: {
4: {"n": "Slot {n} error reading chip id."}, # reading chip id error "n": "Slot {n} miner type error.",
5: {"n": "Slot {n} has bad chips."}, # board has bad chips error }, # board miner type error
6: {"n": "Slot {n} loss of balance error."}, # loss of balance error 2: {
7: {"n": "Slot {n} xfer error chip."}, # xfer error "n": "Slot {n} bin type error.",
8: {"n": "Slot {n} reset error."}, # reset error }, # chip bin type error
9: {"n": "Slot {n} frequency too low."}, # freq error 3: {
"n": "Slot {n} not found.",
}, # board not found error
4: {
"n": "Slot {n} error reading chip id.",
}, # reading chip id error
5: {
"n": "Slot {n} has bad chips.",
}, # board has bad chips error
6: {
"n": "Slot {n} loss of balance error.",
}, # loss of balance error
7: {
"n": "Slot {n} xfer error chip.",
}, # xfer error
8: {
"n": "Slot {n} reset error.",
}, # reset error
9: {
"n": "Slot {n} frequency too low.",
}, # freq error
}, },
6: { # env temp error 6: { # env temp error
0: {0: "Environment temperature is too high."}, # normal env temp error 0: {
0: "Environment temperature is too high.",
}, # normal env temp error
1: { # high power env temp error 1: { # high power env temp error
0: "Environment temperature is too high for high performance mode." 0: "Environment temperature is too high for high performance mode.",
}, },
}, },
7: { # control board error 7: { # control board error
0: {0: "MAC address invalid", 1: "Control board no support chip."}, 0: {
0: "MAC address invalid",
1: "Control board no support chip.",
},
1: { 1: {
0: "Control board rebooted as an exception.", 0: "Control board rebooted as an exception.",
1: "Control board rebooted as exception and cpufreq reduced, please upgrade the firmware", 1: "Control board rebooted as exception and cpufreq reduced, please upgrade the firmware",
2: "Control board rebooted as an exception.", 2: "Control board rebooted as an exception.",
3: "The network is unstable, change time.",
4: "Unknown error.",
},
2: {
"n": "Control board slot {n} frame error.",
}, },
}, },
8: { # checksum error 8: { # checksum error
@@ -228,63 +308,152 @@ ERROR_CODES = {
0: "CGMiner checksum error.", 0: "CGMiner checksum error.",
1: "System monitor checksum error.", 1: "System monitor checksum error.",
2: "Remote daemon checksum error.", 2: "Remote daemon checksum error.",
} },
1: {0: "Air to liquid PCB serial # does not match."},
}, },
9: {0: {1: "Power rate error."}}, # power rate error 9: {
0: {0: "Unknown error.", 1: "Power rate error.", 2: "Unknown error."}
}, # power rate error
20: { # pool error 20: { # pool error
1: {0: "All pools are disabled."}, # all disabled error 0: {
2: {"n": "Pool {n} connection failed."}, # pool connection failed error 0: "No pool information configured.",
3: {0: "High rejection rate on pool."}, # rejection rate error },
1: {
0: "All pools are disabled.",
}, # all disabled error
2: {
"n": "Pool {n} connection failed.",
}, # pool connection failed error
3: {
0: "High rejection rate on pool.",
}, # rejection rate error
4: { # asicboost not supported error 4: { # asicboost not supported error
0: "The pool does not support asicboost mode." 0: "The pool does not support asicboost mode.",
}, },
}, },
21: {1: {"n": "Slot {n} factory test step failed."}}, 21: {
1: {
"n": "Slot {n} factory test step failed.",
}
},
23: { # hashrate error 23: { # hashrate error
1: {0: "Hashrate is too low."}, 1: {
2: {0: "Hashrate is too low."}, 0: "Hashrate is too low.",
3: {0: "Hashrate loss is too high."}, },
4: {0: "Hashrate loss is too high."}, 2: {
5: {0: "Hashrate loss."}, 0: "Hashrate is too low.",
},
3: {
0: "Hashrate loss is too high.",
},
4: {
0: "Hashrate loss is too high.",
},
5: {
0: "Hashrate loss.",
},
}, },
50: { # water velocity error/voltage error 50: { # water velocity error/voltage error
1: {"n": "Slot {n} chip voltage too low."}, 1: {
2: {"n": "Slot {n} chip voltage changed."}, "n": "Slot {n} chip voltage too low.",
3: {"n": "Slot {n} chip temperature difference is too large."}, },
4: {"n": "Slot {n} chip hottest temperature difference is too large."}, 2: {
7: {"n": "Slot {n} water velocity is abnormal."}, # abnormal water velocity "n": "Slot {n} chip voltage changed.",
8: {0: "Chip temp calibration failed, please restore factory settings."}, },
9: {"n": "Slot {n} chip temp calibration check no balance."}, 3: {
"n": "Slot {n} chip temperature difference is too large.",
},
4: {
"n": "Slot {n} chip hottest temperature difference is too large.",
},
5: {"n": "Slot {n} stopped hashing, chips temperature protecting."},
7: {
"n": "Slot {n} water velocity is abnormal.",
}, # abnormal water velocity
8: {
0: "Chip temp calibration failed, please restore factory settings.",
},
9: {
"n": "Slot {n} chip temp calibration check no balance.",
},
}, },
51: { # frequency error 51: { # frequency error
1: {"n": "Slot {n} frequency up timeout."}, # frequency up timeout 1: {
7: {"n": "Slot {n} frequency up timeout."}, # frequency up timeout "n": "Slot {n} frequency up timeout.",
}, # frequency up timeout
2: {"n": "Slot {n} too many CRC errors."},
3: {"n": "Slot {n} unstable."},
7: {
"n": "Slot {n} frequency up timeout.",
}, # frequency up timeout
},
52: {
"n": {
"c": "Slot {n} chip {c} error nonce.",
},
},
53: {
"n": {
"c": "Slot {n} chip {c} too few nonce.",
},
},
54: {
"n": {
"c": "Slot {n} chip {c} temp protected.",
},
},
55: {
"n": {
"c": "Slot {n} chip {c} has been reset.",
},
},
56: {
"n": {
"c": "Slot {n} chip {c} zero nonce.",
},
}, },
52: {"n": {"c": "Slot {n} chip {c} error nonce."}},
53: {"n": {"c": "Slot {n} chip {c} too few nonce."}},
54: {"n": {"c": "Slot {n} chip {c} temp protected."}},
55: {"n": {"c": "Slot {n} chip {c} has been reset."}},
56: {"n": {"c": "Slot {n} chip {c} does not return to the nonce."}},
80: { 80: {
0: {0: "The tool version is too low, please update."}, 0: {
1: {0: "Low freq."}, 0: "The tool version is too low, please update.",
2: {0: "Low hashrate."}, },
3: {5: "High env temp."}, 1: {
0: "Low freq.",
},
2: {
0: "Low hashrate.",
},
3: {
5: "High env temp.",
},
}, },
81: { 81: {
0: {0: "Chip data error."}, 0: {
0: "Chip data error.",
},
}, },
82: { 82: {
0: {0: "Power version error."}, 0: {
1: {0: "Miner type error."}, 0: "Power version error.",
2: {0: "Version info error."}, },
1: {
0: "Miner type error.",
},
2: {
0: "Version info error.",
},
}, },
83: { 83: {
0: {0: "Empty level error."}, 0: {
0: "Empty level error.",
},
}, },
84: { 84: {
0: {0: "Old firmware."}, 0: {
1: {0: "Software version error."}, 0: "Old firmware.",
},
1: {
0: "Software version error.",
},
}, },
85: { 85: {
"n": { "n": {
@@ -296,8 +465,12 @@ ERROR_CODES = {
}, },
}, },
86: { 86: {
0: {0: "Missing product serial #."}, 0: {
1: {0: "Missing product type."}, 0: "Missing product serial #.",
},
1: {
0: "Missing product type.",
},
2: { 2: {
0: "Missing miner serial #.", 0: "Missing miner serial #.",
1: "Wrong miner serial # length.", 1: "Wrong miner serial # length.",
@@ -314,12 +487,34 @@ ERROR_CODES = {
3: "Wrong power model rate.", 3: "Wrong power model rate.",
4: "Wrong power model format.", 4: "Wrong power model format.",
}, },
5: {0: "Wrong hash board struct."}, 5: {
6: {0: "Wrong miner cooling type."}, 0: "Wrong hash board struct.",
7: {0: "Missing PCB serial #."}, },
6: {
0: "Wrong miner cooling type.",
},
7: {
0: "Missing PCB serial #.",
},
},
87: {
0: {
0: "Miner power mismatch.",
},
},
90: {
0: {
0: "Process error, exited with signal: 3.",
},
1: {
0: "Process error, exited with signal: 3.",
},
},
99: {
9: {
9: "Miner unknown error.",
},
}, },
87: {0: {0: "Miner power mismatch."}},
99: {9: {9: "Miner unknown error."}},
1000: { 1000: {
0: { 0: {
0: "Security library error, please upgrade firmware", 0: "Security library error, please upgrade firmware",
@@ -328,7 +523,11 @@ ERROR_CODES = {
3: "/antiv/dig/pf_partial.dig illegal.", 3: "/antiv/dig/pf_partial.dig illegal.",
}, },
}, },
1001: {0: {0: "Security BTMiner removed, please upgrade firmware."}}, 1001: {
0: {
0: "Security BTMiner removed, please upgrade firmware.",
},
},
1100: { 1100: {
0: { 0: {
0: "Security illegal file, please upgrade firmware.", 0: "Security illegal file, please upgrade firmware.",

View File

@@ -19,21 +19,8 @@ from typing import List, Union
from pyasic.errors import APIError from pyasic.errors import APIError
from pyasic.miners import AnyMiner from pyasic.miners import AnyMiner
from pyasic.miners.backends import ( # noqa - Ignore access to _module from pyasic.miners.backends import AntminerModern, BOSMiner, BTMiner
AntminerModern, from pyasic.miners.types import S9, S17, T17, S17e, S17Plus, S17Pro, T17e, T17Plus
BOSMiner,
BTMiner,
)
from pyasic.miners.btc._types import ( # noqa - Ignore access to _module
S9,
S17,
T17,
S17e,
S17Plus,
S17Pro,
T17e,
T17Plus,
)
FAN_USAGE = 50 # 50 W per fan FAN_USAGE = 50 # 50 W per fan
@@ -162,10 +149,10 @@ class _MinerPhaseBalancer:
not self.miners[data_point.ip]["shutdown"] not self.miners[data_point.ip]["shutdown"]
): ):
# cant do anything with it so need to find a semi-accurate power limit # cant do anything with it so need to find a semi-accurate power limit
if not data_point.wattage_limit == -1: if not data_point.wattage_limit == None:
self.miners[data_point.ip]["max"] = int(data_point.wattage_limit) self.miners[data_point.ip]["max"] = int(data_point.wattage_limit)
self.miners[data_point.ip]["min"] = int(data_point.wattage_limit) self.miners[data_point.ip]["min"] = int(data_point.wattage_limit)
elif not data_point.wattage == -1: elif not data_point.wattage == None:
self.miners[data_point.ip]["max"] = int(data_point.wattage) self.miners[data_point.ip]["max"] = int(data_point.wattage)
self.miners[data_point.ip]["min"] = int(data_point.wattage) self.miners[data_point.ip]["min"] = int(data_point.wattage)

View File

@@ -16,31 +16,29 @@
import logging import logging
from pyasic.settings import PyasicSettings
def init_logger(): def init_logger():
if PyasicSettings().logfile: # if PyasicSettings().logfile:
logging.basicConfig( # logging.basicConfig(
filename="logfile.txt", # filename="logfile.txt",
filemode="a", # filemode="a",
format="%(pathname)s:%(lineno)d in %(funcName)s\n[%(levelname)s][%(asctime)s](%(name)s) - %(message)s", # format="%(pathname)s:%(lineno)d in %(funcName)s\n[%(levelname)s][%(asctime)s](%(name)s) - %(message)s",
datefmt="%x %X", # datefmt="%x %X",
) # )
else: # else:
logging.basicConfig( logging.basicConfig(
format="%(pathname)s:%(lineno)d in %(funcName)s\n[%(levelname)s][%(asctime)s](%(name)s) - %(message)s", format="%(pathname)s:%(lineno)d in %(funcName)s\n[%(levelname)s][%(asctime)s](%(name)s) - %(message)s",
datefmt="%x %X", datefmt="%x %X",
) )
_logger = logging.getLogger() _logger = logging.getLogger()
if PyasicSettings().debug: # if PyasicSettings().debug:
_logger.setLevel(logging.DEBUG) # _logger.setLevel(logging.DEBUG)
logging.getLogger("asyncssh").setLevel(logging.DEBUG) # logging.getLogger("asyncssh").setLevel(logging.DEBUG)
else: # else:
_logger.setLevel(logging.WARNING) _logger.setLevel(logging.WARNING)
logging.getLogger("asyncssh").setLevel(logging.WARNING) logging.getLogger("asyncssh").setLevel(logging.WARNING)
return _logger return _logger

View File

@@ -18,9 +18,9 @@ import ipaddress
from typing import Union from typing import Union
from pyasic.miners.base import AnyMiner, BaseMiner from pyasic.miners.base import AnyMiner, BaseMiner
from pyasic.miners.miner_factory import MinerFactory from pyasic.miners.miner_factory import miner_factory
# abstracted version of get miner that is easier to access # abstracted version of get miner that is easier to access
async def get_miner(ip: Union[ipaddress.ip_address, str]) -> AnyMiner: async def get_miner(ip: Union[ipaddress.ip_address, str]) -> AnyMiner:
return await MinerFactory().get_miner(ip) return await miner_factory.get_miner(ip)

View File

@@ -18,4 +18,6 @@ from .bmminer import *
from .bosminer import * from .bosminer import *
from .cgminer import * from .cgminer import *
from .hiveon import * from .hiveon import *
from .luxos import *
from .vnish import * from .vnish import *
from .epic import *

View File

@@ -0,0 +1,34 @@
# ------------------------------------------------------------------------------
# Copyright 2022 Upstream Data Inc -
# -
# Licensed under the Apache License, Version 2.0 (the "License"); -
# you may not use this file except in compliance with the License. -
# You may obtain a copy of the License at -
# -
# http://www.apache.org/licenses/LICENSE-2.0 -
# -
# Unless required by applicable law or agreed to in writing, software -
# distributed under the License is distributed on an "AS IS" BASIS, -
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerOld
from pyasic.miners.types import S17, S17e, S17Plus, S17Pro
class BMMinerS17(AntminerOld, S17):
pass
class BMMinerS17Plus(AntminerOld, S17Plus):
pass
class BMMinerS17Pro(AntminerOld, S17Pro):
pass
class BMMinerS17e(AntminerOld, S17e):
pass

View File

@@ -15,9 +15,16 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerOld from pyasic.miners.backends import AntminerOld
from pyasic.miners.ltc._types import L3Plus # noqa - Ignore access to _module from pyasic.miners.types import T17, T17e, T17Plus
class BMMinerL3Plus(AntminerOld, L3Plus): class BMMinerT17(AntminerOld, T17):
def __init__(self, ip: str, api_ver: str = "0.0.0"): pass
super().__init__(ip, api_ver)
class BMMinerT17Plus(AntminerOld, T17Plus):
pass
class BMMinerT17e(AntminerOld, T17e):
pass

View File

@@ -0,0 +1,18 @@
# ------------------------------------------------------------------------------
# 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 .S17 import BMMinerS17, BMMinerS17e, BMMinerS17Plus, BMMinerS17Pro
from .T17 import BMMinerT17, BMMinerT17e, BMMinerT17Plus

View File

@@ -15,9 +15,52 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerModern from pyasic.miners.backends import AntminerModern
from pyasic.miners.btc._types import S19j, S19jNoPIC # noqa - Ignore access to _module from pyasic.miners.types import (
S19,
S19L,
S19XP,
S19a,
S19aPro,
S19i,
S19j,
S19jNoPIC,
S19jPro,
S19Plus,
S19Pro,
S19ProPlus,
)
# noqa - Ignore access to _module
class BMMinerS19(AntminerModern, S19):
pass
class BMMinerS19Plus(AntminerModern, S19Plus):
pass
class BMMinerS19i(AntminerModern, S19i):
pass
class BMMinerS19Pro(AntminerModern, S19Pro):
pass
class BMMinerS19ProPlus(AntminerModern, S19ProPlus):
pass
class BMMinerS19XP(AntminerModern, S19XP):
pass
class BMMinerS19a(AntminerModern, S19a):
pass
class BMMinerS19aPro(AntminerModern, S19aPro):
pass
class BMMinerS19j(AntminerModern, S19j): class BMMinerS19j(AntminerModern, S19j):
@@ -26,3 +69,11 @@ class BMMinerS19j(AntminerModern, S19j):
class BMMinerS19jNoPIC(AntminerModern, S19jNoPIC): class BMMinerS19jNoPIC(AntminerModern, S19jNoPIC):
pass pass
class BMMinerS19jPro(AntminerModern, S19jPro):
pass
class BMMinerS19L(AntminerModern, S19L):
pass

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerModern from pyasic.miners.backends import AntminerModern
from pyasic.miners.btc._types import T19 # noqa - Ignore access to _module from pyasic.miners.types import T19
# noqa - Ignore access to _module # noqa - Ignore access to _module

View File

@@ -14,13 +14,18 @@
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from .S19 import S19 from .S19 import (
from .S19_Pro import S19Pro BMMinerS19,
from .S19_Pro_Plus import S19ProPlus BMMinerS19a,
from .S19_XP import S19XP BMMinerS19aPro,
from .S19a import S19a BMMinerS19i,
from .S19a_Pro import S19aPro BMMinerS19j,
from .S19j import S19j, S19jNoPIC BMMinerS19jNoPIC,
from .S19j_Pro import S19jPro BMMinerS19jPro,
from .S19L import S19L BMMinerS19L,
from .T19 import T19 BMMinerS19Plus,
BMMinerS19Pro,
BMMinerS19ProPlus,
BMMinerS19XP,
)
from .T19 import BMMinerT19

View File

@@ -15,10 +15,10 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerModern from pyasic.miners.backends import AntminerModern
from pyasic.miners.hns._types import HS3 # noqa - Ignore access to _module from pyasic.miners.types import HS3
class CGMinerHS3(AntminerModern, HS3): class BMMinerHS3(AntminerModern, HS3):
def __init__(self, ip: str, api_ver: str = "0.0.0"): def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver) super().__init__(ip, api_ver)
self.supports_shutdown = False self.supports_shutdown = False

View File

@@ -14,8 +14,9 @@
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import CGMinerAvalon # noqa - Ignore access to _module from pyasic.miners.backends import AntminerOld
from pyasic.miners.types import L3Plus
class CGMinerA10X(CGMinerAvalon): class BMMinerL3Plus(AntminerOld, L3Plus):
pass pass

View File

@@ -13,6 +13,5 @@
# 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 .X9 import * from .HS3 import BMMinerHS3
from .X17 import * from .L3 import BMMinerL3Plus
from .X19 import *

View File

@@ -14,7 +14,7 @@
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerModern from pyasic.miners.backends import AntminerModern
from pyasic.miners.ltc._types import L7 # noqa - Ignore access to _module from pyasic.miners.types import L7
class BMMinerL7(AntminerModern, L7): class BMMinerL7(AntminerModern, L7):

View File

@@ -15,10 +15,10 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerModern from pyasic.miners.backends import AntminerModern
from pyasic.miners.etc._types import E9Pro # noqa - Ignore access to _module from pyasic.miners.types import E9Pro
class CGMinerE9Pro(AntminerModern, E9Pro): class BMMinerE9Pro(AntminerModern, E9Pro):
def __init__(self, ip: str, api_ver: str = "0.0.0"): def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver) super().__init__(ip, api_ver)
self.supports_shutdown = False self.supports_shutdown = False

View File

@@ -15,8 +15,16 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import BMMiner from pyasic.miners.backends import BMMiner
from pyasic.miners.btc._types import S9i # noqa - Ignore access to _module from pyasic.miners.types import S9, S9i, S9j
class BMMinerS9(BMMiner, S9):
pass
class BMMinerS9i(BMMiner, S9i): class BMMinerS9i(BMMiner, S9i):
pass pass
class BMMinerS9j(BMMiner, S9j):
pass

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import BMMiner from pyasic.miners.backends import BMMiner
from pyasic.miners.btc._types import T9 # noqa - Ignore access to _module from pyasic.miners.types import T9
class BMMinerT9(BMMiner, T9): class BMMinerT9(BMMiner, T9):

View File

@@ -14,7 +14,6 @@
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from .S9 import BMMinerS9 from .E9 import BMMinerE9Pro
from .S9i import BMMinerS9i from .S9 import BMMinerS9, BMMinerS9i, BMMinerS9j
from .S9j import BMMinerS9j
from .T9 import BMMinerT9 from .T9 import BMMinerT9

View File

@@ -13,6 +13,8 @@
# 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 .X3 import *
from .X7 import *
from .X9 import * from .X9 import *
from .X17 import * from .X17 import *
from .X19 import * from .X19 import *

View File

@@ -15,8 +15,20 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import BOSMiner from pyasic.miners.backends import BOSMiner
from pyasic.miners.btc._types import S17Plus # noqa - Ignore access to _module from pyasic.miners.types import S17, S17e, S17Plus, S17Pro
class BOSMinerS17(BOSMiner, S17):
pass
class BOSMinerS17Plus(BOSMiner, S17Plus): class BOSMinerS17Plus(BOSMiner, S17Plus):
pass pass
class BOSMinerS17Pro(BOSMiner, S17Pro):
pass
class BOSMinerS17e(BOSMiner, S17e):
pass

View File

@@ -15,8 +15,16 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import BOSMiner from pyasic.miners.backends import BOSMiner
from pyasic.miners.btc._types import T17Plus # noqa - Ignore access to _module from pyasic.miners.types import T17, T17e, T17Plus
class BOSMinerT17(BOSMiner, T17):
pass
class BOSMinerT17Plus(BOSMiner, T17Plus): class BOSMinerT17Plus(BOSMiner, T17Plus):
pass pass
class BOSMinerT17e(BOSMiner, T17e):
pass

View File

@@ -0,0 +1,18 @@
# ------------------------------------------------------------------------------
# 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 .S17 import BOSMinerS17, BOSMinerS17e, BOSMinerS17Plus, BOSMinerS17Pro
from .T17 import BOSMinerT17, BOSMinerT17e, BOSMinerT17Plus

View File

@@ -15,7 +15,15 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import BOSMiner from pyasic.miners.backends import BOSMiner
from pyasic.miners.btc._types import S19j, S19jNoPIC # noqa - Ignore access to _module from pyasic.miners.types import S19, S19j, S19jNoPIC, S19jPro, S19Pro
class BOSMinerS19(BOSMiner, S19):
pass
class BOSMinerS19Pro(BOSMiner, S19Pro):
pass
class BOSMinerS19j(BOSMiner, S19j): class BOSMinerS19j(BOSMiner, S19j):
@@ -24,3 +32,7 @@ class BOSMinerS19j(BOSMiner, S19j):
class BOSMinerS19jNoPIC(BOSMiner, S19jNoPIC): class BOSMinerS19jNoPIC(BOSMiner, S19jNoPIC):
pass pass
class BOSMinerS19jPro(BOSMiner, S19jPro):
pass

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import BOSMiner from pyasic.miners.backends import BOSMiner
from pyasic.miners.btc._types import T19 # noqa - Ignore access to _module from pyasic.miners.types import T19
class BOSMinerT19(BOSMiner, T19): class BOSMinerT19(BOSMiner, T19):

View File

@@ -0,0 +1,24 @@
# ------------------------------------------------------------------------------
# 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 .S19 import (
BOSMinerS19,
BOSMinerS19j,
BOSMinerS19jNoPIC,
BOSMinerS19jPro,
BOSMinerS19Pro,
)
from .T19 import BOSMinerT19

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import BOSMiner from pyasic.miners.backends import BOSMiner
from pyasic.miners.btc._types import S9 # noqa - Ignore access to _module from pyasic.miners.types import S9
class BOSMinerS9(BOSMiner, S9): class BOSMinerS9(BOSMiner, S9):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerOld from pyasic.miners.backends import AntminerOld
from pyasic.miners.zec._types import Z15 # noqa - Ignore access to _module from pyasic.miners.types import Z15
class CGMinerZ15(AntminerOld, Z15): class CGMinerZ15(AntminerOld, Z15):

View File

@@ -13,9 +13,8 @@
# 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.miners.backends import AntminerOld from pyasic.miners.backends import AntminerOld
from pyasic.miners.dsh._types import D3 # noqa - Ignore access to _module from pyasic.miners.types import D3
class CGMinerD3(AntminerOld, D3): class CGMinerD3(AntminerOld, D3):

View File

@@ -13,4 +13,5 @@
# 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 .D3 import CGMinerD3 from .D3 import CGMinerD3

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerOld from pyasic.miners.backends import AntminerOld
from pyasic.miners.dcr._types import DR5 # noqa - Ignore access to _module from pyasic.miners.types import DR5
class CGMinerDR5(AntminerOld, DR5): class CGMinerDR5(AntminerOld, DR5):

View File

@@ -13,4 +13,7 @@
# 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 .X3 import *
from .X5 import *
from .X15 import * from .X15 import *

View File

@@ -0,0 +1,40 @@
# ------------------------------------------------------------------------------
# Copyright 2022 Upstream Data Inc -
# -
# Licensed under the Apache License, Version 2.0 (the "License"); -
# you may not use this file except in compliance with the License. -
# You may obtain a copy of the License at -
# -
# http://www.apache.org/licenses/LICENSE-2.0 -
# -
# Unless required by applicable law or agreed to in writing, software -
# distributed under the License is distributed on an "AS IS" BASIS, -
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners.backends import ePIC
from pyasic.miners.types import (
S19,
S19Pro,
S19j,
S19jPro,
S19XP,
)
class ePICS19(ePIC, S19):
pass
class ePICS19Pro(ePIC, S19Pro):
pass
class ePICS19j(ePIC, S19j):
pass
class ePICS19jPro(ePIC, S19jPro):
pass
class ePICS19XP(ePIC, S19XP):
pass

View File

@@ -0,0 +1,23 @@
# ------------------------------------------------------------------------------
# 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 .S19 import (
ePICS19,
ePICS19Pro,
ePICS19j,
ePICS19jPro,
ePICS19XP,
)

View File

@@ -20,8 +20,8 @@ import asyncssh
from pyasic.data import HashBoard from pyasic.data import HashBoard
from pyasic.errors import APIError from pyasic.errors import APIError
from pyasic.miners.backends import Hiveon # noqa - Ignore access to _module from pyasic.miners.backends import Hiveon
from pyasic.miners.btc._types import T9 # noqa - Ignore access to _module from pyasic.miners.types import T9
class HiveonT9(Hiveon, T9): class HiveonT9(Hiveon, T9):
@@ -58,7 +58,7 @@ class HiveonT9(Hiveon, T9):
hashrate = 0 hashrate = 0
chips = 0 chips = 0
for chipset in board_map[board]: for chipset in board_map[board]:
if hashboard.chip_temp == -1: if hashboard.chip_temp == None:
try: try:
hashboard.board_temp = api_stats["STATS"][1][f"temp{chipset}"] hashboard.board_temp = api_stats["STATS"][1][f"temp{chipset}"]
hashboard.chip_temp = api_stats["STATS"][1][f"temp2_{chipset}"] hashboard.chip_temp = api_stats["STATS"][1][f"temp2_{chipset}"]

View File

@@ -14,8 +14,9 @@
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import CGMinerAvalon # noqa - Ignore access to _module from pyasic.miners.backends import LUXMiner
from pyasic.miners.types import S9
class CGMinerA7X(CGMinerAvalon): class LUXMinerS9(LUXMiner, S9):
pass pass

View File

@@ -14,4 +14,4 @@
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from .T3X import * from .S9 import LUXMinerS9

View File

@@ -13,4 +13,5 @@
# 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 .X9 import * from .X9 import *

View File

@@ -13,11 +13,13 @@
# 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.miners.backends import VNish
from pyasic.miners.btc._types import S17Pro # noqa - Ignore access to _module from pyasic.miners.types import S17Plus, S17Pro
from .X17 import BMMinerX17
class BMMinerS17Pro(BMMinerX17, S17Pro): class VNishS17Plus(VNish, S17Plus):
pass
class VNishS17Pro(VNish, S17Pro):
pass pass

View File

@@ -13,5 +13,4 @@
# 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 .S17 import VNishS17Plus, VNishS17Pro
from .T3H_Plus import InnosiliconT3HPlus

View File

@@ -14,8 +14,45 @@
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import VNish # noqa - Ignore access to _module from pyasic.miners.backends import VNish
from pyasic.miners.btc._types import S19jPro # noqa - Ignore access to _module from pyasic.miners.types import (
S19,
S19XP,
S19a,
S19aPro,
S19j,
S19jPro,
S19NoPIC,
S19Pro,
)
class VNishS19(VNish, S19):
pass
class VNishS19NoPIC(VNish, S19NoPIC):
pass
class VNishS19Pro(VNish, S19Pro):
pass
class VNishS19XP(VNish, S19XP):
pass
class VNishS19a(VNish, S19a):
pass
class VNishS19aPro(VNish, S19aPro):
pass
class VNishS19j(VNish, S19j):
pass
class VNishS19jPro(VNish, S19jPro): class VNishS19jPro(VNish, S19jPro):

View File

@@ -14,8 +14,9 @@
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import CGMinerAvalon # noqa - Ignore access to _module from pyasic.miners.backends import VNish
from pyasic.miners.types import T19
class CGMinerA8X(CGMinerAvalon): class VNishT19(VNish, T19):
pass pass

View File

@@ -14,10 +14,14 @@
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from .S17 import S17 from .S19 import (
from .S17_Plus import S17Plus VNishS19,
from .S17_Pro import S17Pro VNishS19a,
from .S17e import S17e VNishS19aPro,
from .T17 import T17 VNishS19j,
from .T17_Plus import T17Plus VNishS19jPro,
from .T17e import T17e VNishS19NoPIC,
VNishS19Pro,
VNishS19XP,
)
from .T19 import VNishT19

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import VNish from pyasic.miners.backends import VNish
from pyasic.miners.ltc._types import L3Plus # noqa - Ignore access to _module from pyasic.miners.types import L3Plus
class VnishL3Plus(VNish, L3Plus): class VnishL3Plus(VNish, L3Plus):

View File

@@ -0,0 +1,17 @@
# ------------------------------------------------------------------------------
# Copyright 2022 Upstream Data Inc -
# -
# Licensed under the Apache License, Version 2.0 (the "License"); -
# you may not use this file except in compliance with the License. -
# You may obtain a copy of the License at -
# -
# http://www.apache.org/licenses/LICENSE-2.0 -
# -
# Unless required by applicable law or agreed to in writing, software -
# distributed under the License is distributed on an "AS IS" BASIS, -
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
from .L3 import VnishL3Plus

View File

@@ -14,6 +14,6 @@
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from .X9 import * from .X3 import *
from .X17 import * from .X17 import *
from .X19 import * from .X19 import *

View File

@@ -14,10 +14,9 @@
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.btc._types import Avalon1026 # noqa - Ignore access to _module from pyasic.miners.backends import CGMinerAvalon
from pyasic.miners.types import Avalon1026
from .A10X import CGMinerA10X
class CGMinerAvalon1026(CGMinerA10X, Avalon1026): class CGMinerAvalon1026(CGMinerAvalon, Avalon1026):
pass pass

View File

@@ -14,10 +14,9 @@
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.btc._types import Avalon1047 # noqa - Ignore access to _module from pyasic.miners.backends import CGMinerAvalon
from pyasic.miners.types import Avalon1047
from .A10X import CGMinerA10X
class CGMinerAvalon1047(CGMinerA10X, Avalon1047): class CGMinerAvalon1047(CGMinerAvalon, Avalon1047):
pass pass

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